找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2175|回复: 2
收起左侧

51单片机实现按键短按双击长按程序

  [复制链接]
ID:1020872 发表于 2023-9-13 14:32 | 显示全部楼层 |阅读模式
这个程序使用状态机实现长按,双击,短按识别程序,很好的用,欢迎大家参考和指导
  1. /*-----------------------------------------------
  2.   名称:按键
  3. ------------------------------------------------*/
  4. #include"key.h"
  5. extern unsigned char keyvalue;

  6. unsigned char keyscan()
  7. {
  8.         unsigned char keynumber;
  9.         if(!KEY1) keynumber = 1;                                                                        //!!!修改此处,可以增加/减少按键数量
  10.         else if(!KEY2) keynumber = 2;                                                        //!!!修改此处,可以增加/减少按键数量
  11.         else if(!KEY3) keynumber = 3;                                                        //!!!修改此处,可以增加/减少按键数量
  12.         else if(!KEY4) keynumber = 4;                                                        //!!!修改此处,可以增加/减少按键数量
  13.         else keynumber = 0;
  14.         return keynumber;
  15. }

  16. unsigned char key_multi(void)
  17. {
  18.         static uchar key_state;                                                                         //按键状态变量
  19.         static uint key_time;                                                                                 //按键计时变量
  20.         static uchar key_press_nums;                                                        //按键次数变量               
  21.         static uint key_time_double;                                                        //按键双击时间
  22.         static uchar keynum;                                                                                        //键值
  23.         static uchar new_keynum;                                                                        //新的键值
  24.         uchar key_press, key_return;                                                        //键值和返回值
  25.        
  26.         key_return = None_click;                                                                         //清除返回按键值
  27.        
  28.         switch(keyscan())
  29.         {
  30.                 case 1:key_press = KEY1;new_keynum = 1;break;                //!!!修改此处,可以增加/减少按键数量
  31.                 case 2:key_press = KEY2;new_keynum = 2;break;                //!!!修改此处,可以增加/减少按键数量
  32.                 case 3:key_press = KEY3;new_keynum = 3;break;                //!!!修改此处,可以增加/减少按键数量
  33.                 case 4:key_press = KEY4;new_keynum = 4;break;                //!!!修改此处,可以增加/减少按键数量
  34.                 default:key_press = 1;break;
  35.         }
  36.         if(key_press_nums > 0)                                                                                 //按键次数大于0,说明有按键
  37.         {
  38.                 key_time_double++;                                                                                        //是否开始双击计
  39.                 if(key_time_double >= DOUBLE_KEY_TIME && key_time_double < LONG_KEY_TIME) key_state = KEY_STATE_2;//如果时间到了在双击和长按之间,切换到状态2
  40.         }
  41.         switch (key_state)
  42.         {
  43.                 case KEY_STATE_0:                                                                                         //按键状态0:判断有无按键按下
  44.                 {
  45.                         if (!key_press)                                                                                         //是否有按键按下,没有按下就退出
  46.                         {
  47.                                 key_time = 0;                                                                                         //清零时间间隔计数
  48.                                 key_state = KEY_STATE_1;                                                 //然后进入 按键状态1
  49.                         }
  50.                 }break;
  51.                 case KEY_STATE_1:                                                                                         //按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
  52.                 {
  53.                         if (!key_press)
  54.                         {
  55.                                 key_time++;                                                                                                 //一次10ms
  56.                                 if(key_time>=SINGLE_KEY_TIME)                         //消抖时间为:SINGLE_KEY_TIME*10ms = 10ms;
  57.                                 {
  58.                                         key_state = KEY_STATE_2;                                         //如果按键时间超过 消抖时间,即判定为按下的按键有效。进入按键状态2,继续判定到底是单击、双击还是长按
  59.                                         key_press_nums++;                                                                        //按键次数+1
  60.                                 }
  61.                         }
  62.                         else key_state = KEY_STATE_0;                                 //如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
  63.                 }break;
  64.                 case KEY_STATE_2:                                                                                         //按键状态2:判定按键有效的种类:是单击,双击,还是长按
  65.                 {
  66.                         if(key_press)                                                                                                 //如果按键在 设定的双击时间内释放,则判定为单击/双击
  67.                         {
  68.                                 if(key_time_double < DOUBLE_KEY_TIME ) key_state = KEY_STATE_0;                                                        //双击时间达到前,再次扫描按键,看还有没有按键按下
  69.                                 if(key_time_double >= DOUBLE_KEY_TIME && key_time_double < LONG_KEY_TIME)         //达到双击设定时间后,如果时间超过双击的时间则判断按键按下的次数
  70.                                 {
  71.                                         if(key_press_nums == 1) key_return = Single_click + new_keynum*10;                                 //判断只按了1次,返回有效按键值:单击,通过不同的值判断是哪个按键按下的单击
  72.                                         else if(key_press_nums ==2 && new_keynum == keynum) key_return = Double_click + new_keynum*10;         //判断按了2次和两次按键按的一样,返回有效按键值:双击,通过不同的值判断是哪个按键按下的双击
  73.                                         key_state = KEY_STATE_0;                                         //返回 按键状态0,继续等待按键
  74.                                         key_press_nums = 0;                                                                //清空按键次数
  75.                                         key_time_double = 0;                                                        //清空双击计时
  76.                                 }
  77.                                 if(key_time_double >LONG_KEY_TIME ) key_state = KEY_STATE_3;        //如果长按之后才松开的,则切换到状态3清0
  78.                         }
  79.                         else
  80.                         {       
  81.                                 key_time++;                                                                                                        //按键一直按着的话,长按计时
  82.                                 if(key_time >= LONG_KEY_TIME)                         //如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=80*10ms=800ms), 则判定为 长按
  83.                                 {
  84.                                         key_return = Long_click + new_keynum*10;         //返回有效键值值:长按,通过不同的值判断是哪个按键按下的长按了
  85.                                         //key_state = KEY_STATE_3;                                         //去状态3,等待按键释放
  86.                                 }
  87.                         }
  88.                 }break;
  89.                 case KEY_STATE_3:                                                                                         //等待按键释放
  90.                 {
  91.                         if (key_press)
  92.                         {
  93.                                 key_state = KEY_STATE_0;                                                 //按键释放后,进入 按键状态0 ,进行下一次按键的判定
  94.                                 key_press_nums = 0;                                                                        //清空按键次数
  95.                                 key_time_double = 0;                                                                //清空双击计时
  96.                         }
  97.                 }break;
  98.                 default:key_state = KEY_STATE_0;break;        //特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
  99.         }
  100.         keynum = new_keynum;                                                                                        //将新获取的键值赋值给键值
  101.         return key_return;                                                                                                 //返回 按键值
  102. }
复制代码


回复

使用道具 举报

ID:123289 发表于 2023-9-15 15:29 | 显示全部楼层
要点:做一个计数器CJ来判定长按与短按,CJ的规则如下:
1、CJ计数只发生于定时器的中断服务程序中,每次中断+1,计满不再计,即不回0。
2、CJ计数只发生于键按下的时候,未按下不计。
3、做一个键状态判定触发标记:B_OK,如果键未按下,但CJ<>0,则置B_OK=1,表示是判断键状态的时候了。
4、当B_OK=1,判断键状态的界定法则是:CJ<某个值为短按,CJ>某个值为长按,某个值是多少由你决定。建议事先将长短两个界定值放置在某个寄存器中,这样可以随意变更界定值。
5、状态界定完成后将:B_OK清0、CJ清0以备下次再界定。

双击:只是规定的时间内,发生了两个短按,这不在此叙述了。三击、多击如法炮制。
回复

使用道具 举报

ID:275826 发表于 2023-9-17 20:37 | 显示全部楼层
这个程序太复杂了
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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