State值 | 状态 |
---|---|
0 | IDLE |
1 | P_FILTER |
2 | WAIT_R |
3 | R_FILTER |
为了消除亚稳态,前面加两个D触发器,使得信号同步,再与边沿检测器相连
上升沿:前一拍为0,后一拍为1
下降沿:前一拍为1,后一拍为0
module key_filter(
clk,
rst_n,
key,
key_p_flag,
key_r_flag
);
input clk;
input rst_n;
input key;
output reg key_p_flag;//press按下
output reg key_r_flag;//release松开
reg sync_d0_key;
reg sync_d1_key;
reg r_key;
wire pedge_key;//下降沿
wire nedge_key;//上升沿
wire time_20ms_reached;
reg [1:0]state;
localparam IDLE=0;
localparam P_FILTER=1;
localparam WAIT_R=2;
localparam R_FILTER=3;
parameter MCNT = 1_000_000-1;
reg [29:0]cnt;
always @(posedge clk) begin
sync_d0_key<=key;
end
always @(posedge clk) begin
sync_d1_key<=sync_d0_key;
end
always @(posedge clk) begin
r_key<=sync_d1_key;
end
assign nedge_key=(sync_d1_key==0)&&(r_key==1);
assign pedge_key=(sync_d1_key==1)&&(r_key==0);
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state<=IDLE;
key_p_flag<=0;
key_r_flag<=0;
end
else begin
case (state)
IDLE:begin
key_r_flag<=0;
if(nedge_key)
state<=P_FILTER;//检测到下降沿,进入按下消抖状态
end
P_FILTER:begin
if(time_20ms_reached)begin
state<=WAIT_R;//按下消抖完成,进入等待释放状态
key_p_flag<=1;
end
else if(pedge_key)
state<=IDLE;//20ms内检测到上升沿,是抖动,回到空闲
else
state<=state;//维持
end
WAIT_R:begin
key_p_flag<=0;
if(pedge_key)
state<=R_FILTER;//检测到上升沿,进入释放消抖状态
end
R_FILTER: begin
if(time_20ms_reached)begin
state<=IDLE;//20ms后没有出现下降沿,消抖完成
key_r_flag<=1;
end
else if(nedge_key)
state<=WAIT_R;//发生抖动,回到WAIT_R,等待下一次上升沿
else
state<=state;//维持
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt<=0;
else if((state==R_FILTER)||(state==P_FILTER))
cnt<=cnt+1'd1;
else
cnt<=0;
end
assign time_20ms_reached=(cnt==MCNT);
endmodule
`timescale 1ns/1ns
module key_filter_tb;
reg clk;
reg rst_n;
reg key;
wire key_p_flag;
wire key_r_flag;
key_filter k1(
.clk(clk),
.rst_n(rst_n),
.key(key),
.key_p_flag(key_p_flag),
.key_r_flag(key_r_flag)
);
initial clk=1;
always #10 clk=~clk;
initial begin
rst_n=0;
key=1;
#201;
rst_n=1;
key=1;#100000000;
//按下,开始抖动
key=0;#18000000;
key=1;#2000000;
key=0;#1000000;
key=1;#200000;
key=0;#20000000;
//稳定
key=0;#50000000;
//释放,开始抖动
key=1;#2000000;
key=0;#1000000;
key=1;#20000000;
//稳定
key=1;#50000000;
$stop;
end
endmodule
通过波形可以观察到,key信号有抖动,key_p_flag和key_r_flag依然正确指示按键是否按下,达到了消抖效果
本文章使用limfx的vscode插件快速发布