实现按键消抖功能:
1.滤除按键按下时的噪声和松开时的噪声信号。
2.获取已消抖的按键按下的标志信号。
3.实现已消抖的按键的连续功能。
Verilog实现
模块端口
key_filter(input wire clk ,input wire rst_n ,input wire key_in , //按下按键时为0output 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;elsecnt_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;endelsecnt_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;endelsekey_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;#20rst_n = 1'b1;#(20*199+100)$stop;
endalways #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;elsetb_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;elsekey_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