实现按键消抖功能:
1.滤除按键按下时的噪声和松开时的噪声信号。
2.获取已消抖的按键按下的标志信号。
3.实现已消抖的按键的连续功能。
Verilog实现
模块端口
key_filter(
input wire clk ,
input wire rst_n ,
input wire key_in , //按下按键时为0
output reg key_flag, //第一次按下的标志信号(已消抖)
output reg key_out , //输出按键信号(已消抖)
output reg key_cont //输出连续按键信号(已消抖)-计时一段时间拉高1次
);
20ms计数
always@(posedge clk or negedge rst_n)
if(!rst_n) cnt_20ms <= 20'd0;
else if(key_in) //松下按键
cnt_20ms <= 20'd0;
else if(cnt_20ms == CNT_20MS_MAX) //达到消抖时间
cnt_20ms <= CNT_20MS_MAX;
else
cnt_20ms <= cnt_20ms+20'd1;
按键第一次按下的标志信号
always@(posedge clk or negedge rst_n)
if(!rst_n) key_flag<=1'b0;
else if(cnt_20ms == CNT_20MS_MAX-20'd1) //已消抖,拉高key_flag一个周期
key_flag<= 1'b1;
else
key_flag<=1'b0;
已消抖的按键信号
always@(posedge clk or negedge rst_n)
if(!rst_n) key_out<=1'b0;
else if(key_in) //松下按键
key_out<= 1'b0;
else if(key_flag) //已消抖
key_out<= 1'b1;
else ;
连续信号所需计数器
always@(posedge clk or negedge rst_n)
if(!rst_n) cnt_cont <= 20'd0;
else if(key_out) begin //已消抖
if(cnt_cont == CNT_CONT_MAX)
cnt_cont <= 20'd0;
else
cnt_cont <= cnt_cont+20'd1;
end
else
cnt_cont <= 20'd0;
连续按键信号(已消抖)-计时一段时间拉高1次
always@(posedge clk or negedge rst_n)
if(!rst_n) key_cont<=1'b0;
else if(key_flag)
key_cont <= 1'b1;
else if(key_out) begin //已消抖
if(cnt_cont == CNT_CONT_MAX) //连续按下一定时间,拉高key_cont一个周期
key_cont <= 1'b1;
else
key_cont <= 1'b0;
end
else
key_cont <= 1'b0;
testbench:
`timescale 1ns/1ns
module tb_key_filter();
reg clk ;
reg rst_n ;
reg key_in ;
reg [7:0] tb_cnt ;
wire key_flag;
wire key_out ;
wire key_cont;
defparam u_key_filter.CNT_20MS_MAX = 20'd9;
defparam u_key_filter.CNT_CONT_MAX = 24'd49;
initial begin
clk = 1'b1 ;
rst_n = 1'b0;
#20
rst_n = 1'b1;
#(20*199+100)
$stop;
end
always #10 clk=~clk;
always@(posedge clk or negedge rst_n)
if(!rst_n) tb_cnt <=8'b0;
else if(tb_cnt ==8'd199)
tb_cnt <=8'b0;
else
tb_cnt <= tb_cnt +8'b1;
always@(posedge clk or negedge rst_n)
if(!rst_n) key_in <= 1'b1 ;
else if(((tb_cnt>=8'd9) && (tb_cnt<=8'd39))
||((tb_cnt>=8'd159) && (tb_cnt<=8'd179)))
key_in<={$random}%2;
else if((tb_cnt<8'd9)||(tb_cnt>8'd179))
key_in<=1'b1;
else
key_in<=1'b0;
key_filter u_key_filter(
.clk (clk ),
.rst_n (rst_n ),
.key_in (key_in ),
.key_flag (key_flag ), //第一次按下的标志信号(已消抖)
.key_out (key_out ), //输出按键信号(已消抖)
.key_cont (key_cont ) //输出连续按键信号(已消抖)-计时一段时间拉高1次
);
endmodule