首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

按键消抖的原理和基于verilog的消抖设计(2)

按键消抖的原理和基于verilog的消抖设计(2)

在处理按键抖动的程序中,必须同时考虑消除闭合和断开两种情况下的抖动。所以,对于按键消抖的处理,必须按最差的情况来考虑。我们从上面的图上可以看到,按键输出的信号的跳变时间(上升沿和下降沿)最大是在20ms左右。按键一次闭合最短的时间大概是120ms左右。
如果我们把按键的输出做为一个时钟域(时钟频率未知,但信号的slowrate是已知的,既最大20ms左右)的信号,用另外一个时钟来采集这个按键的输出,则就可以把按键的消抖归结为一个最基本的CDC问题来处理。而问题的核心是如何确定采集时钟的频率。假设采集时钟的周期小于20ms,那么,采集时钟就有可能两次采到按键断开时的不确定的值,就没有办法避免采用CDC电路所想避免的问题。所以采集时钟的周期必须要大于20ms。假设采集时钟的周期大于120ms的话,就有可能采不到按键的闭合信号,所以采集时钟的周期必须小于120ms。我们在这里选用周期为25ms的采集时钟(频率为40Hz)。
下面的verilog实现实际上是一个标准的CDC电路,直接可以用来做按键的消抖。
module RMV_BJ (
BJ_CLK, //采集时钟,40Hz
RESET, //系统复位信号
BUTTON_IN, //按键输入信号
BUTTON_OUT //消抖后的输出信号
);
input B_CLK;
input RESET;
input BUTTON_IN;
output BUTTON_OUT;
reg BUTTON_IN_Q, BUTTON_IN_2Q, BUTTON_IN_3Q;
always @(posedge BJ_CLK or negedge RESET)
begin
if(~RESET)
begin
BUTTON_IN_Q <= 1'b1;
BUTTON_IN_2Q <= 1'b1;
BUTTON_IN_3Q <= 1'b1;
end
else
begin
BUTTON_IN_Q <= BUTTON_IN;
BUTTON_IN_2Q <= BUTTON_IN_Q;
BUTTON_IN_3Q <= BUTTON_IN_2Q;
end
end
wire BUTTON_OUT = BUTTON_IN_2Q | BUTTON_IN_3Q;
endmodule
在实际的实现中,我们首先要生成一个40Hz的时钟,然后有多少个按键就将上面的模块例化多少次就可以了。比如说我们有4个按键,那么下面的实现就可以了。其中KEY_CTL[3:0]是按键的输入,KEY_OUT[3:0]是按键的输出。
RMV_BJ RMV_BJ0( .BJ_CLK(BJ_CLK), .RESET(RESET),.BUTTON_IN(KEY_CTL[0]), .BUTTON_OUT(KEY_OUT[0]) );
RMV_BJ RMV_BJ1( .BJ_CLK(BJ_CLK), .RESET(RESET),.BUTTON_IN(KEY_CTL[1]), .BUTTON_OUT(KEY_OUT[1]) );
RMV_BJ RMV_BJ2( .BJ_CLK(BJ_CLK), .RESET(RESET),.BUTTON_IN(KEY_CTL[2]), .BUTTON_OUT(KEY_OUT[2]) );
RMV_BJ RMV_BJ3( .BJ_CLK(BJ_CLK), .RESET(RESET),.BUTTON_IN(KEY_CTL[3]), .BUTTON_OUT(KEY_OUT[3]) );
下面的波形是实测出来的按键消抖前后的波形,红色的为消抖前,白色的为消抖后。

要注意的是,经过处理后的按键信号,实际上是一个时钟域为40Hz的信号,如果我们要将按键送给后级电路使用,那么必须要将其转换到后级电路的时钟域中,转换的方法与上面所述CDC电路相同。
另外不同的按键的闭合,断开抖动时间都是有差异的,上面所讲的例子只参照了一种普通的机械按键,所以可能不具有普遍性。但对于不同的按键,处理方法都是一样的,只要根据按键特性,选定采集时钟的频率就可以了。
继承事业,薪火相传
返回列表