硬件消抖

友晶科技很多板子的按键其实是已经有硬件消抖电路的, 这样的板子的按键的值 直接input 进来后 直接用就可以。

比如DE2-115  DE1-SOC  DE10-Standard 等等。这里用74HC245芯片来消抖:

 

 

 

软件消抖

如果没有硬件上的消抖,我们可以手写Verilog代码替代消抖电路。

软件消抖的原理主要为按键按下或松开后延时 5ms—20ms 采样。
按键去抖的思路是检测到按下时延时 20ms,再检测,如果状态仍为按下,则确认是按下的;如果状态为弹起的,则确认是干扰,无按键按下。
模板1:
module key                //按键消抖模块
(    input clk,                    //系统时钟
    input rst_n,                //系统复位
    input key[0],                    //按键输入
    output reg key_value,    //有效的按键值
);

    reg [31:0]cnt;//计数器
    reg value;//中间寄存器

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt <= 0;                //初始状态下寄存器清零
            key_value <= 0;        //有效按键值清零        
            value <= 0;                //中间寄存器清零            
        end    
        else begin
            if(cnt == 50000) begin
                cnt <= 0;//每隔0.001秒检测一次 将key的值寄存到value寄存器当中(如果系统时钟是50MHz)
                value <= key[0];
                    
                if(value == 1 && key[0] == 0) //按键按下为0,平时为1
                    key_value <= 1;

            end                        
            else begin
                cnt <= cnt + 1;
                key_value <= 0;
            end
        end    
    end                
endmodule

 

 

第二个按键消抖模板:

//按键平时为0,按下为1
module Key(
    input clk,//系统时钟
    input rst_n,//系统复位
    input key[0],//按键输入
    output reg key_value//有效的按键值输出
    );

    reg [31:0] cnt;//计数器
    reg cnt_en;
   reg value;//中间寄存器
    
    parameter interval=1_000_000;//计数器的最大值 代表0.02秒  如果系统时钟的50MHz
        
    always @(posedge clk or negedge rst_n)
     begin
       if (~rst_n) 
        value<=1'b0;//复位的时候中间寄存器清零
            
        else if (cnt==interval-1) //每次按键的值和中间寄存器的值不一样并保持了0.02秒时,将key[0]的值赋值给中间寄存器
            value<=key[0];
    end
    
    always @(posedge clk or negedge rst_n)
     begin
       if (~rst_n) 
            key_value<=1'b0;//复位的时候有效的按键值输出寄存器清零
       else if (cnt==interval-1 && key[0]) 
            key_calue<=1'b1;
        else if (key_value) 
            key_value<=1'b0;
    end
    
    always @(posedge clk or negedge rst_n)
     begin
       if (~rst_n) 
            cnt_en<=1'b0;
            else if (key[0] != value) //当中间寄存器的值和当前keu[0]的值不同的时候 计数器自增1
            cnt_en<=1'b1;
        else cnt_en<=1'b0;
    end

    always @(posedge clk or negedge rst_n)
     begin
       if (~rst_n) 
            cnt<=32'b0;//复位的时候计数器清零
        else if (cnt_en) 
            cnt<=cnt+32'b1;
        else cnt<=32'b0;
    end
        
endmodule