You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog中如何消除按钮抖动,避免单次按压被识别多次?

按钮防抖的硬件实现方案(无需轮询/仿真延迟)

针对按钮抖动导致多次移位的问题,完全可以通过直接处理按钮输入解决,下面给出两种适用于实际硬件的纯逻辑实现方案,不需要内部轮询,也不用#10这类仅适用于仿真的延迟语句:

方案1:单次按压锁定(每毫秒仅响应一次)

核心思路是:检测到按钮上升沿后,立即锁定1毫秒,这段时间内不再响应任何边沿,避免抖动触发多次移位。依赖系统全局时钟(比如常见的50MHz)实现定时,属于同步逻辑处理输入。

module TopLevel(
    input        CLK,       // 系统全局时钟,例:50MHz
    input        KEY,       // 带抖动的按钮输入
    input        SW,
    output reg [9:0] LEDR
);

// 异步输入同步:避免亚稳态
reg KEY_sync1, KEY_sync2;
always @(posedge CLK) begin
    KEY_sync1 <= KEY;
    KEY_sync2 <= KEY_sync1;
end
wire KEY_posedge = KEY_sync2 & ~KEY_sync1; // 提取按钮上升沿

// 1ms定时锁定计数器(50MHz下,50000个时钟周期=1ms)
reg [15:0] debounce_cnt;
reg debounce_lock;
always @(posedge CLK) begin
    if(KEY_posedge) begin
        debounce_cnt <= 16'd50000; // 加载定时值
        debounce_lock <= 1'b1;     // 触发锁定
    end else if(debounce_cnt != 0) begin
        debounce_cnt <= debounce_cnt - 1'b1;
    end else begin
        debounce_lock <= 1'b0;     // 定时结束,解锁
    end
end

// 仅在未锁定时响应有效上升沿,执行移位
always @(posedge CLK) begin
    if(KEY_posedge && !debounce_lock) begin
        LEDR <= {LEDR[8:0], SW}; // 简化移位逻辑,与原代码功能一致
    end
end

endmodule

逻辑说明:

  1. 先将异步的KEY输入同步到系统时钟域,解决跨时钟域亚稳态问题;
  2. 检测到上升沿后启动1ms计数器,期间通过debounce_lock禁止再次响应;
  3. 定时结束后解锁,等待下一次有效按压,单次抖动只会触发一次移位。

方案2:滞回式稳定电平检测

核心思路是:只有当按钮电平持续稳定一段时间(比如20ms,覆盖绝大多数物理抖动时长)后,才判定为有效按压,再触发移位。同样基于系统时钟实现,属于输入信号的滤波处理。

module TopLevel(
    input        CLK,       // 系统全局时钟,例:50MHz
    input        KEY,       // 带抖动的按钮输入
    input        SW,
    output reg [9:0] LEDR
);

// 异步输入同步
reg KEY_sync1, KEY_sync2;
always @(posedge CLK) begin
    KEY_sync1 <= KEY;
    KEY_sync2 <= KEY_sync1;
end

// 稳定电平计数:跟踪电平持续时间
reg [19:0] stable_cnt;
reg KEY_stable;
always @(posedge CLK) begin
    if(KEY_sync2 != KEY_stable) begin
        stable_cnt <= 20'd1000000; // 50MHz下,1e6个周期=20ms
        KEY_stable <= KEY_sync2;
    end else if(stable_cnt != 0) begin
        stable_cnt <= stable_cnt - 1'b1;
    end
end

// 提取稳定后的有效上升沿
reg KEY_stable_prev;
always @(posedge CLK) begin
    KEY_stable_prev <= KEY_stable;
end
wire KEY_valid_posedge = (stable_cnt == 0) && KEY_stable && ~KEY_stable_prev;

// 执行移位操作
always @(posedge CLK) begin
    if(KEY_valid_posedge) begin
        LEDR <= {LEDR[8:0], SW};
    end
end

endmodule

逻辑说明:

  1. 同步输入后,用计数器跟踪电平变化:一旦电平改变,重置计数器;
  2. 只有当电平持续稳定20ms(计数器归0),才认为是有效电平;
  3. 检测稳定电平的上升沿作为触发信号,彻底过滤抖动毛刺。

两种方案都是纯硬件逻辑实现,完全适配实际FPGA/ASIC环境,不存在仿真延迟的问题,也不需要轮询机制,属于直接处理按钮输入的防抖方案。

内容的提问来源于stack exchange,提问作者Alex Kibbe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:55:55