FPGA|CPLD|ASIC论坛
直播中

张玉兰

7年用户 1341经验值
私信 关注
[经验]

FPGA如何实现按键除抖

`假设你将一个机械按键开关与FPGA相连,你可能会遇上一些麻烦。
下图是一个按键开关按下10次的结果。

【问题所在】
要想将开关与FPGA相连,你的连接方式可能是这样的:
2.png
但机械开关最大的问题就在于它们会抖动!
当按下按键时,要是幸运的话结果会如图:
3.png
这是比较罕见的,比较常见的应该如下图:
1.png
2.png
3.png

【FPGA计数器】
假设你在FPGA中加入了一个计数器,让后将其显示出来。如下图:
1.jpg
按下10次得到的结果可能和本文开头的图片一样。

【解决办法】
解决办法之一就是加入一个R/C硬件滤波器,然后给FPGA加入一个施密特触发器,但其实还有一个更简单的办法。


FPGA滤波器


FPGA在简单算法上使用起来相当顺手。我们用FPGA的计数器来看按键按下与松开的时间有多长。只有当该计数器超值时,我们才决定该按键改变了状态。
1.png
该图中PB是按键信号(图中为低电平有效)。这样的设计可能会有一些毛刺,因为它没有与任何时钟同步。所以目前还是无法使用的。

我们要将PB与一个时钟同步(本例中使用20MHz),然后创建三个按键输出,全部都是无毛刺且与时钟同步的。每个输出都是高电平有效,且表示按键的三个不同状态(按键状态,刚按下状态,刚松开状态)。

  1. module PushButton_Debouncer(
  2.     input clk,
  3.     input PB,

  4.     output reg PB_state,
  5.     output PB_down,
  6.     output PB_up
  7. );

  8. reg PB_sync_0;  always @(posedge clk) PB_sync_0 <= ~PB;  // invert PB to make PB_sync_0 active high
  9. reg PB_sync_1;  always @(posedge clk) PB_sync_1 <= PB_sync_0;

  10. reg [15:0] PB_cnt;

  11. wire PB_idle = (PB_state==PB_sync_1);
  12. wire PB_cnt_max = &PB_cnt;        // true when all bits of PB_cnt are 1's

  13. always @(posedge clk)
  14. if(PB_idle)
  15.     PB_cnt <= 0;  // nothing's going on
  16. else
  17. begin
  18.     PB_cnt <= PB_cnt + 16'd1;
  19.     if(PB_cnt_max) PB_state <= ~PB_state;
  20. end

  21. assign PB_down = ~PB_idle & PB_cnt_max & ~PB_state;
  22. assign PB_up   = ~PB_idle & PB_cnt_max &  PB_state;
  23. endmodule
我们用了一个16位计数器,在20MHz的系统时钟下,只要3ms就可以超值。在用户的眼中看来,3ms几乎是不可察觉了。但好在毛刺没了。按键有多少毛刺以及系统时钟速度,都决定了你如何调整计数器的位宽。
` 1.jpg

更多回帖

发帖
×
20
完善资料,
赚取积分