【传播知识手有余香🌹】转发此文到朋友圈赠送于振南老师知识视频合集哦!
你有没有想过一个问题:按一下按键,程序里读到的是十几次通断。不是程序错了,是按键在抖。机械按键的触点在闭合的瞬间,会弹跳。接触 → 弹开 → 接触 → 弹开……这个过程持续10ms到20ms,频率约2kHz。如果你直接读引脚电平,会读到0、1、0、1、0、1……按一下,CPU以为你按了十下。
那个“机械”的宿命,按键不是理想开关。它是机械结构——金属触点碰撞,必然弹跳。就像把钢球扔到地上,它会弹几下才停。这是物理规律,不是质量问题。那个“电容”的硬件消抖,怎么消除抖动?硬件方法:在按键两端并联一个电容。电容的特性:两端电压不能突变。触点弹开时,电容里的电荷维持电压。触点接触时,电容放电。引脚上的电压被电容“平滑”了,抖动被滤除。这就是“硬件消抖”——用模拟电路解决数字问题。那个“延时”的软件消抖,软件方法:检测到低电平后,等20ms,再读一次。如果还是低电平 → 真的按下了。如果是高电平 → 刚才只是抖动。
if(GPIO_ReadPin(KEY_PIN) == 0) {
HAL_Delay(20);
if(GPIO_ReadPin(KEY_PIN) == 0) {
// 真的按下了
}
}
这就是“软件消抖”——用时间换可靠。
那个“20ms”的经验值为什么是20ms?大多数机械按键的抖动时间在5ms到15ms。留点余量,取20ms,基本覆盖所有情况。太短,可能没躲过抖动。太长,用户觉得“这按键好迟钝”。20ms,是工程师在“可靠”和“体验”之间的平衡。那个“RC滤波”的电路,更专业的硬件消抖:RC低通滤波器。一个电阻+一个电容,截止频率低于2kHz。抖动的信号被滤除,只剩稳定的电平。
用模拟电路,做数字信号的“清洁工”。那个“施密特”的整形。GPIO输入引脚内部,通常有施密特触发器。它有迟滞特性——输入电压高于阈值才判1,低于阈值才判0。中间的抖动,被“消化”了。这是硬件级别的“抗抖”。那个“状态机”的进阶,软件消抖的进阶:状态机。
- 状态0:等待按键按下
- 状态1:检测到低电平,进入消抖等待
- 状态2:20ms后确认按下,执行动作
- 状态3:等待按键释放
比简单延时更高效,不阻塞CPU。这个故事给我们的启示为什么按键会“抖”?因为机械接触不是理想的。你按下去的那一下,金属触点之间经历了多次碰撞。这不是设计缺陷,是物理世界的“天性”。我们无法消除它,只能“适应”它。硬件消抖:用电容吸收能量。软件消抖:用延时等待稳定。等20ms,世界就安静了。写在最后下次你写按键程序,别以为“读到低电平就是按下”。想想那个弹跳的触点。想想那个并联的电容。想想那20ms的等待。不是按键“坏了”,是物理世界“不理想”。而我们工程师的工作,就是在“不理想”中,找到“可靠”的方案。
(本文灵感源于于振南《新概念ARM32单片机》教程中对按键消抖的深刻讲解,感谢作者将物理与数字的冲突讲得如此通透。)
如果您觉得这个故事对您有启发,欢迎点赞、转发,让更多工程师看到这个藏在20ms背后的“等待哲学”。关注我,一起探索嵌入式世界里那些“等一等就好”的硬核真相。