树莓派(Python):按键触发LED闪烁循环脚本异常问题
万圣节电椅LED闪烁程序修复(松开按键无法停止问题)
问题描述
编写模拟闪电/电流闪烁效果的LED控制程序,用于万圣节电椅道具,预期功能:
- 初始LED关闭
- 按下按键启动闪烁循环
- 松开按键时关闭LED并退出循环,等待再次触发
当前按下按键闪烁正常,但松开后无法关闭LED并退出循环。设备为Raspberry Pi 3B,Python3开发,原代码如下:
import RPi.GPIO as GPIO import time import random import math bulb = 18 button = 23 pwms = [] intensity = 1.0 def setupGPIO(): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(bulb, GPIO.OUT, initial=GPIO.LOW) GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP) # GPIO.add_event_detect(button, GPIO.BOTH, callback=handleButtonPress, bouncetime=300) def handleButtonPress(): p = GPIO.PWM(bulb, 300) p.start(0) while True: GPIO.wait_for_edge(button, GPIO.FALLING) p.ChangeDutyCycle(random.randint(1, 44) * math.pow(intensity, 2) if intensity > 0 else 0) rand_flicker_sleep() while GPIO.input(button) == GPIO.LOW: print("button is being pressed") def rand_flicker_sleep(): time.sleep(random.randint(3, 10) / 100.0) def flicker_it(_): global intensity intensity = min(0, 1.0) def main(): try: setupGPIO() handleButtonPress() except KeyboardInterrupt: pass finally: for p in pwms: p.stop() GPIO.cleanup() if __name__ == '__main__': main()
问题分析
- 按键检测逻辑错误:原代码只等待按键按下(FALLING边缘),未处理松开(RISING边缘)的情况,导致松开后循环无法终止
- PWM对象未管理:创建的PWM对象
p未加入pwms列表,finally块无法停止它,可能导致LED保持点亮 - 内部循环冗余:
while GPIO.input(button) == GPIO.LOW会阻塞程序,无法及时检测按键松开 - 无用代码干扰:
flicker_it函数逻辑错误且未被调用,属于无效代码
修复后的代码
import RPi.GPIO as GPIO import time import random import math bulb = 18 button = 23 pwms = [] intensity = 1.0 def setupGPIO(): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(bulb, GPIO.OUT, initial=GPIO.LOW) GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP) def handleButtonPress(): while True: # 等待按键按下 GPIO.wait_for_edge(button, GPIO.FALLING) # 创建PWM对象并加入管理列表 p = GPIO.PWM(bulb, 300) p.start(0) pwms.append(p) # 按键按下时持续闪烁 while GPIO.input(button) == GPIO.LOW: # 随机调整亮度模拟闪电效果 duty_cycle = random.randint(1, 44) * math.pow(intensity, 2) if intensity > 0 else 0 p.ChangeDutyCycle(duty_cycle) rand_flicker_sleep() # 松开按键后停止PWM,关闭LED p.stop() pwms.remove(p) GPIO.output(bulb, GPIO.LOW) def rand_flicker_sleep(): time.sleep(random.randint(3, 10) / 100.0) def main(): try: setupGPIO() handleButtonPress() except KeyboardInterrupt: pass finally: for p in pwms: p.stop() GPIO.cleanup() if __name__ == '__main__': main()
关键修改点
- 调整循环结构:外层循环等待按键按下,内层循环在按键保持按下时持续闪烁,一旦检测到按键松开,立即停止PWM并关闭LED
- 正确管理PWM对象:创建PWM后加入
pwms列表,停止后从列表移除,确保程序退出时能彻底清理 - 移除无用代码:删除未使用且逻辑错误的
flicker_it函数,简化代码结构 - 实时检测按键状态:内层循环通过
GPIO.input实时判断按键是否保持按下,避免阻塞导致无法响应松开动作
内容的提问来源于stack exchange,提问作者Matt Facer
相关产品推荐
相关产品推荐

