繁体   English   中英

在main()函数内部的Python中使用IF语句

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM