[英]Using an IF statement in Python inside of a main() function
我正在尝试创建一个程序,该程序检测连接到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)
运行代码并按下按钮时收到错误:
追溯(最近一次通话最新):文件“ /home/pi/Downloads/GPIO_test_06.py”,在butTwo_callback中check21all_depressed()文件“ /home/pi/Downloads/GPIO_test_06.py”,行29,在check_all_depressed中,如果butOne和butTwo和butThree:NameError:未定义名称“ butOne”
您的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
一次又一次。
最后,您已选择创建一个运行主程序的主函数。 最好在其中包含函数定义上方的所有代码。 毕竟,它们都是主程序的一部分,并且只能运行一次。 这样,您还可以避免意外地在函数内部使用全局变量,这可能导致意外的行为(但在技术上正确)。
回答:
删除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程序遵循事件发生的顺序,即从上到下,回调发生在此流程之外。
从根本上讲,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
的调用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
的嵌套函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.