找回密码
 立即注册
查看: 348|回复: 17

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

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:33
  • 最近打卡:2025-04-28 10:23:12

11

主题

93

回帖

469

积分

中级会员

积分
469
发表于 2025-3-7 13:26:33 | 显示全部楼层 |阅读模式
  1. #include <STC8.H>
  2. #include <intrins.h>
  3. // 硬件定义
  4. #define KEY_PIN     P32        // 按键引脚P3.2
  5. #define POWER_PIN   P55        // 电源控制引脚
  6. sbit LED = P5^5;               // 状态指示灯
  7. // 时间阈值定义(基于主循环周期10ms)
  8. #define DEBOUNCE_TIME      3   // 30ms消抖
  9. #define LONG_PRESS_TIME    200  // 200*10ms=2秒
  10. #define DOUBLE_CLICK_TIME  30   // 30*10ms=300ms
  11. // 全局状态变量
  12. bit power_flag = 0;            // 电源状态 0:关机 1:开机
  13. unsigned char key_state = 0;    // 按键状态机
  14. unsigned int press_counter = 0; // 按下计时
  15. unsigned int release_counter = 0;// 释放计时
  16. bit click_count = 0;           // 单击计数
  17. // 延时函数(24MHz粗略延时)
  18. void delay_ms(unsigned int ms) {
  19.     unsigned int i, j;
  20.     for(i=ms; i>0; i--)
  21.         for(j=6000; j>0; j--); // 粗略调整延时
  22. }
  23. // 系统进入低功耗模式
  24. void enter_low_power() {
  25.     POWER_PIN = 0;            // 关闭外设电源
  26.     P3M0 &= ~0x04; P3M1 |= 0x04; // P3.2高阻输入
  27.     PCON |= 0x02;             // 进入掉电模式
  28.     _nop_();
  29.     _nop_();
  30. }
  31. // 外部中断0初始化(下降沿触发)
  32. void INT0_Init() {
  33.     INT0 = 1;                // 使能INT0
  34.     IT0 = 1;                 // 下降沿触发
  35.     EX0 = 1;                 // 允许中断
  36.     EA = 1;                  // 总中断使能
  37. }
  38. // INT0中断服务函数(唤醒+长按检测)
  39. void exint0() interrupt 0 {
  40.     unsigned int hold_time = 0;
  41.    
  42.     while(KEY_PIN == 0) {    // 保持循环直到按键释放
  43.         delay_ms(10);
  44.         if(++hold_time > (LONG_PRESS_TIME*10)) { // 2秒长按
  45.             power_flag = 1;  // 开机
  46.             POWER_PIN = 1;   // 开启外设电源
  47.             P3M0 = 0x00;     // P3.2准双向模式
  48.             P3M1 = 0x00;
  49.             return;
  50.         }
  51.     }
  52. }
  53. // 按键扫描函数(状态机实现)
  54. void key_scan() {
  55.     static bit last_state = 1;
  56.     static unsigned int debounce_counter = 0;
  57.    
  58.     // 状态机处理
  59.     switch(key_state) {
  60.         case 0: // 初始状态
  61.             if(!KEY_PIN && last_state) { // 检测到下降沿
  62.                 debounce_counter = 0;
  63.                 key_state = 1;
  64.             }
  65.             break;
  66.             
  67.         case 1: // 消抖检测
  68.             if(++debounce_counter > DEBOUNCE_TIME) {
  69.                 if(!KEY_PIN) { // 确认有效按下
  70.                     key_state = 2;
  71.                     press_counter = 0;
  72.                 } else {
  73.                     key_state = 0;
  74.                 }
  75.             }
  76.             break;
  77.             
  78.         case 2: // 按下状态
  79.             press_counter++;
  80.             if(KEY_PIN) { // 检测释放
  81.                 key_state = 3;
  82.                 release_counter = 0;
  83.             }
  84.             else if(press_counter > LONG_PRESS_TIME) { // 长按处理
  85.                 if(power_flag) { // 开机状态下长按关机
  86.                     power_flag = 0;
  87.                     enter_low_power();
  88.                 }
  89.                 key_state = 0;
  90.             }
  91.             break;
  92.             
  93.         case 3: // 释放状态
  94.             release_counter++;
  95.             if(release_counter > DOUBLE_CLICK_TIME) { // 单击确认
  96.                 click_count = 1;
  97.                 key_state = 0;
  98.             }
  99.             else if(!KEY_PIN) { // 第二次按下
  100.                 click_count++;
  101.                 key_state = 4;
  102.             }
  103.             break;
  104.             
  105.         case 4: // 双击确认
  106.             if(++debounce_counter > DEBOUNCE_TIME) {
  107.                 if(KEY_PIN) { // 释放确认
  108.                     click_count = (click_count >= 2) ? 2 : 0;
  109.                     key_state = 0;
  110.                 }
  111.             }
  112.             break;
  113.     }
  114.    
  115.     last_state = KEY_PIN; // 更新状态
  116. }
  117. // 主函数
  118. void main() {
  119.     // 初始化配置
  120.     P_SW2 |= 0x80;      // 开启扩展寄存器访问
  121.     INT0_Init();         // 外部中断初始化
  122.     POWER_PIN = 0;       // 默认关闭外设
  123.     enter_low_power();   // 初始进入低功耗
  124.    
  125.     while(1) {
  126.         if(power_flag) {
  127.             key_scan();  // 仅在开机时扫描按键
  128.             
  129.             // 事件处理
  130.             if(click_count == 1) {
  131.                 // 单击事件处理
  132.                 LED = ~LED;
  133.                 click_count = 0;
  134.             }
  135.             else if(click_count == 2) {
  136.                 // 双击事件处理
  137.                 // 添加双击功能代码
  138.                 click_count = 0;
  139.             }
  140.             
  141.             // 其他应用代码...
  142.         }
  143.         else {
  144.             PCON |= 0x02; // 确保进入掉电模式
  145.             _nop_();
  146.         }
  147.     }
  148. }
复制代码

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:33
  • 最近打卡:2025-04-28 10:23:12

11

主题

93

回帖

469

积分

中级会员

积分
469
发表于 2025-3-7 13:27:17 | 显示全部楼层
我使用的是开天斧,只能识别单击,识别不了双击是为啥
回复 支持 反对

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 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. **注意事项**:确保按键消抖处理充分,避免误触发;长按时间可根据实际需求调整。

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

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:33
  • 最近打卡:2025-04-28 10:23:12

11

主题

93

回帖

469

积分

中级会员

积分
469
发表于 2025-3-7 13:44:34 | 显示全部楼层
还有里面的长按开机可以实现吗,有没有大佬指点一下
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:415
  • 最近打卡:2025-04-30 09:58:34
已绑定手机

39

主题

2006

回帖

6841

积分

论坛元老

积分
6841
发表于 2025-3-7 19:12:18 | 显示全部楼层
布丁橘长教学视频第19期有介绍:

截图202503071912097857.jpg

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

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:33
  • 最近打卡:2025-04-28 10:23:12

11

主题

93

回帖

469

积分

中级会员

积分
469
发表于 2025-3-8 11:18:51 | 显示全部楼层
wnag*** 发表于 2025-3-7 20:42
如果你的按键只是接在IO口上,那么长按开机就是假的,比如有屏幕时,没有长按,屏幕不亮,长按后,屏幕有 ...

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

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:33
  • 最近打卡:2025-04-28 10:23:12

11

主题

93

回帖

469

积分

中级会员

积分
469
发表于 2025-3-8 11:19:08 | 显示全部楼层
乘风*** 发表于 2025-3-7 19:12
布丁橘长教学视频第19期有介绍:

我看看,谢谢
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:122
  • 最近打卡:2025-05-01 08:43:07
已绑定手机

2

主题

106

回帖

262

积分

中级会员

积分
262
发表于 2025-3-10 08:11:45 | 显示全部楼层
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-04-29 08:28:25
已绑定手机

17

主题

446

回帖

1173

积分

金牌会员

积分
1173
发表于 2025-3-10 08:46:08 | 显示全部楼层
中断里还死等
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民I
  • 打卡总天数:78
  • 最近打卡:2025-04-30 10:04:20

7

主题

22

回帖

1063

积分

金牌会员

积分
1063
发表于 2025-3-11 10:47:18 | 显示全部楼层
bit click_count = 0;           // 单击计数
这个是不是定义错了。
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-2 01:47 , Processed in 0.126471 second(s), 112 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表