思路:
状态机的思想,分4个状态:
1.空闲状态,等待按键按下
2.消除抖动状态1,用计数器延时5ms至10ms
3.按键按下
4.消除抖动状态2,用计数器延时5ms至10ms
程序:
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;
reg [3:0] state;
reg [19:0] cnt;
reg en_cnt;
reg cnt_full;
reg temp0,temp1;
wire pos_edge,neg_edge;
localparam
IDLE = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
always@( posedge Clk or negedge Rst_n )
begin
if( Rst_n==0 )
begin
state <= IDLE;
Key_flag <= 0;
Key_state <= 1;
en_cnt <= 0;
end
case ( state )
IDLE:
begin
Key_flag <= 0;
if( neg_edge==1 )
begin
state <= FILTER0;
en_cnt <= 1;
end
end
FILTER0:
begin
if( cnt_full==1 )
begin
state <= DOWN;
Key_flag <= 1;
Key_state <= 0;
en_cnt <= 0;
end
else if( pos_edge==1 )
begin
state <= IDLE;
en_cnt <= 0;
end
end
DOWN:
begin
Key_flag <= 0;
if( pos_edge==1 )
begin
state <= FILTER1;
en_cnt <= 1;
end
end
FILTER1:
begin
if( cnt_full==1 )
begin
state <= IDLE;
Key_flag <= 1;
Key_state <= 1;
end
else if( neg_edge==1 )
begin
state <= DOWN;
en_cnt <= 0;
end
end
default:
begin
state <= IDLE;
Key_flag <= 0;
Key_state <= 1;
en_cnt <= 0;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
temp0 <= 1'b0;
temp1 <= 1'b0;
end
else begin
temp0 <= Key_in;
temp1 <= temp0;
end
assign neg_edge = !temp0 & temp1;
assign pos_edge = temp0 & (!temp1);
always@( posedge Clk or negedge Rst_n )
begin
if( Rst_n==0 )
cnt <= 0;
else if( en_cnt==1 )
cnt <= cnt+1;
else
cnt <= 0;
end
always@( posedge Clk or negedge Rst_n )
begin
if( Rst_n==0 )
cnt_full <= 0;
else if( cnt==99_999 )
cnt_full <= 1;
else
cnt_full <= 0;
end
endmodule
testbench程序:
`timescale 1ns/1ns
`define clk_period 20
module Key_Filter_tb;
reg Clk;
reg Rst_n;
reg Key_in;
reg [15:0] rand;
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 = 0;
#(`clk_period*10);
Rst_n = 1;
#(`clk_period*10 + 1);
press_key;
#10000;
press_key;
#10000;
press_key;
#10000;
$stop;
end
task press_key;
begin
repeat(20)
begin
rand = {$random} % 65536 ;
#rand;
Key_in = ~Key_in;
end
Key_in = 0;
#50_000_000;
repeat(20)
begin
rand = {$random} % 65536 ;
#rand;
Key_in = ~Key_in;
end
Key_in = 1;
#50_000_000;
end
endtask
endmodule
RTL仿真结果: