簡體   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