wszjw2 发表于 2025-3-7 13:26:33

关于独立按键的单击、双击、长按开关机

#include <STC8.H>
#include <intrins.h>

// 硬件定义
#define KEY_PIN   P32      // 按键引脚P3.2
#define POWER_PIN   P55      // 电源控制引脚
sbit LED = P5^5;               // 状态指示灯

// 时间阈值定义(基于主循环周期10ms)
#define DEBOUNCE_TIME      3   // 30ms消抖
#define LONG_PRESS_TIME    200// 200*10ms=2秒
#define DOUBLE_CLICK_TIME30   // 30*10ms=300ms

// 全局状态变量
bit power_flag = 0;            // 电源状态 0:关机 1:开机
unsigned char key_state = 0;    // 按键状态机
unsigned int press_counter = 0; // 按下计时
unsigned int release_counter = 0;// 释放计时
bit click_count = 0;         // 单击计数

// 延时函数(24MHz粗略延时)
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i=ms; i>0; i--)
      for(j=6000; j>0; j--); // 粗略调整延时
}

// 系统进入低功耗模式
void enter_low_power() {
    POWER_PIN = 0;            // 关闭外设电源
    P3M0 &= ~0x04; P3M1 |= 0x04; // P3.2高阻输入
    PCON |= 0x02;             // 进入掉电模式
    _nop_();
    _nop_();
}

// 外部中断0初始化(下降沿触发)
void INT0_Init() {
    INT0 = 1;                // 使能INT0
    IT0 = 1;               // 下降沿触发
    EX0 = 1;               // 允许中断
    EA = 1;                  // 总中断使能
}

// INT0中断服务函数(唤醒+长按检测)
void exint0() interrupt 0 {
    unsigned int hold_time = 0;
   
    while(KEY_PIN == 0) {    // 保持循环直到按键释放
      delay_ms(10);
      if(++hold_time > (LONG_PRESS_TIME*10)) { // 2秒长按
            power_flag = 1;// 开机
            POWER_PIN = 1;   // 开启外设电源
            P3M0 = 0x00;   // P3.2准双向模式
            P3M1 = 0x00;
            return;
      }
    }
}

// 按键扫描函数(状态机实现)
void key_scan() {
    static bit last_state = 1;
    static unsigned int debounce_counter = 0;
   
    // 状态机处理
    switch(key_state) {
      case 0: // 初始状态
            if(!KEY_PIN && last_state) { // 检测到下降沿
                debounce_counter = 0;
                key_state = 1;
            }
            break;
            
      case 1: // 消抖检测
            if(++debounce_counter > DEBOUNCE_TIME) {
                if(!KEY_PIN) { // 确认有效按下
                  key_state = 2;
                  press_counter = 0;
                } else {
                  key_state = 0;
                }
            }
            break;
            
      case 2: // 按下状态
            press_counter++;
            if(KEY_PIN) { // 检测释放
                key_state = 3;
                release_counter = 0;
            }
            else if(press_counter > LONG_PRESS_TIME) { // 长按处理
                if(power_flag) { // 开机状态下长按关机
                  power_flag = 0;
                  enter_low_power();
                }
                key_state = 0;
            }
            break;
            
      case 3: // 释放状态
            release_counter++;
            if(release_counter > DOUBLE_CLICK_TIME) { // 单击确认
                click_count = 1;
                key_state = 0;
            }
            else if(!KEY_PIN) { // 第二次按下
                click_count++;
                key_state = 4;
            }
            break;
            
      case 4: // 双击确认
            if(++debounce_counter > DEBOUNCE_TIME) {
                if(KEY_PIN) { // 释放确认
                  click_count = (click_count >= 2) ? 2 : 0;
                  key_state = 0;
                }
            }
            break;
    }
   
    last_state = KEY_PIN; // 更新状态
}

// 主函数
void main() {
    // 初始化配置
    P_SW2 |= 0x80;      // 开启扩展寄存器访问
    INT0_Init();         // 外部中断初始化
    POWER_PIN = 0;       // 默认关闭外设
    enter_low_power();   // 初始进入低功耗
   
    while(1) {
      if(power_flag) {
            key_scan();// 仅在开机时扫描按键
            
            // 事件处理
            if(click_count == 1) {
                // 单击事件处理
                LED = ~LED;
                click_count = 0;
            }
            else if(click_count == 2) {
                // 双击事件处理
                // 添加双击功能代码
                click_count = 0;
            }
            
            // 其他应用代码...
      }
      else {
            PCON |= 0x02; // 确保进入掉电模式
            _nop_();
      }
    }
}

wszjw2 发表于 2025-3-7 13:27:17

我使用的是开天斧,只能识别单击,识别不了双击是为啥

国芯人工智能 发表于 2025-3-7 13:28:00

在嵌入式系统中,独立按键的单击、双击和长按功能实现是常见的需求。以下代码片段展示了基于51单片机的按键状态识别逻辑,适用于开关机等控制场景。

1. **硬件定义**:按键引脚定义在`P3.2`,电源控制引脚在`P5.5`,状态指示灯通过`P5.5`控制。
2. **时间阈值**:消抖时间为30ms(`DEBOUNCE_TIME=3`),长按时间为2秒(`LONG_PRESS_TIME=200`)。
3. **逻辑实现**:通过主循环周期(10ms)检测按键状态,消除抖动后,根据按键持续时间判断单击、双击或长按。长按触发开关机,单击或双击执行相应功能。
4. **注意事项**:确保按键消抖处理充分,避免误触发;长按时间可根据实际需求调整。

此实现方案简洁高效,适用于资源有限的嵌入式系统。

[本文内容由国芯人工智能辅助生成,仅供参考]

wszjw2 发表于 2025-3-7 13:44:34

还有里面的长按开机可以实现吗,有没有大佬指点一下

乘风飞扬 发表于 2025-3-7 19:12:18

布丁橘长教学视频第19期有介绍:



视频教程-32位8051-屠龙刀-第0-100期合集-布丁橘长
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=463
(出处: 国芯技术交流网站)

wszjw2 发表于 2025-3-8 11:18:51

wnagming 发表于 2025-3-7 20:42
如果你的按键只是接在IO口上,那么长按开机就是假的,比如有屏幕时,没有长按,屏幕不亮,长按后,屏幕有 ...

是的,其实就是相当于长按后进入低功耗模式,然后在低功耗模式下只有长按才能唤醒,单击双击无效

wszjw2 发表于 2025-3-8 11:19:08

乘风飞扬 发表于 2025-3-7 19:12
布丁橘长教学视频第19期有介绍:




我看看,谢谢{:4_168:}

lgnstar 发表于 2025-3-10 08:11:45

{:qiang:}

Ayb_ice 发表于 2025-3-10 08:46:08

中断里还死等

wangyifan 发表于 2025-3-11 10:47:18

bit click_count = 0;         // 单击计数
这个是不是定义错了。
页: [1] 2
查看完整版本: 关于独立按键的单击、双击、长按开关机