码迷,mamicode.com
首页 > 其他好文 > 详细

FPGA培训专家 V3学院带你学习 按键消抖 和 边缘检测

时间:2017-03-10 15:27:43      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:parameter   9.png   output   .com   区分   大于   标志位   通过   使用   

FPGA培训专家 V3学院  

  一般情况下,我们从按下按键到松开基本需要大于几十毫秒的时间,系统时钟的周期处于纳秒级,因此我们按下一次按键会被大于十万个时钟的上升沿采集到,然而我们希望的是按下一次按键只被一次上升沿采集到,不然会被认为按了多次按键,所以我们需要对我们的按键进行处理。假设按键在没被按下时为高电平,被按下时处于低电平,如图1所示的波形图。

技术分享

图1 按键波形图

由图1 分析可知在key被按下时有且仅有一个key的上升沿和一个key的下降沿,我们可以通过检测key的上升沿或者下降沿来确定按键被按下一次,这就涉及到边缘检测,具体方法如图2所示,可以用clk的上升沿将key延时一个周期产生key_reg,通过key和key_reg的值同时判断key的上升沿或下降沿。由图2可知,当用clk的上升沿检测到key等于1的同时key_reg等于0,此时则为key的上升沿,若key等于0的同时key_reg等于1则为key的下降沿。

技术分享 

图2 边缘检测

由图2可知根据key的上升沿或下降沿可确定按了一次键,然而事实却不允许我们这么做。图3给出了一个按键的模型,当不按下按键s时,a、b两点是断开的,按下按键s时线路才接通,然而当按下按键时,会存在物理上的抖动现象,此时a、b两点会在断开和接通之间反复的一段时间,就会出现图4所示的抖动、稳定的波形。

技术分享 

图3 按键模型

 技术分享

图4 按键抖动

       图4所示前抖动为按下时产生的抖动,后抖动为按键松开时造成的抖动,前、后抖动持续时间一般均为5~10ms,在有抖动的情况下,key会被clk上升沿采集到很多的上升沿和下降沿,因此用key的上升沿和下降沿判断按键一次就不成立了,我们需要寻找新的方法。

       我们知道按键被按下时key值为低电平(0),在抖动期间key既有高电平也有低电平,我们可以使用clk的上升沿计算key连续为低电平的时间,期间当检测到key为高电平时,则从头开始计数,当计数超过5~10ms时,我们可以认定按键有被按下的时候,此时我们可以产生一个clk周期为高电平的标志,当该标志位高电平认为有一次按键即可,具体波形如图5所示。

技术分享 

图5 按键消抖波形图

    此处我们认为key值有连续性的5ms时为按键被按下,时钟周期为50MHz,即20ns,可以算出5ms占250000个clk周期,也就是说cnt从0计数到249999为5ms,当cnt等于249999时可以将po_key_flag拉高一个周期,由于按键时间长短无法确定,因此cnt有可能多次达到249999这个值,会造成po_key_flag多次被拉高,这样有会出现按下一次键被当成按下多次,所以在图5中出现了cnt_flag变量,在遇到cnt等于249999时,cnt_flag就会被置高,直到遇到key等于高电平时才会被拉低,这样我们就可以将第一个cnt等于249999和后面的区分开,那么我们也可以用cnt和cnt_flag共同控制在一次按键中,保证po_key_flag有且仅有一个时钟周期的高电平。根据波形图可得到如下所示的代码。

代码示例:

1  //按键消抖模块

module       key_debounce(

input        wire    sclk            ,//系统时钟

input        wire    rst_n           ,

input        wire    key             ,//按键输入

output       reg     po_key_flag     //消抖后产生的标志

);

10 reg[17:0]    cnt             ;//消抖计数器

11

12 reg          cnt_flag        ;//计数器标志

13

14 //计数到5ms的最终值

15 parameter    CNT_END =       500000-1;

16

17 //产生消抖计数器

18 always@(posedge      sclk    or      negedge rst_n)

19      if(rst_n==1‘b0)

20              cnt     <=      18‘b0;

21      else if(key==1‘b0)

22              cnt     <=      cnt+1‘b1;

23      else

24              cnt     <=      18‘b0;

25

26 //产生消抖计数器的标志信号

27 always@(posedge      sclk    or      negedge rst_n)

28      if(rst_n==1‘b0)

29              cnt_flag        <=      1‘b0;

30      else if(cnt==CNT_END)

31              cnt_flag        <=      1‘b1;

32      else if(key==1‘b1)

33              cnt_flag        <=      1‘b0;

34             

35 //产生消抖后的po_key_flag

36 always@(posedge      sclk    or      negedge rst_n)

37      if(rst_n==1‘b0)

38              po_key_flag     <=      1‘b0;

39      else if(cnt==CNT_END&&cnt_flag==1‘b0)

40              po_key_flag     <=      1‘b1;

41      else

42              po_key_flag     <=      1‘b0;

43             

44 endmodule           

代码解析:

① 第18行的always块实现了一个计数器,当key键按下(值为0)的时候开始计数,当检测到按键松开(值为1)的时候计数器归零,这样在抖动时候,该计数器会出现计数、归零循环的一个过程,直到key值一直为0,即按键持续被按下并且抖动过程结束,计数器才会持续计数到5ms;

② 第27行的always块产生一个标志,当检测到cnt第一次等于5ms的时候,该标志则被置为高电平,这样就可以将cnt第一次等于5ms和之后的cnt等于5ms区分开,直到key松开(值为1)时,该标志才被置为低电平;

③ 第30行的always块实现产生整个按键过程中的一个时钟周期高电平的标志,当cnt计数到5ms时,为了确保只有一次的po_key_flag有效,因此此处条件中不仅需要cnt==5ms,而且需要cnt_flag==0。

 

来自于v3学院  www.v3edu.org

FPGA培训专家 V3学院带你学习 按键消抖 和 边缘检测

标签:parameter   9.png   output   .com   区分   大于   标志位   通过   使用   

原文地址:http://www.cnblogs.com/v3eduwym/p/6530615.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!