你正在创建很多线程,因为你的
blink()
每次调用时都会创建一个新线程,而旧线程不会停止。
我认为线程有几个选项:
-
只创建一次线程-例如在
__init__()
-它以闪烁的时间间隔(即大部分时间处于睡眠状态)连续运行,读取实例变量并相应地设置LED。要更改led状态,请
闪烁()
,
on()
和
off()
-
在blink例程中,如果线程已经在运行,则不要创建新线程,或者停止旧线程(等待它完成),然后启动一个新线程。
你需要处理的事情是,你希望自己的行为是:
-
如果led熄灭,则只要
on()
或
闪烁()
-
如果led闪烁
闪烁()
再次调用。闪烁开/关序列不受干扰
-
如果闪烁并且
关闭()
如果已经开始运行到完成,则称为“我希望打开循环”,即不应立即关闭led,因为这可能是一个很短的闪光,看起来很奇怪。
创建一个新线程的关键是等待旧线程完成,而只需在一个线程中创建一次就可以了
__初始化()
并使其连续运行。当led亮起或熄灭时,时间段缩短(至数值
FAST_CYCLE
)因此,当led关闭或打开时,它会快速反应,因为
sleep()
是一段很短的时间。
关于代码的其他几点:
-
Thread
-您正在中创建一个新线程
pin=...
-
如果在编写代码时添加注释,通常会使阅读代码时更容易理解发生了什么。
-
self.pin = threading.Thread
不
pin = threading.Thread
reset()
您可以使用
join()
在继续之前确保它已退出
-
由于闪烁时间段可以更改,并且线程必须使用最新的值,因此每次都使用self读取它们,而不是将它们作为参数传递给
__blink_pin()
例程,如果这样做,您也可以使用self来获取pin_stop信号量。
类似这样(未经测试):
import RPi.GPIO as GPIO
import time
import threading
from threading import Thread
class Led(object):
LED_OFF = 0
LED_ON = 1
LED_FLASHING = 2
# the short time sleep to use when the led is on or off to ensure the led responds quickly to changes to blinking
FAST_CYCLE = 0.05
def __init__(self, led_pin):
# create the semaphore used to make thread exit
self.pin_stop = threading.Event()
# the pin for the LED
self.__led_pin = led_pin
# initialise the pin and turn the led off
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.__led_pin, GPIO.OUT)
# the mode for the led - off/on/flashing
self.__ledmode = Led.LED_OFF
# make sure the LED is off (this also initialises the times for the thread)
self.off()
# create the thread, keep a reference to it for when we need to exit
self.__thread = threading.Thread(name='ledblink',target=self.__blink_pin)
# start the thread
self.__thread.start()
def blink(self, time_on=0.050, time_off=1):
# blinking will start at the next first period
# because turning the led on now might look funny because we don't know
# when the next first period will start - the blink routine does all the
# timing so that will 'just work'
self.__ledmode = Led.LED_FLASHING
self.__time_on = time_on
self.__time_off = time_off
def off(self):
self.__ledmode = LED_OFF
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED off immediately, might make for a short flicker on if was blinking
def on(self):
self.__ledmode = LED_ON
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED on immediately, might make for a short flicker off if was blinking
def reset(self):
# set the semaphore so the thread will exit after sleep has completed
self.pin_stop.set()
# wait for the thread to exit
self.__thread.join()
# now clean up the GPIO
GPIO.cleanup()
############################################################################
# below here are private methods
def __turnledon(self, pin):
GPIO.output(pin, GPIO.LOW)
def __turnledoff(self, pin):
GPIO.output(pin, GPIO.HIGH)
# this does all the work
# If blinking, there are two sleeps in each loop
# if on or off, there is only one sleep to ensure quick response to blink()
def __blink_pin(self):
while not self.pin_stop.is_set():
# the first period is when the LED will be on if blinking
if self.__ledmode == Led.LED_ON or self.__ledmode == Led.LED_FLASHING:
self.__turnledon()
else:
self.__turnledoff()
# this is the first sleep - the 'on' time when blinking
time.sleep(self.__time_on)
# only if blinking, turn led off and do a second sleep for the off time
if self.__ledmode == Led.LED_FLASHING:
self.__turnledoff()
# do an extra check that the stop semaphore hasn't been set before the off-time sleep
if not self.pin_stop.is_set():
# this is the second sleep - off time when blinking
time.sleep(self.__time_off)