4. 按键消抖处理
任务说明
机械按键在按下与释放瞬间,触点会因物理弹性产生多次快速通断(通常持续5~20ms),若直接读取GPIO电平,一次按键可能被识别为多次触发。本案例实现基于延时采样的软件消抖:检测到电平变化后,等待10ms再次确认电平状态,仅当两次采样一致时才判定按键状态有效,从而避免误触发。
硬件连接
按键一端接GPIO17,另一端接GND。启用GPIO内部上拉电阻,未按下时读入高电平(1),按下时读入低电平(0)。
代码实现
import RPi.GPIO as GPIO
import time
BUTTON_PIN = 17
DEBOUNCE_MS = 10 # 消抖延时(毫秒)
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def read_debounced(pin, delay_ms=DEBOUNCE_MS):
"""读取按键状态,带软件消抖。
返回:0=按下,1=释放"""
first = GPIO.input(pin)
time.sleep(delay_ms / 1000.0)
second = GPIO.input(pin)
# 两次采样一致才返回,否则返回上一次稳定状态
if first == second:
return first
else:
# 抖动中,返回当前实际电平(保守处理)
return GPIO.input(pin)
try:
last_state = 1 # 初始为释放状态
while True:
current = read_debounced(BUTTON_PIN)
if current != last_state:
if current == 0:
print("按键按下(已消抖)")
else:
print("按键释放(已消抖)")
last_state = current
time.sleep(0.01) # 主循环间隔10ms
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
代码说明
read_debounced()函数是消抖核心:首次读取电平后等待10ms,再读取一次。若两次结果一致,说明电平已稳定,返回该值;若不一致,说明正处于抖动过程,返回当前实际电平。主循环中,仅当消抖后的状态发生变化时才打印事件,从而确保一次物理按键只产生一次“按下”和一次“释放”事件。
运行与验证
sudo python3 debounce.py
运行程序后,快速按下并释放按键多次。判定标准:
- 每次物理按下,终端只打印一行
按键按下(已消抖); - 每次物理释放,终端只打印一行
按键释放(已消抖); - 快速连续按键时,不会出现一次按下对应多行输出,也不会出现无操作时的随机触发。
若观察到一次按键产生多次输出,可适当增大DEBOUNCE_MS至15或20ms;若按键响应明显迟钝,可减小至5ms。