FPGA按键防抖
2012-06-02
标签: 按键

如果你连接了一个机械键盘到FPGA,那么你可能会碰到一些问题。这里我们按下键盘10次,希望LED显示00000010,但最后的结果如下...

按键防抖项目

这个项目包括两个部分:

  • 第一部分: 问题描述
  • 第二部分: 解决办法

链接

* 按键防抖指南

按键防抖 - 问题描述

假设我们需要连接一个键盘到FPGA,硬件上,我们可能这样实现:

但是,机械按键存在这样的问题:抖动!

当你按下按键,可能很幸运能得到如下的理想波形:

但更多的时候,得到的波形是这样的:

FPGA计数器

现在,假设我们在FPGA内部设计了一个计数器,并添加了一个显示器件来观察它是怎样工作的。

上电,看起来一切正常.

连续按下键盘十次,结果...

并不像我们想象的那样从0加到10.

按键防抖 - 解决办法

一种办法是在硬件上添加一个R/C滤波器,并且使用一个施密特触发器,但是我们有更简单的解决办法。

FPGA滤波器

FPGAs在简单的数字代数方面功能很强大. 让我们在FPGA内部使用一个计数器来计算按键被按下或松开多长时间。一旦计数器溢出,我们就认为按键的状态改变了。

PB是按键的信号输入(这个例子中低有效).可能包含若干个毛刺, 并且不与任何时钟信号同步,没有任何规律可言。通过设计,我们希望将其与一个始终信号同步(这个例子中使用的时钟频率为20MHz),并产生3个无毛刺的,与时钟同步的按键输出,所有输出均为高有效,从任何一个信号都能得到按键的状态改变信息。

module PushButton_Debouncer(clk, PB, PB_state, PB_up, PB_down);

input clk;// "clk" 时钟信号

input PB;// "PB" 有毛刺的、异步的、低有效的按键信号

output PB_state;// 当按键被按下时输出1

output PB_down;// 按键被按下的瞬间输出一个高电平脉冲

output PB_up;// 按键被松开的瞬间输出一个高电平脉冲

// 首先使用两个触发器来同步PB信号

reg PB_sync_0;always @(posedge clk) PB_sync_0 <= ~PB;// 翻转PB,使之高有效

reg PB_sync_1;always @(posedge clk) PB_sync_1 <= PB_sync_0;

// 声明一个16位的计数器

reg [15:0] PB_cnt;

// 当按键被按下或松开时,计数器计数

// 当计数器计数溢出时,便认为按键的状态的确已经改变

reg PB_state;// 按键状态 (0:松开, 1:按下)

wire PB_idle = (PB_state==PB_sync_1);

wire PB_cnt_max = &PB_cnt; //当B_cn为全1时,输出为真

always @(posedge clk)

if(PB_idle)

PB_cnt <= 0;// 没发生任何事情

else

begin

PB_cnt <= PB_cnt + 1;// 按键被按下或者松开, 增加计数器的值r

if(PB_cnt_max) PB_state <= ~PB_state;// 如果计数器溢出,改变PB_state的值

end

wire PB_down = ~PB_state & ~PB_idle & PB_cnt_max;// 当按键被按下时,有效一个时钟周期

wire PB_up=PB_state & ~PB_idle & PB_cnt_max;// 当按键被松开时,有效一个时钟周期

endmodule

使用16位的计数器、20MHz的时钟,需要3ms的时间才能使计数器溢出。在用户眼里,3ms的时间很短,甚至来不及反应,但是毛刺却正是在这3ms内被除去的。根据具体的按键和系统时钟,你可能需要修改计数器的宽度。

好了,该轮到你来实践了。

可能会用到的工具/仪表
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号