用单片机或ARM做的产品经常会遇到有键盘输入的产品,而键盘输入有一个绕不过去的问题便是:键盘去抖。见下图
当按键开关闭合或许断开时各有一段电平不安稳的时期,按键开关在闭合时不会立刻就安稳的接通,在断开时也不会一会儿彻底断开,而是在闭合和断开的瞬间随同了一连串的电平颤动。这种颤动一般都在10ms左右。为了保证程序对按键的一次闭合或许一次断开只呼应一次,有必要进行按键的去抖处理。当检测到按键状况变化时,不是当即去呼应动作,而是先等候闭合或断开安稳后再进行处理。
按键去抖办法可分为硬件去抖和软件去抖,硬件去抖不在本文的评论中,本文只评论软件去抖。
一般的软件去抖便是程序在检测到按键闭合或断开时调用一段延时子程序(在C言语中叫函数),程序在此死等10ms或更长。延时往后再检测按键的状况是否与延时前的状况共同,若共同就履行键盘程序部分,若不共同,则越过履行键盘程序。
这种办法在程序工作量不是很大时是没有问题的。但在一些CPU负荷量比较大的程序中,特别是在一些程序工作中有比较多的在不确定时刻就会产生的中止的情况下(外部中止、串口中止、定时器中止等),在这儿死等,就有或许形成某部分程序不能很好地被履行,乃至程序跑飞等严重问题。
自己通过多年的编程,总结了一套处理这问题的办法,供我们参阅。
程序是用51汇编言语写的,我们若要用C言语编写,参阅这流程图改一下就成。
先解说这流程图中的变量和子程序:
KSTEP:步进指示变量,当程序从主程序进入到此子程序后,立刻依据这KSTEP的值跳到相应的程序段。
KEYSCAN:读键盘子程序,若你的按键数量不多的话,直接读IO口。按键数量多的话,就要用矩阵方法读键盘,这儿不作赘述。
HASK:位变量,读键盘子程序中的位变量,当读键盘子程序KEYSCAN检测到有键闭合时置“1”,反之置“0”。
R2:键值变量,读键盘子程序KEYSCAN读出的键值。
KVALU:键值变量,R2的键值送到这儿,供此子程序下一次判别或主程序运用。
K20MS:20ms计时器变量,当第一次检测到有键闭合时往里面送值10。程序初始化中设定定时器中止为2ms时刻距离。进入定时器中止后,首要判别K20MS是否为0?若为0则直接退出定时器中止;若不为0则将K20MS减1后再退出定时器中止。这样K20MS变量从10减到0时刻为20ms。键断开时也是相同地履行。
KAVA:位变量,告知主程序:键闭合(断开)有用。
程序解说:
1.程序初始化时KSTEP的值为0,所以一进入簿本程序,程序立刻就跳到标号KSC0处,在此处调用读键盘子程序KEYSCAN。
1.1从KEYSCAN出来后,若位变量HASK的值为0,阐明没有键闭合,程序直接跳到标号RET处退出。
1.2若位变量HASK的值为1,便是有键闭合,此刻将数值1送入步进指示变量KSTEP中,便于下次进入簿本程序时,程序直接跳到标号KSC1处。再将从KEYSCAN子程序读出来的键值送入变量KVALU中,用于下次再调用读键盘子程序KEYSCAN时与R2读出的键值进行比较。
最终将数值10送入20ms计时器变量K20MS中,用于2ms定时器中止后减1,然后退出子程序。
2.当主程序再次调用簿本程序时,程序立刻就跳到标号KSC1处。
2.1在此处首要判别20ms计时器变量K20MS是否减到0(也便是判别20ms延时到了没有?),若K20MS不为0(20ms延时还没有到),则当即退出。
2.2若K20MS为0(阐明20ms延时时刻到了),再次调用读键盘子程序KEYSCAN。调用KEYSCAN子程序后,再次判别位变量HASK是否有用?
2.2.1若HASK无效,阐明前次(KSC0处)或许是遭到一次搅扰。所以复位KSTEP(清0),退出。使下次调用本程序时,又从头开始。
2.2.2若HASK有用,则将这次从KEYSCAN读出的键值与前次读出并存在KVALU中的键值进行比较。
2.2.2.1若比较值不同,则程序跳到标号KE1处,将新的键值存入KAVALU中,20ms后再调用KEYSCAN子程序,再次比较。
2.2.2.2若比较值相同,则阐明本次键闭合有用,所以置位KAVA(当主程序是键按下履行时),告知主程序,键闭合有用,能够履行此键所要做的程序了。一起将数值2送入步进指示变量KSTEP中,便于下次进入簿本程序时,程序直接跳到标号KSC2处。最终将数值10送入20ms计时器变量K20MS中,在下次进入KSC2标号处,也得等20ms之后再判别键是否断开。
3.现在主程序调用簿本程序时,程序立刻就跳到标号KSC2处,在此也相同,首要判别20ms计时器变量K20MS是否减到0(也便是判别20ms延时到了没有?),若K20MS不为0(20ms延时还没有到),则当即退出。若K20MS为0,调用读键盘子程序KEYSCAN。
调用KEYSCAN子程序后,判别位变量HASK是否有用?
3.1若HASK无效,阐明按键或许被开释断开,所以将数值3送入步进指示变量KSTEP中,便于下次进入簿本程序时程序能够直接跳到标号KSC3处。最终将数值10送入20ms计时器变量K20MS中,在下次进入KSC3标号处,也得等20ms之后再判别键是否持续断开状况。
3.2若HASK有用,阐明按键持续闭合状况,再比较KEYSCAN读出的键值与前次读出在KVALU中的键值进行比较。
3.2.1若比较值不同,则程序跳到标号KE0处,重新开始。
3.2.1若比较值相同,则阐明按键还没有断开,持续将数值10送入20ms计时器变量K20MS中,等20ms之后再进入标号KSC2处,再次判别按键是否断开。
4.当主程序调用簿本程序时,程序程序立刻跳到标号KSC3处,仍是首要判别20ms计时器变量K20MS是否减到0,若K20MS不为0(20ms延时还没有到),则当即退出。若K20MS为0,调用读键盘子程序KEYSCAN。
调用KEYSCAN子程序后,判别位变量HASK是否有用?
4.1若HASK无效,阐明按键现已彻底开释断开,所以将数值0送入步进指示变量KSTEP中,便于下次进入簿本程序时,程序从头开始,一起置位KAVA(当主程序是键开释履行时),告知主程序,键开释有用,能够履行此键所要做的程序了。
4.2如果位变量HASK持续有用,阐明又有键闭合了(尽管这种概率比较小,但程序得编进去),依据新键值与老键值的相同与不同,别离跳到标号KE3处,或许标号KE0处履行。
阐明:KE3标号和KE7标号下面都有SETBKAVA,实践编程时只用一次,依据你的主程序是在键按下履行仍是键开释履行选用。
本程序的特色便是:在等键闭合或断开去抖的那20ms时刻,不是死等,而是做好符号及置好必要的变量值后当即退出到主程序去做其他工作。程序每次从进入到退出这个子程序中所花的时刻一般为十几微秒(不含读键盘子程序KEYSCAN所花的时刻,KEYSCAN花的时刻依据按键数量的多少而不同,一般为几个微秒到几十微秒)。
责任编辑;zl