当前位置:   article > 正文

FPGA搭积木之按键消抖(改进版)

FPGA搭积木之按键消抖(改进版)

目录

1.前言

2.回顾之前的设计

3.基于读者思路的设计

4.ModelSim仿真


1.前言

  昨天分享的关于FPGA对机械按键消抖的设计,有读者指出了其中的不足,并给出了他的思路。今天就读者的设计思路,来再做一个按键消抖模块。这个程序大概是大学的时候写的,当时才开始学,没考虑那么多。现在开始写博客,才陆续把以前写过的东西翻出来、分享。首先感谢这位读者,给我提出意见,学习的时候就是要多互相交流才能进步。大家对文章有问题,欢迎来和我讨论。

2.回顾之前的设计

  之前的按键消抖模块链接

按键消抖过程

  之前的设计思路是,在检测到按键稳定时,延迟20ms再进行采样,然后得到稳定的按键信号。但是有读者说了,这样处理,按下去至少20ms才会生效,对于年轻人来说可能会明显的感觉到延迟,这样设计似乎更适合老年人哈哈哈哈。不过,该方法的一个好处就是,获取的按键值是稳定后的,可以避免一些误触,或者由于抖动之类的导致按键闭合,影响判断。

之前设计的消抖模块如下图所示,如果把延迟时间设置为5ms,一方面迟滞感就不会那么强,另一方面按键也还是稳定了一段时间才进行采样,避免了亚稳态。具体延迟时间可能要根据需求去设置,思路是这么个思路。

按键消抖过程

按键消抖过程

3.基于读者思路的设计

(1)在检测到按键按下时,按键即刻生效,输出一个时钟高电平脉冲。
(2)按键生效时,设置一个标志位;并开始计时20ms
(3)在计时没有完成之前,对按键作输入无效处理。
(4)计时结束,更改标志位状态,按键输入重新有效。
代码如下:

  1. `timescale 1ns / 1ps
  2. module key_debounce #(parameter DELAY_CNT = 'd1_000_000)//50M时钟时的20ms计数值
  3. (    //防抖模块端口声明
  4.       
  5.       input  clk   ,//50M
  6.       input  rst_n  ,
  7.       input  key   , //定义按键输入
  8.       
  9.       output  key_out  //定义按键输出
  10. );
  11. wire        key_edge_pluse ;
  12. wire [$clog2(DELAY_CNT) - 1:0] cnt    ;
  13. wire        cnt_last  ;
  14. reg         key_flag  ;
  15. edge_detection #(.POSEDGE(1'b0))
  16. u_edge_detection (
  17.  .clk   (clk   ), 
  18.  .edge_din     (key   ),
  19.  .edge_pluse     (key_edge_pluse )
  20. );
  21. assign key_out = key_edge_pluse & ~key_flag;
  22. always @ (posedge clk or negedge rst_n) begin
  23.  if (!rst_n) 
  24.   key_flag <= 1'b0;
  25.  else if(key_edge_pluse)
  26.   key_flag <= 1'b1;//检测到按键按下后,在计数结束前后续按键值无效
  27.  else if(cnt_last)
  28.   key_flag <= 1'b0;
  29. end
  30. counter #(.CNT_NUM(DELAY_CNT),
  31.   .ADD(1'b1))
  32. u_counter(
  33.  .clk  (clk  ), 
  34.  .rst_n  (rst_n  ),
  35.  .En_cnt  (key_flag ),      
  36.  .cnt  (cnt  ), 
  37.  .cnt_last (cnt_last )
  38. );
  39. endmodule

其中使用到的计数器模块和边沿检测请参考之前的设计。
FPGA搭积木之计数器
FPGA搭积木之边沿检测电路

4.ModelSim仿真

  1. `timescale 1ns / 1ps
  2. module key_debounce_tb;
  3. parameter T = 20;
  4. reg  clk  ;
  5. reg  rst_n ;
  6. reg  key  ;
  7. wire key_out ;
  8. key_debounce #(.DELAY_CNT('d2_0))//为了减小仿真时间,将延时减小
  9. u_key_debounce(
  10. .clk    (clk    ), 
  11. .rst_n  (rst_n  ),
  12. .key    (key    ), 
  13. .key_out(key_out) 
  14. );
  15. always #(T/2) clk = ~clk;
  16. initial begin
  17.  clk = 1'b0;
  18.  rst_n = 1'b0;
  19.  key = 1'b1;
  20.  #(10*T)
  21.  rst_n = 1'b1;
  22.  //模拟按键抖动,实际只有一次按键输入
  23.  #(T)
  24.  key = 1'b0;
  25.  #(T)
  26.  key = 1'b1;
  27.  #(T)
  28.  key = 1'b0;
  29.  #(3*T)
  30.  key = 1'b1;
  31.  #(T)
  32.  key = 1'b0;
  33.  #(5*T)
  34.  key = 1'b1;
  35.  #(T)
  36.  key = 1'b0;
  37.  #(T)
  38.  key = 1'b1;
  39.  //模拟第二次按键抖动
  40.  #(20*T)
  41.  key = 1'b0;
  42.  #(T)
  43.  key = 1'b1;
  44.  #(2*T)
  45.  key = 1'b0;
  46.  #(T)
  47.  key = 1'b1;
  48.  #(T)
  49.  key = 1'b0;
  50.  #(5*T)
  51.  key = 1'b1;
  52.  #(T)
  53.  key = 1'b0;
  54.  #(T)
  55.  key = 1'b1;
  56.  
  57. end
  58. endmodule

为了减小仿真时间,例化按键消抖模块时,将延时计数器值改小,方便验证逻辑。然后模拟两次按键输入。

仿真

仿真

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

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

闽ICP备14008679号