实际波形相较于理想波形存在约20ms的抖动。
将按键按下的过程分为四个状态:
1、按键未按下空闲态
2、按键按下抖动滤除状态
3、按下稳定状态
4、释放按键抖动滤除状态
一次按键按下及释放需要:IDEL检测下降沿→FILTER检测下降沿(按键按下)→FILTER1检测上升沿→DOWN检测下降沿(按键释放)
key_flag:按下标志信号,检测到按键按下时输出脉冲
key_state:状态标志信号,按键未按下为高,按下为低
通过定义两个寄存器寄存输入状态判断是否有边沿产生。
上升沿:reg0→0,reg1→1
verilog代码(一段状态机):
module key_filter(Clk,Rst_n,key_in,key_flag,key_state);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
en_cnt <= 1'b0;
state <= IDEL;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
test_bench
`timescale 1ns/1ns
`define clk_period 20
module key_vibration_eliminate_tb1;
reg Clk;
reg Rst_n;
reg key_in;
wire key_flag;
wire key_state;
key_filter key_filter0(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(key_in),
.key_flag(key_flag),
.key_state(key_state)
);
initial Clk= 1;
always#(`clk_period/2) Clk = ~Clk;
initial begin
Rst_n = 1'b0;
key_in = 1'b1;
#(`clk_period*10) Rst_n = 1'b1;
#(`clk_period*10 + 1);
press_key;
#10000;
press_key;
#10000;
press_key;
$stop;
end
reg [15:0]myrand;
task press_key;
begin
repeat(50)begin
myrand = {$random}%65536;//0~65535;
#myrand key_in = ~key_in;
end
key_in = 0;
#50000000;
repeat(50)begin
myrand = {$random}%65536;//0~65535;
#myrand key_in = ~key_in;
end
key_in = 1;
#50000000;
end
endtask
endmodule
Modelsim波形