基于全计数的FPGA按键消抖电路代码仿真异常求助
基于全计数法的FPGA按键消抖电路问题排查与修正
问题背景
依据Volnei所著《Circuit Design with VHDL(第三版)》中的全计数法实现FPGA按键消抖电路,核心优化点为扩展计数器位宽,利用最高位(MSB)替代比较器以节省逻辑资源:
- 以50MHz时钟、20ms消抖时间为例,需计数次数 $S = 50MHz * 20ms = 10^6$,原计数器位宽 $N = log_2(S) ≈ 20$;扩展后通过检测MSB翻转判断计时完成,无需额外比较器。
测试书中示例代码时未得到预期消抖效果,现附上相关代码、当前仿真图,寻求修正方案以达成目标仿真效果。
附上代码
消抖电路VHDL代码
-- 此处粘贴原消抖电路代码
测试平台(Testbench)代码
-- 此处粘贴原测试平台代码
当前仿真图
注:当前仿真表现为[描述具体问题,如:按键抖动时输出随抖动变化、计时未完成时输出提前更新、MSB未按预期翻转等]
问题排查与修正建议
1. 输入按键同步处理缺失
FPGA输入按键属于异步信号,未经过同步处理易引入亚稳态,导致计数器逻辑异常。需在消抖前增加两级触发器同步:
signal key_sync : std_logic_vector(1 downto 0); process(clk) begin if rising_edge(clk) then key_sync <= key_sync(0) & key_in; end if; end process;
后续消抖逻辑基于同步后的key_sync(1)处理。
2. 计数器复位逻辑错误
当按键状态变化(抖动)时,需立即复位计数器重新计时。需检查复位条件是否仅在按键状态跳变时触发:
signal cnt : std_logic_vector(20 downto 0); -- 扩展为21位,MSB为第20位 process(clk, rst_n) begin if rst_n = '0' then cnt <= (others => '0'); elsif rising_edge(clk) then -- 按键状态变化时复位计数器 if key_sync(1) /= key_sync(0) then cnt <= (others => '0'); else cnt <= cnt + 1; end if; end if; end process;
3. MSB判断与输出更新逻辑错误
需确保仅当MSB翻转(计时完成)且按键状态稳定时,才更新输出:
signal key_debounced : std_logic; process(clk, rst_n) begin if rst_n = '0' then key_debounced <= '0'; elsif rising_edge(clk) then -- 当计数器MSB为1时,说明计时完成,锁定当前按键状态 if cnt(20) = '1' then key_debounced <= key_sync(1); end if; end if; end process;
验证:50MHz时钟下,21位计数器计数到$2{20}=1,048,576$时MSB翻转,略大于106,满足20ms+的消抖时间要求,符合设计预期
4. 测试平台激励不足
确保测试平台生成包含抖动的按键波形,模拟真实按键输入:
-- 示例:生成带抖动的按键信号 process begin key_in <= '1'; wait for 100ns; -- 模拟抖动:多次跳变 for i in 1 to 10 loop key_in <= not key_in; wait for 50ns; end loop; key_in <= '0'; wait for 100ms; -- 再次模拟抖动释放 for i in 1 to 8 loop key_in <= not key_in; wait for 60ns; end loop; key_in <= '1'; wait; end process;
内容的提问来源于stack exchange,提问作者Ahmad Asmndr
相关产品推荐
相关产品推荐

