转载自:http://m.elecfans.com/article/608499.html
1、引言
在自己在科研实践和对学生教学中发现,现在单片机学习中对于按键处理的方法都是:检测按键、延时消抖、按键执行、等待释放,整个按键处理的程序中大量出现“delay_1ms(5);”和“while(!key);”这样的语句,这明显是在给自己找麻烦,延时消抖与等待释放需要消耗CPU运行时间,执行效率低下,而且这种方法处理的按键程序也实现不了按键的短按、长按等灵活的按键操作方式。本文讲述了一种用状态机实现按键扫描的方法,达到按键的短按和长按功能,高效的处理按键消抖问题。
2、状态机
状态机在软件编程中非常重要,一个思路清晰而且高效的程序,必然有状态机的身影浮现。比如在按键命令解析程序中,本来是在状态1中,触发一个按键后切换到状态2,再触发另一个按键切换到状态3,或者返回到状态1。按键的击键过程也是一种状态的切换,也可以看着是一个状态机,一个按键的击键过程包括:按下、抖动、闭合、抖动和释放等状态。我们只要把这些状态机的思想想办法用程序表示出来就可以了。
3、按键的状态机实现
我们这里用状态机是为解决问题的,那么我们就要从问题本身去思考。为了实现按键扫描,达到按键短按和长按的功能,可以根据一个按键从按下按键到释放按键的整个过程将按键分为4个状态:
S0:等待按键按下
S1:按键按下
S2:等待按键短按释放
S3:等待按键长按释放
假设按键按下为低电平“0”,按键未按下为高电平“1”,按键的整个过程我们就可以通过状态转移图表示出来,如图1所示。
图1:按键的状态转移图
首先,按键的初始状态为S0,当检测到输入为1时,表示按键没有按下,保持S0;当输入为0时,表示按键按下,状态转入S1。在S1状态中,检测输入信号是否为0,如果为0,执行按键程序转入S2;如果为1,表示之前的按键操作是干扰信号,回到S0。在S2状态中,如果输入信号是1,则回到S0,表示按键短按已经释放;如果按键没有释放,输入为0时,就开始计时,计时没有结束前一直在S2,当计时结束了,转入S3,表示按键一直按着,为长按功能,在S2计时过程中,输入从0变为1也会回到S0。在S3状态中,输入信号为1,返回S0,表示按键长按释放;输入信号为0,执行相应的按键程序,也可以计时,等计时结束执行按键程序,达到按键连击的功能。这就是采用状态机进行按键检测达到短按与长按的整个过程。
下面以四个按键接在P1的P1.7、P1.6、P1.5、P1.4,设计状态机按键扫描程序。
程序代码如下:
#defineS00//状态0
#defineS11//状态1
#defineS22//状态2
#defineS33//状态3
voidkey()
{staticunsignedcharstate=S0,key_time;
unsignedcharkey;
key=P1&0xf0;//屏蔽P1低四位
switch(state)//检测状态
{caseS0://状态0
if(key!=0xf0)state=S1;break;//判断输入是否为0,为0转入状态1
caseS1://状态1
if(key==0xf0)state=S0;//判断输入是否为1,为1返回状态0
else//否则,转入状态2,执行按键程序
{state=S2;
switch(key)
{case0xe0:/*按键1执行程序*/
break;
case0xd0:/*按键2执行程序*/break;
case0xb0:/*按键3执行程序*/break;
case0x70:/*按键4执行程序*/break;}}
break;
caseS2://状态2
if(key==0xf0)state=S0;//判断输入是否为1,为1返回状态0
elseif(++key_time==100){key_
time=0;state=S3;}break;
//否则开始计时,计时结束转入状态3
caseS3://状态3
if(key==0xf0)state=S0;//判断输入是否为1,为1返回状态0
elseif(++key_time==5)//否则开始计时,计时结束按键连击
{key_time=0;
switch(key){
case0xe0:break;
case0xd0:break;
case0xb0:break;
case0x70:break;}
}break;}}
4、中断处理按键消抖
通常使用的按键都是机械弹性按键,也就是轻触开关。机械按键在触点的闭合和断开的过程中会产生抖动,一个按键在按下时不会立刻稳定的导通,在释放时也一样,不会一下子就断开,在按下和释放瞬间都会有一连串的抖动现象。按键的抖动时间有按键的机械特性决定,一般情况为5ms~10ms。这种抖动人是感觉不出来的,但是单片机的运行速度是微秒级的,这里可以设计一个定时中断来检测按键的状态,通过定时中断来消除按键抖动问题。因此可以把定时器的时间设置为10ms,每隔10ms进入一次中断检测一次按键的状态。
5、总结
本文介绍的这种以状态机来实现按键检测的方法,与一般的按键检测方法相对比,能完成案件的多种状态的检测,实现按键的短按和长按功能。采用状态机编写的按键程序也大大的改进了按键消抖对CPU运行时间消耗的问题。程序代码简单,维护方便,适用范围广。