30行代码实现按键的长按和多击检测

30行代码实现按键的长按和多击检测

用30行代码(按键扫描函数长度)实现按键的单击,长按,多击检测。代码如下:

//按键宏定义,根据实际测试进行修改
//实际时间为:数值*10ms (按键扫描)
#define K_Dou_Time  2   //按键消抖时间 20ms
#define K_Long_Time 100  //按键长按判定 1S
#define K_Lian_Time 50   //按键连击时间 500ms
//按键连击时间是指按键释放后到再次按下的时间间隔
u8 code er[8]={1,2,4,8,16,32,64,128};
sbit K1=P3^2;
//按键长按及单击,多击检测
//此函数需要10ms执行一次(大概范围即可)
void KEY1_Scan()
{
  static u8 cnt=0;//用于按键按下计时
  static u8 Fcnt=0;//用于按键连击倒计时
  static u8 KEY_cnt=0;//用于记录按键按下次数
  if(K1==0)//按键按下,时间增加
  {
    cnt++;//按键按下时间
  }
  else//按键释放/没有按下按键/按键抖动
  {
    if(cnt>K_Long_Time)//说明是长按,长按时间
    {
      P2=0X00;//按键按下次数用P2口展示
    }
    else if(cnt>K_Dou_Time)//如果大于抖动时间,认为是短按/多个短按
    {
      KEY_cnt++;//按键按下次数加一
      Fcnt=K_Lian_Time;//重新开始倒计时
    }
    cnt=0;//按键按下时间变量清除
    if(Fcnt)//如果大于0,才能递减,Fcnt变量一定会减为0。
    {
      Fcnt--;
      if(Fcnt==0)//如果减到0了,说明按键已经 K_Lian_Time 没有按下了
      {
        P2=~er[KEY_cnt];//按键按下次数用P2口展示
        KEY_cnt=0;//记录按键按下次数的变量,必须被清除
      }
    }
  }
}

代码进行了大量的注释,代码的原理也很简单,这里简单说明一下:

按键按下后,cnt变量自加,10ms加一下,算是定时采样,如果采集到高电平,就认为按键处于释放状态。

然后我们去判断cnt变量的大小,

如果大于长按时间,我们就认为是长按,然后就可以执行长按的内容了。

如果大于一般认为的抖动时间,我们认为当前操作是短按。因为短按存在连击现象,所以这里我们不能立即执行,我们给倒计时变量赋值500ms,当按键处于释放状态下,短按时间才会递减,当时间减为0的时候,认为按键的连击已经结束了,也就是,按键松开后500ms,没有再次按下。那么我们就可以根据按键按下的次数变量,去执行对应的功能。

如果按键再次被按下,因为按键处于低电平,按键连击倒计时是不会进行的。同时按键再次释放后,会将倒计时重置为500ms。

当然以上情况为理想状态,可能存在按键抖动部分去消耗按键倒计时,这部分可以忽略,也可以增长倒计时间去抵消此部分。但是增长时间,会减缓按键的执行速度,因此,这是一个需要权衡的操作。

此代码存在的问题/不足,和使用注意事项:

1,如果按键一直按下不起,这个情况还是不处理的好,程序中没有处理

2,如果按键按下时间超过8位变量最大值,会出现从头开始,那建议修改为16位变量记录

3,按键状态检测代码的先天缺陷,按键执行是在按键释放后,还会存在等待再次按下的时间,因此按键执行延迟较高,如果想要执行速度较快,可以考虑按键确认按下后,立即执行,这里就不分享这个内容了。

4, 此代码中的u8是unsigned char,此代码基于51单片机平台

5,此代码需要10ms运行一次,建议使用定时器。

6,此代码可以扩展到更多形式的按键,比如矩阵按键。

演示视频:https://www.ixigua.com/7125667312317039141

代码讲解视频:https://www.ixigua.com/7125668273185948194