机械按键在按下和松开有一个抖动的过程,这个过程大概在10ms到15ms之间,具体取决于实际情况。如果不消除这个抖动,那么我们想要的效果将会得到一个很不确定的值,比如我想要的是按一下数码管显示1,再按一下数码管管显示2,依次显示3,4,5,6;如果不消抖,我按键按一下上面的每一个值都可能显示,所以无法达到我想要的目的。
真实按键效果如下:
想要的效果如下:
当然,也有机械按键不需要消抖的设计,比如说复位按键,复位按键要求我在按下复位按键后系统回归到原始状态或者一个设定的状态,那么按键按下和松开期间抖动了多少次对结果并没有影响,所以可以不用消抖。
现在我们明确一点,按键有按下,按下后没有松开的等待过程和松开的过程,只有按键按下和松开有机械抖动的效果。那么我们要做的就是判断按键按下的那一刻做一个20ms的延时,然后等待按键松开的那一刻,再做一个延时,整个过程就完成了。
下面给出Verilog程序设计:(系统时钟50M,低电平复位,低电平按键按下)
module shake(
input clk ,
input rstn ,
input key , //按键信号
output reg shape //消抖信号
);
//例化模块
//shake shake1(
// .clk (clk ),
// .rstn (rstn ),
// .key (key ),
// .shape (shape)
//);
parameter delay=999999; //20ms计数,仿真建议50
reg [19:0]t20ms;
reg t ;
reg [ 1:0]cm ;
always@(posedge clk) //按键信号延时一个时钟
t <= key;
wire thl = t&&(!key); //t————|____key,下降沿
wire tlh = (!t)&&key; //t____|————key,上升沿
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
shape <= 0;
t20ms <= 0;
cm <= 0;
end else case(cm)
0:begin
if(thl)begin //等待按键发生
cm <= 1;
shape <= 0;
t20ms <= 0;
end else begin
shape <= 0;
t20ms <= 0;
cm <= 0;
end
end
1:begin
if(t20ms == delay)begin //20ms延时
shape <= 0;
t20ms <= 0;
cm <= 2;
end else begin
shape <= 0;
t20ms <= t20ms+1;
cm <= 1;
end
end
2:begin
if(tlh)begin //等待按键松开
shape <= 0;
t20ms <= 0;
cm <= 3;
end else begin
shape <= 0;
t20ms <= 0;
cm <= 2;
end
end
3:begin
if(t20ms == delay)begin //20ms延时,同时给出消抖信号
shape <= 1;
t20ms <= 0;
cm <= 0;
end else begin
shape <= 0;
t20ms <= t20ms+1;
cm <= 3;
end
end
default:begin
shape <= 0;
t20ms <= 0;
cm <= 0;
end
endcase
end
endmodule
如果要实现按键按一下,计数器加一下,就可以把shape波形作为计数器的时钟。
下面给出Verilog程序设计:(系统时钟50M,低电平复位,低电平按键按下)
module shake(
input clk ,
input rstn ,
input key , //按键信号
output reg [3:0] count //按键个数,10进制
);
//例化模块
//shake shake1(
// .clk (clk ),
// .rstn (rstn ),
// .key (key ),
// .count (count)
//);
parameter delay=999999; //20ms计数,仿真建议50
reg shape;
reg [19:0]t20ms;
reg t ;
reg [ 1:0]cm ;
always@(posedge clk) //按键信号延时一个时钟
t <= key;
wire thl = t&&(!key); //t————|____key,下降沿
wire tlh = (!t)&&key; //t____|————key,上升沿
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
shape <= 0;
t20ms<= 0;
cm <= 0;
end else case(cm)
0:begin
if(thl)begin //等待按键发生
cm <= 1;
shape <= 0;
t20ms<= 0;
end else begin
shape <= 0;
t20ms<= 0;
cm <= 0;
end
end
1:begin
if(t20ms== delay)begin //20ms延时
shape <= 0;
t20ms <= 0;
cm <= 2;
end else begin
shape <= 0;
t20ms <= t20ms+1;
cm <= 1;
end
end
2:begin
if(tlh)begin //等待按键松开
shape <= 0;
t20ms<= 0;
cm <= 3;
end else begin
shape <= 0;
t20ms<= 0;
cm <= 2;
end
end
3:begin
if(t20ms== delay)begin //20ms延时,同时给出消抖信号
shape <= 1;
t20ms <= 0;
cm <= 0;
end else begin
shape <= 0;
t20ms <= t20ms+1;
cm <= 3;
end
end
default:begin
shape <= 0;
t20ms <= 0;
cm <= 0;
end
endcase
end
always@(posedge clk or negedge rstn)
begin
if(!rstn)begin
count <= 0;
end else begin
if((count == 9)&&(shape))begin //按键10进制计数器
count <= 0;
end else if(shape)begin
count <= count+1;
end else begin
count <= count;
end
end
end
endmodule