4

So, I have 2 buttons set up on pins 17 and 27.

buttons = (17, 27)
GPIO.setup(buttons, GPIO.IN, pull_up_down=GPIO.PUD_UP)

I need to accept input from EITHER of these for a set period of time.

I found this code which works for 1 button here

channel = GPIO.wait_for_edge(17, GPIO_RISING, timeout=5000)
if channel is None:
    print('Timeout occurred')
else:
    print('Edge detected on channel', channel)

I changed "GPIO_RISING" to "GPIO.RISING" to get it to work.

As mentioned this works fine for 1 button, and can detect the button press. The problem is when I try and alter the code to accept the second button.

channel = GPIO.wait_for_edge(17, GPIO.RISING, timeout=5000)
channel1 = GPIO.wait_for_edge(27, GPIO.RISING, timeout=5000)

if channel is None and channel1 is None :
    print('Timeout occurred')
elif channel is not None:
    print('Edge detected on channel', channel)
elif channel1 is not None:
    print('Edge detected on channel', channel1)
else:
    print('something')

This makes channel detectable for the first 5 seconds and channel1 detectable the next 5 seconds, not concurrently.

How do I solve this?

3 Answers 3

3

The answer of joan is probably working fine, but with the event_detected() function you can also do it like this:

GPIO.add_event_detect(17, GPIO.RISING)  # add rising edge detection on a channel
GPIO.add_event_detect(27, GPIO.RISING)  #for both buttons

start = time.time()
while True:
    if GPIO.event_detected(17):
        print('Button 1 pressed')
    if GPIO.event_detected(27):
        print('Button 2 pressed')
    if time.time() - start > 5:
        print('Timeout')
    time.sleep(0.0001)

See documentation for more info.

1
  • does this work even if we put a callback inside add_event_detect?? Commented Sep 30, 2017 at 12:34
3

You will need to use callbacks, to detect both signals. Use a queue, to communicate with the main program:

from queue import Queue, Empty

queue = Queue()
GPIO.add_event_detect(17, GPIO.RISING, queue.put)
GPIO.add_event_detect(27, GPIO.RISING, queue.put)

# wait for a event for 5 seconds
try:
    event = queue.get(timeout=5)
except Empty:
    event = None

GPIO.remove_event_detect(17)
GPIO.remove_event_detect(27)

if event is None:
    print("timeout")
else:
    print("event on {}".format(event))
2

You will need to adopt a different design.

wait_for_edge "does what it says on the tin". It waits for an edge or times out.

I'd use a GPIO callback (add_event_detect in RPi.GPIO terms) and have a different callback triggered by each GPIO.

Something like (pseudo code to give an idea)

def callback_1():
   global GPIO1_triggered
   set GPIO1_triggered

def callback_2():
   global GPIO2_triggered
   set GPIO2_triggered

GPIO1_triggered = False
GPIO2_triggered = False

add_event_detect(GPIO1, callback1)
add_event_detect(GPIO2, callback2)

stop = time.time() + 5

while not GPIO1_triggered and not GPIO_2 triggered and time.time() < stop:
   time.sleep(0.01)

cancel_event_detect(GPIO1)
cancel_event_detect(GPIO2)

if GPIO1_triggered:
   code
elif GPIO2_triggered:
   code
else:
   code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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