-1

I have 4 buttons connected to my Raspberry Pi that call the same function when pressed. I'm using GPIO.add_event_detect to connect the buttons to the callback function. When one button press executes the callback function (which takes a few seconds to complete), I want to ignore all other button presses until the function finished. Is there a good "pythonic" way to do this? Due to compatibility problems with other modules that I use in my final program, I cannot use gpiozero's Button class, which does not have this issue. This is my example code:

import RPi.GPIO as GPIO
from time import sleep
from signal import pause
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
try:
    def handleBtnPress(pinNum):   
            switcher = {
                5: "Button 1 pressed",
                6: "Button 2 pressed",
                13: "Button 3 pressed",
                19: "Button 4 pressed"
            }
            print(switcher.get(pinNum, "Error, pin number for button press not defined"))
            sleep(2)
            print("2sec passed, work is done")


    GPIO.setup(5, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(6, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(13, GPIO.IN, GPIO.PUD_UP)
    GPIO.setup(19, GPIO.IN, GPIO.PUD_UP)

    GPIO.add_event_detect(5, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(6, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(13, GPIO.FALLING, handleBtnPress,bouncetime=300)
    GPIO.add_event_detect(19, GPIO.FALLING, handleBtnPress,bouncetime=300)

    pause()
except KeyboardInterrupt:
    GPIO.cleanup()
    raise SystemExit

However with this code, when I press other buttons while the callback function runs, the presses are not ignored but also execute the callback function one after the other.

My idea that I have so far is to check at the beginning of the callback function whether the button that triggered it, is still pressed. The input should then still be 0. This filters button presses that are performed while the callback function is running. While this seems to work, I wonder if there is a better way to do this?

def handleBtnPress(pinNum):
            if GPIO.input(pinNum)==1:  
                print("Pressing BCM button %d ignored"%pinNum)
                return
            switcher = {
                5: "Button 1 pressed",
                6: "Button 2 pressed",
                13: "Button 3 pressed",
                19: "Button 4 pressed"
            }
            print(switcher.get(pinNum, "Error, pin number for button press not defined"))
            sleep(2)
            print("2sec passed, work is done")
1
  • The design is wrong for what you want to do. Treat callbacks as interrupts. Do the minimum amount of work needed to record state and return. Don't sleep! Don't do a time consuming job! Set a flag to tell your main program to do those things.
    – joan
    Mar 1 at 9:27
0

This is not really a Pi specific question but programming. Nonetheless checking buttons in callback is error prone.

The traditional approach is to set flags until the callback finishes.

NOTE there should be no reason you can't use gpiozero as this is (normally) just a wrapper around RPi.GPIO.

I note you are still calling SystemExit. This is not normal and poor practice as you were previously advised. Indeed it is unnecessary.

2
  • -So if I understand it correctly: If I press all 4 buttons simultaneously, they would all be randomly queued and the callback function would be executed in a new thread 4x sequentially. Could you maybe give an example of how such a flag would look like? - In my previous question, I was not advised to mix gpiozero and RPi.GPIO. I was getting problems because GPIO.cleanup() which is called by some modules I use is clashing with gpiozeros automatic cleanup - As for raising SystemExit, I won't do it again.
    – J.P.
    Feb 28 at 23:21
  • @J.P. If I was implementing something I would use separate callbacks for each button and only execute if flag was clear. It may be possible to write code in a single callback, but more complex. Each callback could call a common function (if relevant) .
    – Milliways
    Mar 1 at 2:21
0

i think you need to call GPIO.cleanup() not only by keyboardinterrupt but always;

`except KeyboardInterrupt:
     print ('Ctrl + C Pressed')
 finally:
     GPIO.cleanup()`

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.