FPGA开发:按键消抖

        按键是FPGA开发板上的重要交互元件,因为按键的内部的结构设计,在按下和松开按键时,按键会无法避免地产生机械抖动,因此要对按键输入进行特殊处理,否则可能会因为机械抖动产生意外的重复触发。

        按键消抖有很多方法,可以在按键后使用低通滤波器和缓冲器,也可以使用锁存器来保存按键的稳定值(如下图所示)。

FPGA开发:按键消抖_第1张图片

        本文将使用硬件编程的方式来完成消抖,使用一个计时器来保存按键稳定的时间,当发现按键不稳定时,则清空计时器重新开始,这样一来当按键稳定时间达到设定值(例如10ms)后,就会输出无抖动的按键值。

        另外需要注意的是,由于按键信号属于单比特异步信号,在进入时钟域前需要使用两级同步器来避免亚稳态,关于信号同步,可以阅读这篇文章数字IC前端学习笔记:跨时钟域信号同步。

module  Debounce 
(
    input       clk, 
    input       rst, 
    input       button_in,
    output reg  button_out
);

parameter N = 32 ;           // 计数器位宽
parameter FREQ = 50;         // 系统时钟频率 单位MHz
parameter MAX_TIME = 20;     // 设定时长,单位毫秒
localparam TIMER_MAX_VAL =   MAX_TIME * 1000 * FREQ; //计数值


reg  [N-1 : 0]  q_reg;      // 计时寄存器
reg  [N-1 : 0]  q_next;     // 下一状态计时组合逻辑
reg DFF1, DFF2;             // 两级缓冲器
wire q_add;                 // 计数使能信号
wire q_reset;               // 计数复位信号


assign q_reset = (DFF1 ^ DFF2);          // 复位信号产生逻辑
assign q_add = ~(q_reg == TIMER_MAX_VAL); // 使能信号产生逻辑
    
//计数器组合逻辑
always @ (q_reset, q_add, q_reg)
begin
    case({q_reset , q_add})
        2'b00 :
                q_next = q_reg;
        2'b01 :
                q_next = q_reg + 1;
        default :
                q_next = {N{1'b0}};
    endcase     
end

//同步器逻辑
always @ (posedge clk or negedge rst)
begin
    if(!rst)
    begin
        DFF1 <= 1'b0;
        DFF2 <= 1'b0;
    end
    else
    begin
        DFF1 <= button_in;
        DFF2 <= DFF1;
    end
end

//计数器时序逻辑
always @ (posedge clk or negedge rst)
begin
    if(!rst)
        q_reg <= {N{1'b0}};
    else
        q_reg <= q_next;
end

//输出逻辑
always @ (posedge clk or negedge rst)
begin
	if(!rst)
		button_out <= 1'b1;
    else if(q_reg == TIMER_MAX_VAL)
        button_out <= DFF2;
    else
        button_out <= button_out;
end

        当两次采集到的按键值不同时,q_reset为1,在下一个时钟沿时,计数器会被清零,TIMER_MAX_VAL中保存了特定计数时长所需的计数值。当q_reset为0,且计数值未到设定值时,q_add为1,在下一个时钟沿时,计数器加一。

图源《Verilog HDL高级数字设计》

你可能感兴趣的:(FPGA开发,fpga开发)