我正在尝试创建一个程序,该程序检测连接到Raspberry Pi上GPIO引脚的三个不同按钮的状态,并且一旦三个按钮都变为高电平,便采取措施。现在,我所有的按钮都通过回调函数单独工作,但是'main'函数内部的if
语句似乎没有运行。
这是我第一次使用Python,所以如果您在代码结构中发现任何其他逻辑错误,请告诉我。仍在尝试摆脱困境,尤其是GPIO库功能。预先感谢,我已经在下面发布了我的代码。
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
butOne = False
butTwo = False
butThree = False
# Setup button inputs
GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(19, GPIO.RISING)
GPIO.add_event_detect(20, GPIO.RISING)
GPIO.add_event_detect(21, GPIO.RISING)
def butOne_callback(channel1):
print("Button 1 /n")
butOne = True
def butTwo_callback(channel2):
print("Button 2 /n")
butTwo = True
def butThree_callback(channel3):
print("Button 3 /n")
butThree = True
def main():
GPIO.add_event_callback(19, butOne_callback)
GPIO.add_event_callback(20, butTwo_callback)
GPIO.add_event_callback(21, butThree_callback)
if (butOne == True) and (butTwo == True) and (butThree == True):
print("All Depressed")
main()
更新的代码,根据Aditya Shankar的建议:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(19, GPIO.RISING)
GPIO.add_event_detect(20, GPIO.RISING)
GPIO.add_event_detect(21, GPIO.RISING)
def butOne_callback(channel1):
print("Button 1 /n")
butOne = True
check_all_depressed()
def butTwo_callback(channel2):
print("Button 2 /n")
butTwo = True
check_all_depressed()
def butThree_callback(channel3):
print("Button 3 /n")
butThree = True
check_all_depressed()
def check_all_depressed():
if butOne and butTwo and butThree:
print("All Depressed")
GPIO.add_event_callback(19, butOne_callback)
GPIO.add_event_callback(20, butTwo_callback)
GPIO.add_event_callback(21, butThree_callback)
运行代码并按下按钮时收到错误:
回溯(最近通话最近): 在butTwo_callback中,文件“ /home/pi/Downloads/GPIO_test_06.py”,第21行 check_all_depressed() 文件“ /home/pi/Downloads/GPIO_test_06.py”,第29行,在check_all_depressed中 如果butOne和butTwo和butThree: NameError:名称“ butOne”未定义
答案 0 :(得分:1)
您的if
语句仅运行一次-首次启动脚本时立即运行。到那时,还没有按过按钮,因此似乎不起作用。
一种解决方法是将语句以较小的延迟放入循环中并测试该循环中的条件。像这样:
import time
while not condition:
time.sleep(1)
另一个问题是风格之一。您可以编写条件:
(butOne == True) and (butTwo == True) and (butThree == True)
简单地为:
butOne and butTwo and butThree
因为它们都是布尔值开头。在Python中,您甚至可以编写:
all([butOne, butTwo, butThree])
这并不短,但是如果您有更多条件,则可以避免一次又一次地重复and
。
最后,您已选择创建一个运行主程序的主函数。最好在其中包含函数定义上方的所有代码。毕竟,它们都是主程序的一部分,并且只能运行一次。这样,您还可以避免意外地在函数内部使用全局变量,否则可能导致意外的行为(但在技术上正确)。
答案 1 :(得分:1)
答案:
删除if条件
添加一个函数check_all_depressed()
将函数添加到所有三个按钮回调的末尾,例如
def butOne_callback(channel1):
global butOne
print("Button 1 /n")
butOne = True
check_all_depressed()
check_all_depressed看起来像这样-
def check_all_depressed():
if butOne and butTwo and butThree:
print("All Depressed")
说明: 因此,有回调,并且有常规程序流程。 基本上python程序遵循事件发生的顺序,即从上到下,回调发生在此流程之外。
答案 2 :(得分:0)
从根本上讲,GPIO包支持事件的方式是通过等待所选通道上的上升沿和下降沿。无论在主线程中发生什么,这都是在后台线程中完成的。您的if
语句在配置按钮之后立即运行一次,然后主线程结束。
您可以实施两种类型的解决方案。一种是强制主线程等待状态更改。另一种是响应回调中的状态更改。
强制main
等待:
import RPi.GPIO as GPIO
channels = [19, 20, 21]
def main():
GPIO.setmode(GPIO.BCM)
for chan in channels:
GPIO.setup(chan, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
for chan in channels:
GPIO.wait_for_edge(chan, GPIO.RISING)
# Now all your buttons have been pressed
这可能是更有效的方法。最少的设置,没有显式的多线程。
另一种方法是在单独的线程中侦听输入。您可以像配置add_event_callback
一样配置回调以响应上升沿,但是请记住,该函数主要用于设置多个回调。一种更简洁的方法是将对add_event_detect
的调用移至main
并将其与add_event_callback
合并:
GPIO.add_event_detect(chan, GPIO.RISING, callback=...)
从编程的角度来看,我会使用这样的事实,即所有通道都几乎相同,并且仅定义一个回调。实际上,在您的设置中,最重要的是频道号和频道名称:
import RPi.GPIO as GPIO
channels = {19: 1, 20: 2, 21: 3}
class callback:
def __init__(self):
self.pressed = dict.fromkeys(channels, False)
def __call__(self, channel):
print(f'Button {channels[channel]} pressed')
self.pressed[channel] = True
if sum(self.pressed.values()) == len(self.pressed):
# All buttons have been pressed
def main():
GPIO.setmode(GPIO.BCM)
cb = callback()
for chan in channels:
GPIO.setup(chan, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(chan, GPIO.RISING, callback=cb)
请注意,在两个示例中,除了通道配置之外,我都避免了全局状态。第二种方法将回调设置为可调用类的实例。另一种方法是将回调定义为main
中的嵌套函数。