按键消抖通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开
消抖是为了避免在按键按下或是抬起时电平剧烈抖动带来的影响
结合上节笔记的边沿检测,我们看一下按键消抖例程
代码:
module Key_filter( clk, rst_n, key_in, key_flag, key_state ); input clk,rst_n; input key_in; output reg key_state;//按键状态 output reg key_flag;//按键标志输出 // localparam // idel = 4'b0001, //空闲态 // filter0 = 4'b0010, //抖动滤波 // down = 4'b0100, //按下稳定态 // filter1 = 4'b1000; ////////////////处理外部输入信号//////////////////////// reg key_in1,key_in2;// //外部输入的异步信号同步化 消除亚稳态 always @(posedge clk or negedge rst_n) if(!rst_n)begin key_in1 <= 1'b0; key_in2 <= 1'b0; end else begin key_in1 <= key_in; key_in2 <= key_in1; end reg key_tmp1,key_tmp2; //使用两级寄存器,边沿检测 always @(posedge clk or negedge rst_n) if(!rst_n)begin key_tmp1 <= 1'b0; key_tmp2 <= 1'b0; end else begin key_tmp1 <= key_in2; key_tmp2 <= key_tmp1; end wire p_edge,n_edge; //产生跳变沿信号 assign n_edge = !key_tmp1 & key_tmp2; assign p_edge = key_tmp1 & (!key_tmp2); /////////////////计数信号输出////////////////////// reg [3:0]cnt; reg en_cnt;//使能计数 always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 4'd0; else if(en_cnt) cnt <= cnt + 1'b1; else if(!en_cnt) cnt <= 4'd0; //计数满标志 always @(posedge clk or negedge rst_n) if(!rst_n) key_flag <= 1'd0; else if(cnt == 4'd9) key_flag <= 1'b1; else key_flag <= 1'd0; ////////////////状态机模块/////////////////////// reg [3:0]state,NS;//两段式状态机 always @(posedge clk or negedge rst_n) if(!rst_n) begin state <= 4'b1; end else begin state <= NS; end always @(state or n_edge or p_edge or key_flag) begin //en_cnt <= 1'b0; key_state <= 1'b1; case(state) 4'd1 : begin if(n_edge)begin en_cnt <= 1'b1; NS <= 4'd2; end else NS <= 4'd1; end 4'd2 : begin if(key_flag)begin NS <= 4'd3; en_cnt <= 1'b0; end else NS <= 4'd2; end 4'd3 : begin key_state <= 1'b0; if(p_edge)begin en_cnt <= 1'b1; NS <= 4'd4; end else NS <= 4'd3; end 4'd4 : begin if(key_flag)begin en_cnt <= 1'b0; key_state <= 1'b1; NS <= 4'd1; end else NS <= 4'd4; end default : begin NS <= 4'd1; en_cnt <= 1'b0; key_state <= 1'b1; end endcase end endmodule `timescale 1ns/1ns `define clk_period 20 module Key_tb; reg clk; reg rst_n; reg key_in; 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; // always @(posedge clk)//随机函数使用 // begin // #(`clk_period*100); // key_in ={$random}%2; // end initial begin rst_n = 0; key_in = 1; #(`clk_period*5); rst_n = 1; #(`clk_period + 1); press_key; #(`clk_period*200); press_key; #(`clk_period*200); press_key; #(`clk_period*500); $stop; end task press_key;//任务函数的使用 begin #500 key_in = 0; #500 key_in = 1; #500 key_in = 0; #500 key_in = 1; #500 key_in = 0; #500 key_in = 1; #500 key_in = 0; #500 key_in = 1; #500 key_in = 0; #500 key_in = 1; #500 key_in = 0; #500 key_in = 1; end endtask endmodule
仿真波形:
关于仿真模型
此时可以使用仿真模型,Augus会使用...但是讲不明白==,很伤情的
需要了解的请查看
发烧友小梅哥专版 http://bbs.elecfans.com/zhuti_fpga_1.html
视频讲的很容易懂
文章评论(0条评论)
登录后参与讨论