(1)设计意义:按键消抖主要针对的时机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子就断开。因而在闭合以及断开的瞬间会伴随有一连串的抖动,为了保证系统正确的识别到按键的开关,就必须对按键的抖动进行处理,这就是按键消抖。
(2)Verilog实现代码:
module key_filter(clk,reset_n,key_in,key_p_flag,key_r_flag,key_state);
input clk;
input reset_n;
input key_in;
output reg key_p_flag;
output reg key_r_flag;
output reg key_state;
reg key_in1;
reg key_in2;
reg key_in3;
reg [3:0]STATE;
//抖动时间往往小于20ms,20ms = 20_000_000ns = 20ns * 1_000_000; 需要一个20位的寄存器
reg [19:0]cnt;
reg en_cnt;
wire podge;
wire nedge;
wire arrive_time_20ms;
//状态设计
parameter IDLE = 4'b0001;
parameter P_SHAKE = 4'b0010;
parameter DOWN = 4'b0100;
parameter R_SHAKE = 4'b1000;
//异步输入key_in信号的同步化————“打两拍”
always@(posedge clk)begin
key_in1 <= key_in;
key_in2 <= key_in1;
end
//上升沿、下降沿设计
always@(posedge clk)
key_in3 <= key_in2;
assign podge = key_in2 && (!key_in3);
assign nedge = (!key_in2) && key_in3;
//20ms计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 20'd0;
else if(en_cnt &&(cnt == 20'd999_999))
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 20'd1;
else
cnt <= 20'd0;
//计满20ms信号设计
assign arrive_time_20ms = (cnt == 20'd999_999);
//状态机主程序设计
always@(posedge clk or negedge reset_n)
if(!reset_n)begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
end
else begin
case(STATE)
IDLE:begin
key_r_flag <= 1'd0;
key_state <= 1'd1;
if(nedge)begin
STATE <= P_SHAKE;
en_cnt <= 1'd1;
end
else
STATE <= STATE;
end
P_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= DOWN;
en_cnt <= 1'd0;
key_p_flag <= 1'd1;
key_state <= 1'd0;
end
else if(podge)begin
STATE <= IDLE;
en_cnt <= 1'd0;
end
else
STATE <= STATE;
end
DOWN:begin
key_p_flag <= 1'd0;
key_state <= 1'd0;
if(podge)begin
STATE <= R_SHAKE;
en_cnt <= 1'd1;
end
else
STATE <= STATE;
end
R_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= IDLE;
en_cnt <= 1'd0;
key_r_flag <= 1'd1;
key_state <= 1'd1;
end
else if(nedge)begin
STATE <= DOWN;
en_cnt <= 1'd0;
end
else
STATE <= STATE;
end
default:begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
end
endcase
end
endmodule
(3)仿真文件代码:
`timescale 1ns / 1ps
module key_filter_tb;
reg clk;
reg reset_n;
reg key_in;
wire key_p_flag;
wire key_r_flag;
wire key_state;
key_filter key_filter_inst(
.clk(clk),
.reset_n(reset_n),
.key_in(key_in),
.key_p_flag(key_p_flag),
.key_r_flag(key_r_flag),
.key_state(key_state)
);
initial clk = 1'd1;
always #10 clk = ~clk;
initial begin
reset_n <= 1'd0;
key_in <= 1'd1;
#15;
reset_n <= 1'd1;
#2000;
key_in <= 1'd0;
#1500;
key_in <= 1'd1;
#20000;
key_in <= 1'd0;
#40_000_000;
key_in <= 1'd1;
#1000;
key_in <= 1'd0;
#200;
key_in <= 1'd1;
#1800;
key_in <= 1'd0;
#25000;
key_in <= 1'd1;
#30_000_000;
$stop;
end
endmodule
(4)仿真波形分析: