Multiple threaded callback interrupts in Python
We’ve been learning about interrupts this week because of the brand new interrupt capabilities of RPi.GPIO. We covered a simple “wait for” interrupt in part 1, threaded callback interrupt and button debouncing in part 2 and today we’re getting sophisticated with multiple threaded callbacks. “WoooooooooOOOOOOOOOOOOOOOooooooooooo”, I hear you say. ;)
Well actually, we’re not doing much that’s very different from last time, except, now there’s more of it. We’ll add another button and another threaded callback function the same as the first one (but on a different GPIO port). This is just to show that you can do multiple threaded callbacks in one program. After that, your imagination is the limit. (Well actually the number of GPIO ports is probably the limit.)
We’re just building on what we did before and this is exactly how programs are made. You do a bit at a time, test it, fix it, make sure it does what it ought to do, then go on to the next bit.
Here’s the Circuit
This circuit is a bit different from the previous one. The top two buttons connect port 17 and port 23 to GND when pressed. These are the two which trigger callbacks. The bottom button, connecting port 24 to 3V3 on button press is the “wait for” interrupt this time. So when you press button 3 it’s “game over”, but buttons 1 and 2 just report that they’ve been pressed until button 3 is eventually pressed.
We’ve used all the same building blocks we developed in parts 1 and 2, including button debouncing.
Do you need to update RPi.GPIO?
If you didn’t do it for the first or second examples, you will quite likely need to update your RPi.GPIO package. You can check what version of RPi.GPIO you have in the command line with…
import RPi.GPIO as GPIO
This should show you what RPi.GPIO version you have. You need 0.5.1a or higher for this example.
You can exit the python environment with
Install RPi.GPIO version 0.5.2a for multiple threaded callback interrupts
If you need to, you can install 0.5.2a or later with
sudo apt-get update (This will update all your Raspbian packages and may take up to an hour)
sudo apt-get upgrade
Update July 2014
The best way to get the latest RPi.GPIO (currently 0.5.5) is to flash a new SD card with the latest NOOBS or Raspbian. This will give you a clean start with the latest version of RPi.GPIO.
And now onto the code
I’ve put most of the explanations in the code, so that if you use it, you will still have them.
#!/usr/bin/env python2.7 # script by Alex Eames https://raspi.tv # https://raspi.tv/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3 import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) # GPIO 23 & 17 set up as inputs, pulled up to avoid false detection. # Both ports are wired to connect to GND on button press. # So we'll be setting up falling edge detection for both GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # now we'll define two threaded callback functions # these will run in another thread when our events are detected def my_callback(channel): print "falling edge detected on 17" def my_callback2(channel): print "falling edge detected on 23" print "Make sure you have a button connected so that when pressed" print "it will connect GPIO port 23 (pin 16) to GND (pin 6)\n" print "You will also need a second button connected so that when pressed" print "it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)\n" print "You will also need a third button connected so that when pressed" print "it will connect GPIO port 17 (pin 11) to GND (pin 14)" raw_input("Press Enter when ready\n>") # when a falling edge is detected on port 17, regardless of whatever # else is happening in the program, the function my_callback will be run GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300) # when a falling edge is detected on port 23, regardless of whatever # else is happening in the program, the function my_callback2 will be run # 'bouncetime=300' includes the bounce control written into interrupts2a.py GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300) try: print "Waiting for rising edge on port 24" GPIO.wait_for_edge(24, GPIO.RISING) print "Rising edge detected on port 24. Here endeth the third lesson." except KeyboardInterrupt: GPIO.cleanup() # clean up GPIO on CTRL+C exit GPIO.cleanup() # clean up GPIO on normal exit
bouncetime=300 in lines 34 & 39 sets a time of 300 milliseconds during which time a second button press will be ignored. The code from example 2a has been incorporated into RPi.GPIO.
You can download this directly to your Pi using…
Then you can run it with…
sudo python interrupt3.py
Can I switch off an event detection?
There’s just one more thing. If you want to stop an event detection on a particular port, you can use the following command…
You now know all you need to know about how to create and manage interrupts in RPi.GPIO in Python on the Raspberry Pi. The official documentation is here if you want to check it out.
Have fun with interrupts. I hope this mini-series has been useful. Let us know, in the comments below, what you’re planning to use it for and then come back and tell us how it went. :)
For extra credit, can you tell me why I chose those specific GPIO ports for these experiments?