Использование оператора IF в Python внутри функции main () - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь создать программу, которая обнаруживает состояние трех разных кнопок, подключенных к выводам GPIO на Raspberry Pi, и как только все три раза ВЫСОКЫ раз, выполняется действие.Прямо сейчас у меня все кнопки работают индивидуально через функции обратного вызова, но оператор if внутри функции 'main', похоже, не выполняется.

Я впервые использую 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()

ОБНОВЛЕННЫЙ КОД, согласно советам Адитьи Шанкара:

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)

Ошибка полученакогда код запущен и нажата кнопка:

Traceback (последний вызов был последним): файл "/home/pi/Downloads/GPIO_test_06.py", строка 21, в файле butTwo_callback check_all_depressed () File "/home/pi/Downloads/GPIO_test_06.py ", строка 29, в check_all_depressed, если butOne и butTwo и butThree: NameError: имя 'butOne' не определено

Ответы [ 3 ]

0 голосов
/ 05 февраля 2019

Ответ:

удалить условие 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 следуют порядку событий возникновения, то есть сверху вниз, обратные вызовы происходят вне этого потока.

0 голосов
/ 05 февраля 2019

По сути, пакет 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.

0 голосов
/ 05 февраля 2019

Ваш оператор 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 снова и снова.

Наконец, вы 'Мы решили создать основную функцию, которая запускает основную программу.Вероятно, хорошей идеей будет включить весь код над определениями ваших функций.В конце концов, это все часть вашей основной программы, и она предназначена для запуска только один раз.Таким образом, вы также избегаете случайного использования глобальных переменных внутри функций, что может привести к неожиданному (но технически правильному) поведению.

...