0

In Python, Does anyone know if there is a way to have a multi-input interrupt? I have a 4 button input and I want to be able to have a special condition to reset. I know interrupts are written like: GPIO.add_event_detect(##, GPIO.FALLING, callback=my_callback, bouncetime=300)

OR

try:  
GPIO.wait_for_edge(##, GPIO.RISING)

So if I want: button 1 = interrupt1 button 2 = interrupt2 button 3 = interrupt3 button 4 = interrupt4

how do I make button 3 & button 4 = interrupt 5

OR

if button 4 is held for 10seconds = interrupt 5

1
  • I don't use python, but the functions that fire for GPIO interrupts are callbacks or event handlers; what you are talking about WRT "button 4 is held for 10 seconds" isn't in a strict sense an interrupt (that refers to things that are explicitly about hardware triggers), but you can accomplish something functionally identical in code. It implies the use of multiple threads, but there may be a simpler way via an event module that keeps that under the hood for you. Some similar languages provide timer based callbacks, which could be used to accomplish that example.
    – goldilocks
    Sep 29 '16 at 19:29
1

My recommendation is to build 8 interrupt functions, two for each button, one for GPIO.RISING and one for GPIO.FALLING. You also keep a binary variable (e.g. int) which has bit 0 = button 1 (i.e. mask 0b00000001), bit 1 = button 2 (i.e. mask 0b00000010), ... , bit 3 = button 4 (i.e. mask 0b00001000). Upon entering the RISE callback for button 1, it sets its corresponding bit, and the FALL callback for the button sets it back to 0.

In each RISE callback function you then test with a bit mask to see if a desired combination of buttons (using a simple mask, e.g. 0b00001100 for button 3&4) has been pressed, and you trigger the corresponding interrupt function.

Something like this:

def button1RISE():
    global buttonRegister
    buttonRegister = buttonRegister | 0b00000001

    if buttonRegister & 0b00000011: #test for button 1 & 2 pressed
       .....

def button1FALL():
    global buttonRegister
    buttonRegister = buttonRegister & 0b11111110

For the timer related question, I would have the RISE callback code create a timer thread (with the code to be executed after the time interval in that thread), and the FALL callback code cancel the timer thread.

1

Here's how I would code this with pigpio.

The callback function is a bit clunky, but given your requirements I don't see how to simplify it that much.

#!/usr/bin/env python

import time

import pigpio

A=4
B=5
C=6
D=7

GPIO=[A, B, C, D]

levels=[] # Store levels of buttons A, B, C, and D.

cbs=[] # Store callback handles for buttons A, B, C, and D.

def cbfunc(gpio, level, tick):
   global levels
   if   gpio == A:
      levels[0] = level
      if level == 1:
         print("interrupt 1")
   elif gpio == B:
      levels[1] = level
      if level == 1:
         print("interrupt 2")
   elif gpio == C:
      levels[2] = level
      if level == 1:
         if levels[3] == 0:
            print("interrupt 3")
         else:
            print("interrupt 5")
   elif gpio == D:
      timeout = 0
      if level == pigpio.TIMEOUT:
         print("button D pressed for 10 seconds")
      elif level == 1:
         if levels[2] == 0:
            print("interrupt 4")
            timeout=10000 # 10 seconds
         else:
            print("interrupt 5")
      pi.set_watchdog(D, timeout) # Cancel or create timeout.
      levels[3] = level

   print(levels)

pi = pigpio.pi()

if not pi.connected:
   exit()

for g in GPIO:
   levels.append(pi.read(g))
   cbs.append(pi.callback(g, pigpio.EITHER_EDGE, cbfunc))

try:
   while True:
      time.sleep(1)

except KeyboardInterrupt:
   pass

print("\ntidying up")

for cb in cbs:
   cb.cancel()

pi.stop()

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.