c语言学 判断按键_按键消抖的状态机实现
近期学习了关于FPGA的按键消抖程序,对于开发板上按键的抖动通常都是由于按键开关为机械弹性开关所导致,当机械触点断开或闭合时,由于弹性作用,按键不会立刻断开或闭合,因而在闭合及断开的瞬间会形成一连串的抖动。这对判断按键按下的次数以及控制作用形成了一系列的干扰,为了保证能够正确的识别按键的触发,就必须对按键进行消抖。
01
按键抖动及消抖程序
话不多说先上图。

就比如上面的波形,前面几段比较短的抖动和后面几段比较短的抖动都是由于机械按键的弹性所造成的。中间那段比较长的波形便是我们按下的一段,为了能够正确的识别到这段波形,便必须将几段抖动的波形滤除掉。
下面便开始介绍消除抖动的程序,并通过按键控制四个LED进行二进制加减法运算。

和以前的定义端口类型一样时钟信号、复位信号和按键控制和led输出。时钟信号连接开发板上的50M晶振端口,复位信号和按键端口也是靠外部按键控制,led端口连接着FPGA的四个LED端口,通过系统内部的信号控制,所以时钟信号clk和复位信号rst和按键控制都定义为input输入类型,led端口定义为output输出类型。

这部分程序便是定义上升沿和下降沿,首先定义一个存储按键信号上一时刻的寄存器(key_r),用来存储按键上一时刻的状态。
然后定义上升沿(pedge_key)和下降沿(nedge_key),对其进行定义和描述,第20行,pedge_key = ((!key_r) && key)这行代码是说,当按键的上一时刻为低电平且当前时刻为高电平时,此时为上升沿;nedge_key = (key_r && (!key))这行代码是说,当按键的上一时刻为高电平且当前时刻为低电平时,此时为下降沿。

此处的程序为计数的程序,用于判断按键按下后的时间,因为一般按键按下后最起码会有20ms的延时,这也就是上面的波形正常按下的脉宽要长而抖动的时间却很短,计数持续通过定义的一个使能端(en_cnt)控制,当使能端(en_cnt)为1时开始计数,当使能端为0时停止计数,这部分程序在下面消抖部分会使用到。

这部分便是消抖所用的程序,使用了类似于c语言中的switch case语句,state为定义的判断按键当前状态的标志位,当state等于0时,判断按键此时是否按下触发下降沿;当系统检测到下降沿后便将state置1然后开始判断按键按下后低电平的持续时间,此时将计数信号的使能端给高电平,让计数程序开始计数,每一个周期(20ns)cnt加1,当计数时间大于20ms时判断为按键有效即停止计数将使能端置0,然后将state置2进行下一轮判断,如果在计数时间还未达到20ms时便检测到了上升沿,即判断为抖动并停止计数和将state置0,重新开始检测;当state置为2时,此时开始判断上升沿,当检测到上升沿之后便将state置3并将计数使能端置1开始计数,如果没有检测到则重复当前程序继续检测上升沿;当state置为3后便开始滤除掉按键松开后的抖动信号,也就是通过计数时间的长短来判断。
到此为止按键消抖的程序基本就写完了,然后就开始写仿真的程序。

首先也是老生常谈的端口定义和引用前面的程序端口并进行连线。

然后就是进行时钟仿真,首先开始让时钟信号置1,然后每隔10ns便让时钟信号clk翻转一次,这便是对50M时钟进行仿真。

这部分便是对按键信号进行仿真,仿真按键按下时的情景,对应的上面那张图的几个抖动和两次实际按下的情景。
02
程序仿真
首先来张全局仿真图。

这是我最后仿真结果,包含了对LED自减运算的仿真。

这是按键识别成功波形的仿真,图中可见state由1到3的变化,一般在state为2时也就是检测到了有效的上升沿后按键便识别成功,此时led自减一个二进制数1'b1,然后计数器停止计数等现象。
对于led自减的程序如下所示。

当state为2时也就是按键检测成功之后,首先判断led自减是否溢出,也就是四个灯是否全亮,如果是则返回重新开始计数,如果没有到顶溢出,则led执行相应的自减。
在这里的key_flag_r是我定义的一个标志位,因为我昨天在这里遇到了一个bug问题,那就是state由2变为3时系统需要执行一个周期,一个周期也就是20ns,如果不用一个标志位限制一下,在这个20ns内,led会持续递减,也就违背了要求不是按键按一下减一次。
标志位的设置为,当led在按键按下自减一次后,标志位置1,然后再加一个限制条件,当标志位为1时led不变化,当state为3时也就是按键过度后再将led的标志位清零。
若不加标志位限制的波形如下所示。

如上图所示,若不加标志位,在state为2时,led会持续递减,直到state为3。
03
实际现象
今天将程序下载进FPGA中观察一下现象。
按键没按一次,led进行一次二进制加法运算,至于为什么程序写的是减法,而现象却是加法,那是因为在FPGA中led一段接的上拉电阻,所以给低电平亮,则此处与程序则相反为加法运算。
更多推荐



所有评论(0)