当前位置:   article > 正文

FPGA搭积木之按键消抖

FPGA搭积木之按键消抖

目录

1.前言

2.原理

3.verilog代码

4.按键消抖模块IP核调用


1.前言

  由于机械按键的物理特性,按键被按下的过程中,存在一段时间的抖动,同 时在释放按键的过程中也存在抖动,这就导致在识别的时候可能检测为多次的按键按下,而通常检测到一次按键输入信号的状态为低电平,就可以确认按键被按下了,所以我们在使用按键时往往需要消抖,以确保按键被按下一次只检测到一次低电平。

我们理想中的按键是下面这样:

但是实际中的按键是这样的:

实际中的按键

2.原理

  一般开发板上的按键都是机械按键,所以在按下的时候,会产生回弹的时刻,称为机械的弹性开关。机械按键在按下和松开有一个抖动的过程,这个过程大概在10ms到15ms之间,具体取决于实际情况。这导致你按键按下但不一定真的按下了,按键弹起来了但不一定真的弹起来了。 如果不消除这个抖动,那么我们想要的效果将会得到一个很不确定的值。

机械按键

  为了能够得到准确的按键信号,我们需要在检测到按键抖动时,延迟20ms再进行采样,即可得到稳定的按键信号。

延迟采样消抖

3.verilog代码

设计思路如下:
(1)使用一个寄存器,将按键信号打一拍,将按键信号打一拍后的值与当前按键信号进行比较,来检测按键是否稳定。
(2)只要检测到按键不稳定,即还在抖动,就清零计数器,重新开始计数。
(3)只有当按键稳定后才启动计数器进行20ms的计数。
(4)如果按键信号未能稳定20ms时,key_flag <= 1'b0;认为按键值无效。
(5)只有当按键信号稳定20ms时,key_flag <= 1'b1;此按键值有效。

按键消抖过程

  1. module key_debounce 
  2. #(parameter DELAY_CNT = 'd1_000_000)//50M时钟时的20ms计数值
  3. (    //防抖模块端口声明
  4.       input clk      ,//50M
  5.       input rst_n    ,
  6.       input key      ,//定义按键输入
  7.       
  8.       output key_out//定义按键输出
  9. );
  10. reg         key_value ;//用于反馈key的值
  11. reg        key_flag ;//按键标志
  12. reg  [$clog2(DELAY_CNT) - 1:0]  delay_cnt ;//用于延时计数
  13. reg                             key_reg  ;//用于记住上一刻key的值
  14. assign key_out = key_flag & ~key_value;
  15. always @ (posedge clk or negedge rst_n) begin
  16.       if (!rst_n) begin //复位,key_reg置1,即未按下,延时计数清0
  17.             key_reg <= 1'b1;
  18.             delay_cnt <= 'd0;
  19.       end
  20.       else begin
  21.             key_reg <= key; //key_reg记下此时key的值
  22.             if (key_reg != key)  //若按键不稳定
  23.                   delay_cnt <= DELAY_CNT;  //延时计数置满
  24.             else if (key_reg == key) begin
  25.                   if (delay_cnt > 0)
  26.                         delay_cnt <= delay_cnt - 1'd1; 
  27.                         //若20ms延时没结束,每次延时计数减1
  28.                  else
  29.                         delay_cnt <= delay_cnt;
  30.             end
  31.       end   
  32. end                  
  33.              
  34. always @ (posedge clk or negedge rst_n) begin
  35.       if (!rst_n) begin
  36.             key_flag <= 1'b0;       //复位时按键标志置0
  37.             key_value <= 1'b1;    //按键值置1
  38.       end
  39.       else begin
  40.             if (delay_cnt == 'd1) begin 
  41.                   //20ms延时结束,按键标志置1,反馈值记下此时key的值
  42.                   key_flag <= 1'b1;
  43.                   key_value <= key;
  44.            end
  45.             else begin //20ms延时未到按键标志置0
  46.                   key_flag <= 1'b0;
  47.                   key_value <= key_value;
  48.              end
  49.         end
  50.  end
  51. endmodule 
  52.             

4.按键消抖模块IP核调用

  该模块可以当成IP核使用,根据自己的FPGA时钟频率,计算出20ms需要的计数值,调用模块时,在顶层修改参数即可使用。如100M时钟时的调用如下所示:

  1. key_debounce #(.DELAY_CNT('d2_000_000))//100M时钟的计数值
  2. u_key_debounce(
  3. .clk    (clk    ), 
  4. .rst_n  (rst_n  ),
  5. .key    (key    ), 
  6. .key_out(key_out) 
  7. );

  将设计参数化,放入自己的代码库,供有需要时直接使用。相比于官方提供的封闭的IP核,自己设计的IP核虽然性能比不过,但是更灵活,方便进行个性化修改。FPGA其实就像搭积木一样,只要自己的代码库够丰富,设计只会越来越轻松! 此合集持续分享一些笔者自己设计的可复用硬件模块:FPGA搭积木

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/591997
推荐阅读
相关标签
  

闽ICP备14008679号