简体   繁体   English

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

[英]Using an IF statement in Python inside of a main() function

I am trying to create a program that detects the state of three different buttons, connected to GPIO pins on a Raspberry Pi, and once all three have been HIGH once, an action is taken. 我正在尝试创建一个程序,该程序检测连接到Raspberry Pi上GPIO引脚的三个不同按钮的状态,并且一旦三个按钮都变为高电平,便采取措施。 Right now I have all the buttons working individually through callback functions, but the if statement inside the 'main' function does not seem to be running. 现在,我所有的按钮都通过回调函数单独工作,但是'main'函数内部的if语句似乎并未运行。

This is my first time using Python so please let me know if you see any other logical errors in the structure of my code. 这是我第一次使用Python,因此如果您在代码结构中发现任何其他逻辑错误,请告诉我。 Still trying to get a hang of it, especially the GPIO library functions. 仍在尝试摆脱困境,尤其是GPIO库功能。 Thanks in advance, I've posted my code below. 在此先感谢您,我已在下面发布了我的代码。

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()

UPDATED CODE, according to Aditya Shankar's suggestions: 根据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)

Error received when code is run and button is pressed: 运行代码并按下按钮时收到错误:

Traceback (most recent call last): File "/home/pi/Downloads/GPIO_test_06.py", line 21, in butTwo_callback check_all_depressed() File "/home/pi/Downloads/GPIO_test_06.py", line 29, in check_all_depressed if butOne and butTwo and butThree: NameError: name 'butOne' is not defined 追溯(最近一次通话最新):文件“ /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”

Your if statement runs, but only once - immediately when the script is first started. 您的if语句仅运行一次-首次启动脚本时立即运行。 By that time, the buttons haven't been pushed and thus it seems like it's not working. 到那时,还没有按下按钮,因此似乎无法使用。

One way of solving that would be to put the statement in a loop with a small delay and test for the condition in that loop. 解决该问题的一种方法是将语句放入具有较小延迟的循环中,然后测试该循环中的条件。 Something like: 就像是:

import time

while not condition:
    time.sleep(1)

Another issue is one of style. 另一个问题是风格。 You can write your condition: 您可以写下您的条件:

(butOne == True) and (butTwo == True) and (butThree == True)

simply as: 就像这样:

butOne and butTwo and butThree

since they all are boolean values to begin with. 因为它们都是布尔值开头。 In Python, you can even write: 在Python中,您甚至可以编写:

all([butOne, butTwo, butThree])

That's not shorter, but if you had even more conditions, it would avoid repeating and again and again. 这并不短,但如果你有更多的条件,这将避免重复and一次又一次。

Finally, you've chosen to create a main function, that runs the main program. 最后,您已选择创建一个运行主程序的主函数。 It's probably a good idea to include all the code above your function definitions in there as well. 最好在其中包含函数定义上方的所有代码。 After all, it's all part of your main program and it is all meant to run only once. 毕竟,它们都是主程序的一部分,并且只能运行一次。 This way, you also avoid accidentally using global variables inside of functions, which can result in unexpected (but technically correct) behaviour. 这样,您还可以避免意外地在函数内部使用全局变量,这可能导致意外的行为(但在技术上正确)。

Answer: 回答:

remove the if condition 删除if条件

add a function check_all_depressed() 添加一个函数check_all_depressed()

add the function to the end of all three button callbacks, like this 将函数添加到所有三个按钮回调的末尾,如下所示

def butOne_callback(channel1):
    global butOne
    print("Button 1 /n")
    butOne = True
    check_all_depressed()

check_all_depressed looks like this - check_all_depressed看起来像这样-

def check_all_depressed():
    if butOne and butTwo and butThree:
        print("All Depressed")

Explanation: So, there are callbacks and there is general program flow. 说明:因此,存在回调,并且存在常规程序流。 basically python programs follow an order of events of occurrence, that is top to bottom, callbacks occur outside this flow. 基本上python程序遵循事件发生的顺序,即从上到下,回调发生在此流程之外。

Fundamentally, the way the GPIO package supports events is by waiting for rising and falling edges on the channels you select. 从根本上讲,GPIO软件包支持事件的方式是等待所选通道的上升沿和下降沿。 This is done in a background thread, regardless of what happens in the main thread. 无论在主线程中发生什么,这都是在后台线程中完成的。 Your if statement runs once, immediately after the buttons are configured, and then the main thread ends. 您的if语句在配置按钮后立即运行一次,然后主线程结束。

There are two types of solutions you can implement. 您可以实施两种解决方案。 One is to force the main thread to wait for a change in state. 一种是强制主线程等待状态更改。 The other is to respond to changes in state in the callbacks. 另一种是响应回调中的状态更改。

To force main to wait: 强制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

This is probably the more efficient way to do it. 这可能是更有效的方法。 Minimal setup and no explicit multithreading. 最少的设置,没有显式的多线程。

The alternative is to listen for the input in a separate thread. 另一种方法是在单独的线程中监听输入。 You can configure your callbacks to respond to a rising edge as you have done with add_event_callback , but keep in mind that that function is mostly for setting up multiple callbacks. 您可以像配置add_event_callback一样配置回调以响应上升沿,但是请记住,该函数主要用于设置多个回调。 A more succinct way would be to move the calls to add_event_detect into main and combine them with add_event_callback : 一种更简洁的方法是将对add_event_detect的调用add_event_detect main并将其与add_event_callback结合:

GPIO.add_event_detect(chan, GPIO.RISING, callback=...)

From a programmatic point of view, I'd use the fact that all the channels are treated almost the same and only define one callback. 从编程的角度来看,我会使用这样的事实,即所有通道都几乎相同,并且仅定义一个回调。 In fact all that matters in your setup is the channel number and the channel name: 实际上,设置中最重要的是通道号和通道名称:

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)

Notice that in both examples, I have avoided global state aside form the channel configurations. 请注意,在两个示例中,除了通道配置之外,我都避免了全局状态。 The second way sets the callback to an instance of a callable class to do so. 第二种方法将回调设置为可调用类的实例。 The alternative is to define the callback as a nested function in main . 另一种方法是将回调定义为main的嵌套函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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