按键抖动现象分析
机械按键的物理结构
机械按键由弹性触点、弹簧机构和导电材料组成。当按下或释放按键时,弹簧的弹性势能使触点产生振动,导致触点不能立即稳定接触或断开。
电平跳变的表现形式
抖动表现为短时间内电平的多次跳变。FPGA的高速时钟(通常50MHz)会将这些跳变识别为多次独立的按键操作,导致系统行为异常。
抖动带来的问题
计数器误触发:单次按键导致计数器多次增加
状态机异常:状态跳转不符合预期
多次识别:一次操作被识别为多次


工程结论:抖动是机械按键的固有特性,无法避免,必须通过硬件或软件方法进行消抖处理。
消抖原理
消抖核心思想
等待信号稳定
连续稳定计数
输出有效信号
消抖不是性能优化手段,而是确保系统正确运行的必需措施。任何使用机械按键的 FPGA 设计都必须包含消抖模块,否则系统无法稳定工作。
消抖工作流程

稳定计数器的工作原理
信号相同:计数器递增
当 key_in == key_last 时,说明信号保持稳定,计数器 stable_cnt 加1。
信号不同:计数器清零
当 key_in != key_last 时,说明信号发生变化,计数器 清零,重新开始计数。
达到阈值:输出更新
当 stable_cnt == CNT_MAX 时,认为信号已稳定,更新输出 key_out。

Verilog 核心代码
按键消抖代码
modulekey_debounce ( inputwire clk, // 系统时钟,50MHz inputwire rst_n, // 复位信号,低有效 inputwire key_in, // 原始按键输入 outputreg key_out // 消抖后按键输出 ); // 参数定义:稳定计数器最大值// 50MHz时钟,20ms消抖时间 = 1_000_000个时钟周期 parameter CNT_MAX = 20'd1_000_000; // 内部信号定义reg [19:0] stable_cnt; // 稳定计数器,最大1_000_000 reg key_last; // 上一次按键状态//================================================== // 消抖核心逻辑//================================================== always @(posedge clk or negedge rst_n) beginif (!rst_n) begin stable_cnt <= 20'd0; key_last <= 1'b1; // 按键默认高电平(上拉) key_out <= 1'b1; endelsebegin// 保存当前按键状态 key_last <= key_in; // 稳定计数器逻辑if (key_in == key_last) stable_cnt <= stable_cnt + 1'b1; else stable_cnt <= 20'd0; // 输出更新逻辑if (stable_cnt == CNT_MAX) key_out <= key_in; endendendmodule
代码详细解析欢迎关注 ALINX 黑金云课堂课程直播回放
按键仿真波形分析

key_in 分析
多次跳变: 在T0-T1期间,信号在高低电平之间快速跳变约50次
抖动时长: 典型抖动持续时间约10ms
key_out 分析
只变化一次: 在T2时刻,信号稳定后才更新输出
完全消抖: 消除了所有抖动带来的虚假触发
验证结论
消抖正确: 成功消除抖动
响应及时: 稳定后立即输出
单次触发: 每次按键只触发一次
实验扩展建议
调整CNT_MAX值
尝试不同的稳定阈值(5ms、10ms、20ms、50ms),观察消抖效果和响应速度的平衡
添加边沿检测
在消抖模块后添加边沿检测逻辑,实现单次触发功能,避免长按时的连续触发
实际项目应用
将消抖模块应用于按键控制LED、按键计数器、按键状态机等实际项目中
更多细节欢迎关注我们黑金云课堂全年免费直播课, 黑金云课堂四月直播日历 我们将在每周二、三、四,同步推进 Verilog开发、Vitis开发、Linux开发三大系列,带你从零开始,稳扎稳打掌握 FPGA 开发全流程!
| 系列 | 内容定位 |
|---|---|
| Verilog开发 | 硬件描述语言基础、逻辑设计、仿真调试 |
| Vitis开发 | Zynq软硬件协同、外设驱动、网络协议栈 |
| Linux开发 | 嵌入式Linux系统移植、驱动编写、应用开发 |
301