我是初级python开发人员,主要是后台Django。我工作中的第一项任务是在树莓派上编写程序,将状态设置为LOW
,5秒后设置为HIGH
。
似乎不是问题,但是。。。。我认为等待5秒更改为HIGH
的正确方式不是通过time.sleep()
,而是通过threading.Timer
(我在stackoverflow上找到了它(。。。它将通过网络套接字连接,所以我认为一个线程必须侦听,另一个线程则必须更改状态
我的问题是一半是蟒蛇,一半是树人。。。这是我的代码:
import RPi.GPIO as GPIO
from threading import Timer
from time import sleep
pin = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
def set_high():
GPIO.output(pin, GPIO.HIGH)
def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
t = Timer(5, set_high(GPIO))
t.start()
web_socket_loop()
GPIO.cleanup()
当我运行这个代码时,状态正在改变,但几秒钟后我也得到了一个错误:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
TypeError: 'NoneType' object is not callable
我在堆栈上发现我必须这样做:(但它不能正常工作(:;/
t = Timer(5, set_high, args=[GPIO])
它确实修复了关于NoneType的错误。。。但我又犯了一个错误:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
我可能知道这个错误的原因,但不知道如何处理。我认为在另一个线程上RPi.GPIO
没有配置(GPIO.setmode(GPIO.BCM), GPIO.setup(pin, GPIO.OUT))
这就是为什么我将GPIO
作为变量传递给函数set_high(GPIO)
,而在另一个线程上没有它,它认为RPi
没有配置。。。传递这个变量很酷,但是。。。我收到NoneType
错误…;/
当我用Timer(5, set_high, args=[GPIO])
尝试第二种方法时,NoneType
错误消失,但发生了另一个错误(RuntimeError with info about pin setup
(。。。这与我没有将GPIO
传递给这样的函数时得到的错误相同
def set_high(#i_dont_pass_GPIO):
#things
pass
将GPIO变量传递给另一个线程的正确方法是什么?以便它能正确地识别这个变量并将引脚22设置为高电平。
或者你建议换一种方式试试?也许睡眠更好?但它将通过网络套接字连接,所以我认为一个必须倾听,另一个必须改变状态?
我感谢任何帮助!!
您的第一个问题和第三个问题实际上并不相关,因为您已经正确地解决了它们。
当您调用Timer(5, set_high(GPIO))
时,它现在调用set_high(GPIO)
,并传递它返回的任何内容作为Timer
要调用的目标函数。由于它在5秒后返回None
,因此Timer
会尝试将None
作为函数调用,从而生成TypeError
。
修复正是你已经做的:
Timer(5, set_high, [GPIO])
现在,一旦你解决了这个问题,就要仔细思考你所要求的控制流程。
首先,你要这样做:
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
然后你调用web_socket_loop
,它会这样做:
GPIO.output(pin, GPIO.LOW)
然后它创建并启动一个Timer
,然后返回。你这样做:
GPIO.cleanup()
然后,5秒后,计时器关闭并调用set_high
函数,该函数执行以下操作:
GPIO.output(pin, GPIO.HIGH)
清理GPIO后,无法将引脚设置为高电平。
错误消息有点误导:
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
这是因为清理后的状态与初始化前的状态相同,所以它假设您的问题是还没有通过调用setmode
来初始化。
你怎么能解决这个问题?你的主线不应该试图清理,直到你完成。
通常,主线程还有其他事情要做。这就是为什么要使用Timer
、Thread
或其他形式的并发。但当你这样做的时候,你需要给你的主线程一些方法来等待后台工作完成,或者你需要找到一些方法来把事情链接起来,这样cleanup
只在最后一个线程使用GPIO完成之后发生。
当你添加处理通过websocket进行通信的代码时,你需要做其中一件事。但是,如果不知道如何组织代码,就不可能向您展示您应该做什么。
同时,除了等待5秒之外,您真的没有其他事情可做,所以您不需要任何并发;仅sleep
:
def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
time.sleep(5)
set_high(GPIO)