在使用单片机搭建有人机交互的系统时需要用到键盘,因为单片机工作时间都是纳秒与毫秒级别,但是我们人体的反应时间最少要0.2秒,之间差距很大,现实过程中也会不小心碰到按键,正常的按下按键应该是持续数十秒的稳定。
一、按键电路常用的非编码键盘,每个在使用单片机搭建有人机交互的系统时需要用到键盘,因为单片机工作时间都是纳秒与毫秒级别,但是我们人体的反应时间最少要0.2秒,之间差距很大,现实过程中也会不小心碰到按键,正常的按下按键应该是持续数十秒的稳定。
一、按键电路常用的非编码键盘,每个键都是一个常开开关电路。
计数器输入脉冲最好不要直接接普通的按键开关,因为记数器的记数速度非常快,按键、触点等接触时会有多次接通和断开的现象。
我们感觉不到,可是记数器却都记录了下来。
例如,虽然只按了1下,记数器可能记了3下。
因此,使用按键的记数电路都会增加单稳态电路避免记数错误。
二、按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号小型如下图。
由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
因而在闭合及断开的瞬间均伴随有一连串的抖动,如下图。
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。
这是一个很重要的时间参数,在很多场合都要用到。
按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。
键抖动会引起一次按键被误读多次。
为确保CPU对键的一次闭合仅作一次处理,必须去除键抖动。
在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。
按键的抖动,可用硬件或软件两种方法。
三、硬件消抖在键数较少时可用硬件方法消除键抖动。
下图所示的RS触发器为常用的硬件去抖。
消抖电路如下图中两个“与非”门构成一个RS触发器。
当按键未按下时,输出为1;当键按下时,输出为0。
此时即使用按键的机械性能,使按键因弹性抖动而产生瞬时断开(抖动跳开B),中要按键不返回原始状态A,双稳态电路的状态不改变,输出保持为0,不会产生抖动的波形。
也就是说,即使B点的电压波形是抖动的,但经双稳态电路之后,其输出为正规的矩形波。
这一点通过分析RS触发器的工作过程很容易得到验证。
利用电容的放电延时,采用并联电容法,也可以实现硬件消抖:消抖电路如下四、软件延时消抖如果按键较多,常用软件方法去抖,即检测出键闭合后执行一个延时程序,产生5ms~10ms的延时,让前沿抖动消失后再一次检测键的状态,如果仍保持闭合状态电平,则确认为真正有键按下。
当检测到按键释放后,也要给5ms~10ms 的延时,待后沿抖动消失后才能转入该键的处理程序。
五、无延时的软件消抖/*********************************************名称:键盘扫描子函数功能:在按键稳定期内判断键值,并返回键值**********************************************/uchar keyscan(void){static char key_state = 0;static char key_value = 0;uchar key_press, key_return = 0;key_press=turn_left&turn_right; //读按键I/O电平switch (key_state){case 0 : // 按键初始态if (key_press==0) key_state = 1; // 键被按下,但需要确认是否是干扰break;case 1 : // 按键确认态if (key_press==0)//如有键按下则不是干扰,判断键值{if(turn_left==0) //判断是哪一个按键被按下key_value=1; //按键较多时可采用switch选择结构else if(turn_right==0)key_value=2;elsekey_value=0;key_state = 2; // 状态转换到键释放态}elsekey_state = 0; // 按键已抬起,属于干扰,转换到按键初始态break;case 2 :if (key_press==1){key_return=key_value;//按键释放后再输出键值,如果按下键就输出则可省略key_valuekey_value=0;key_state = 0; //如果按键释放,转换到按键初始态}break;}return key_return; //返回键值}/*********************************************名称:按键处理子函数功能:**********************************************/void key_operation(void){switch (keyscan()) //根据键值不同,执行不同的内容{case 1:hight_votage-=1;if(hight_votage<5)hight_votage=5;break;case 2:hight_votage+=1;if(hight_votage>25)hight_votage=25;break;default :break;}}系统的信号输入中,键盘因其结构简单而被广泛使用。
因此,对键盘的输入(逻辑0或1)进行准确采样,避免错误输入是非常有必要的。
理想的键盘输入特性如图1所示:按键没有按下时,输入为逻辑1,一旦按下则输入立刻变为逻辑0,松开时输入则立刻变为逻辑1。
图 1理想键盘输入特性然而实际的键盘受制造工艺等影响,其输入特性不可能如图1完美。
当按键按下时,在触点即将接触到完全接触这段时间里,键盘的通断状态很可能已经改变了多次。
即在这段时间里,键盘输入了多次逻辑0和1,也就是输入处于失控状态。
如果这些输入被系统响应,则系统暂时也将处于失控状态,这是我们要尽量避免的。
在触点即将分离到完全分离这段时间也是一样的。
实际键盘的输入特性如图2所示:图 2实际键盘输入特性我们可以看到:键盘在输入逻辑转换时,实际上是产生了瞬时的高频干扰脉冲。
按键消抖的目的在于消除此干扰,以达到接近图1所示的理想输入特性。
有两个阶段可以设法消除此干扰:1.在键盘信号输入系统之前(系统外);2.键盘信号输入系统以后(系统内)。
在信号输入系统之前将抖动干扰消除,可以节省系统资源,提高系统对其他信号的响应能力,也就是硬件消抖。
一种比较巧妙的硬件消抖电路结构如图3所示:图 3用基本SR锁存器构成的消抖电路该电路利用基本SR锁存器的记忆作用消除开关触点振动所产生的影响。
开关S 每切换一次,输出端只有一次翻转,不存在抖动波形(读者可以根据SR锁存器功能自行分析,此处略)。
但是使用SR锁存器消抖只适用于单刀双掷开关,实际应用当中常用的键盘多是两个接线端的按键。
对此类按键的常用硬件消抖电路如图4所示:图 4常用键盘硬件消抖电路此电路利用电容平波,再经过施密特反相器整形之后就得到了没有毛刺的脉冲波。
软件消抖要占用系统资源,在系统资源充足的情况下使用软件消抖更加简单。
软件消抖的实质在于降低键盘输入端口的采样频率,将高频抖动略去。
实际应用中通常采用延时跳过高频抖动区间,然后再检测输入做出相应处理。
一般程序代码如下:if(value == 0) //一旦检测到键值{Delay(); //延时20ms,有效滤除按键的抖动if(value == 0) //再次确定键值是否有效{…… //执行相应处理这段软消抖程序从机理上看不会有什么问题,通常在软件程序不太"繁忙"的情况下也能够很好的消抖并做相应处理。
但是如果在延时期间产生了中断,则此中断可能无法得到响应。
对于硬件资源丰富的FPGA系统,可以使用硬件来减轻软件工作量,通常称之为"硬件加速"。
在按键信号输入到软件系统前用逻辑对其进行一下简单的处理即可实现所谓的"硬件消抖",verilog代码如下:该程序中设置了一个20ms计数器,通过间隔20ms对输入信号inpio采样两次,两次相同则认为键盘输入稳定,得到用硬件逻辑处理后的inpio_swin信号则是消抖处理过的信号。
软件程序就不再需要delay()来滤波了,也不会出现使用纯软件处理出现的"中断失去响应"的情况了,这就是"硬件加速"的效果。
上述verilog代码采用间隔采样来达到消抖的目的,对于不同物理特性的键盘,最佳的间隔时间采样时间也不同,因此还存在一些不稳定因素。
下面介绍一种更好的软消抖程序,同样采用"硬件加速",不同之处在于使用了有限状态机来实现,其VHDL代码如下:SIGNAL pre_s, next_s: state; BEGINP0:PROCESS( reset, clk )BEGINif reset = '0' thenpre_s <= s0;elsif rising_edge( clk ) thenpre_s <= next_s;elsenull;end if;END PROCESS P0;P1:PROCESS( pre_s, next_s, din ) BEGINcase pre_s iswhen s0 =>dout <= '1';if din = '1' thennext_s <= s0;elsenext_s <= s1;end if;when s1 =>dout <= '1';if din = '1' then next_s <= s0;elsenext_s <= s2;end if;when s2 =>dout <= '1';if din = '1' then next_s <= s0;elsenext_s <= s3;end if;when s3 =>dout <= '0';if din = '1' then next_s <= s0;elsenext_s <= s1;end if;end case;END PROCESS P1;END RTL;该VHDL代码描述了一个状态机,其状态转换图如图所示:图 5状态转换图该状态机有4个状态:S0、S1、S2、S3,其中前3个状态输出高电平,最后一个状态输出低电平。
初始状态为S0,设按键未按下时为高电平,按下则为低电平。