You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派(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()

问题分析

  1. 按键检测逻辑错误:原代码只等待按键按下(FALLING边缘),未处理松开(RISING边缘)的情况,导致松开后循环无法终止
  2. PWM对象未管理:创建的PWM对象p未加入pwms列表,finally块无法停止它,可能导致LED保持点亮
  3. 内部循环冗余:while GPIO.input(button) == GPIO.LOW会阻塞程序,无法及时检测按键松开
  4. 无用代码干扰: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:17:40