按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开
消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响
结合上节笔记的边沿检测,我们看一下按键消抖例程
代码:
moduleKey_filter(
clk,
rst_n,
key_in,
key_flag,
key_state
);
inputclk,rst_n;
inputkey_in;
outputregkey_state;//按键状态
outputregkey_flag;//按键标志输出
// localparam
// idel=4'b0001,//空闲态
// filter0=4'b0010,//抖动滤波
// down=4'b0100,//按下稳定态
// filter1=4'b1000;
////////////////处理外部输入信号////////////////////////
regkey_in1,key_in2;//
//外部输入的异步信号同步化消除亚稳态
always@(posedgeclkornegedgerst_n)
if(!rst_n)begin
key_in1<=1'b0;
key_in2<=1'b0;
end
elsebegin
key_in1<=key_in;
key_in2<=key_in1;
end
regkey_tmp1,key_tmp2;
//使用两级寄存器,边沿检测
always@(posedgeclkornegedgerst_n)
if(!rst_n)begin
key_tmp1<=1'b0;
key_tmp2<=1'b0;
end
elsebegin
key_tmp1<=key_in2;
key_tmp2<=key_tmp1;
end
wirep_edge,n_edge;
//产生跳变沿信号
assignn_edge=!key_tmp1&key_tmp2;
assignp_edge=key_tmp1&(!key_tmp2);
/////////////////计数信号输出//////////////////////
reg[3:0]cnt;
regen_cnt;//使能计数
always@(posedgeclkornegedgerst_n)
if(!rst_n)
cnt<=4'd0;
elseif(en_cnt)
cnt<=cnt+1'b1;
elseif(!en_cnt)
cnt<=4'd0;
//计数满标志
always@(posedgeclkornegedgerst_n)
if(!rst_n)
key_flag<=1'd0;
elseif(cnt==4'd9)
key_flag<=1'b1;
else
key_flag<=1'd0;
////////////////状态机模块///////////////////////
reg[3:0]state,NS;//两段式状态机
always@(posedgeclkornegedgerst_n)
if(!rst_n)begin
state<=4'b1;
end
elsebegin
state<=NS;
end
always@(stateorn_edgeorp_edgeorkey_flag)
begin
//en_cnt<=1'b0;
key_state<=1'b1;
case(state)
4'd1 : begin
if(n_edge)begin
en_cnt<=1'b1;
NS<=4'd2;
end
else
NS<=4'd1;
end
4'd2 : begin
if(key_flag)begin
NS<=4'd3;
en_cnt<=1'b0;
end
else
NS<=4'd2;
end
4'd3 : begin
key_state<=1'b0;
if(p_edge)begin
en_cnt<=1'b1;
NS<=4'd4;
end
else
NS<=4'd3;
end
4'd4 : begin
if(key_flag)begin
en_cnt<=1'b0;
key_state<=1'b1;
NS<=4'd1;
end
else
NS<=4'd4;
end
default : begin
NS<=4'd1;
en_cnt<=1'b0;
key_state<=1'b1;
end
endcase
end
endmodule
`timescale1ns/1ns
`defineclk_period20
moduleKey_tb;
regclk;
regrst_n;
regkey_in;
wirekey_flag;
wirekey_state;
Key_filterkey_filter0(
.clk(clk),
.rst_n(rst_n),
.key_in(key_in),
.key_flag(key_flag),
.key_state(key_state)
);
initialclk=1;
always#(`clk_period/2)clk=~clk;
// always@(posedgeclk)//随机函数使用
// begin
// #(`clk_period*100);
// key_in={$random}%2;
// end
initialbegin
rst_n=0;
key_in=1;
#(`clk_period*5);
rst_n=1;
#(`clk_period+1);
press_key;
#(`clk_period*200);
press_key;
#(`clk_period*200);
press_key;
#(`clk_period*500);
$stop;
end
taskpress_key;//任务函数的使用
begin
#500key_in=0;
#500key_in=1;
#500key_in=0;
#500key_in=1;
#500key_in=0;
#500key_in=1;
#500key_in=0;
#500key_in=1;
#500key_in=0;
#500key_in=1;
#500key_in=0;
#500key_in=1;
end
endtask
endmodule
仿真波形: