I went through the
RasPi tutorial on Python interrupts tonight. In the process, I learned that the wget command can be used to download stuff from a website, but that's a moderately uninteresting side bar.
The whole point of interrupts is to not waste CPU cycles polling the buttons (that is, checking on their status). This creates a much more efficient program in the end, and that's a good thing.
Interestingly, this setup does not require the pull-up or pull-down resistors. My guess is that since it's not looking for an actual high/low state but rather a rising/falling state, the fluctuations are too small to be picked up. It could also be that the program is able to internally mimic the pull-up and pull-down resistors, making the physical resistors obsolete.
The important thing for me to remember is that if I use
GPIO.setup(Pin#, GPIO.IN, pull_up_down=GPIO.PUD_UP) then I'm setting the default state to high so that the button needs to connect to ground in order to work.
Since I used wget to download the code, I didn't type it in. I'm going to copy a stripped-down version of the code here so that I at least have a record of it in case the tutorial ever disappears.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
print "Waiting for falling edge on port 23"
try:
GPIO.wait_for_edge(23, GPIO.FALLING)
except KeyboardInterrupt:
GPIO.cleanup()
GPIO.cleanup()
The important new pieces of code are the GPIO.setup which has the extra command to set it as a pull-up or pull-down pin, GPIO.wait_for_edge which puts Python in a passive waiting mode, and GPIO.cleanup() which is probably the command I was missing in an earlier post when it complained about certain pins already being in use.
The try: command is also new. I tried to read some stuff online, but I'm still not completely sure what this does. I think it just tries to execute something and has an error catcher at the end in case there are problems. Since I don't really know the types of exceptions Python can accept and I don't think it's worth spending a lot of time learning them right now, I'm just going to pick things up as I go. The KeyboardInterrupt catches the control-C command, which I think means if I do things right I can make it impossible to quit by hitting control-C.
The first tutorial is pretty straightforward, so I went on to the second one. The purpose of this one was to create a threaded interrupt. This means to use the interrupt to interrupt something else. The buttons are set differently this time, just for demonstration purposes. Here's the basic code:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
def my_callback(channel):
print "Rising edge detected on port 24 - even though, in the main thread,"
GPIO.add_event_detect(24, GPIO.RISING, callback=my_callback)
try:
GPIO.wait_for_edge(23, GPIO.FALLING)
except KeyboardInterrupt:
GPIO.cleanup() # clean up GPIO on CTRL+C exit
GPIO.cleanup() # clean up GPIO on normal exit
This one has the command GPIO.add_event_detect() command. All it seems to say is that it's going to look for pin 24 to rise and when it happens it will call the function my_callback.
The function my_callback is the first user-defined function that I've bumped into so far. I'm not sure why it's set up as my_callback(channel). The "channel" might be the pin number. I'll try to remember to look into that next time I play with this.
The basic idea of this code is that it's waiting for the Pin 23 button to be pressed, but pressing the Pin 24 button will cause the program to jump out of that waiting and do something else.
There's another page to the tutorial where another interrupt event is added. My breadboard ran out of room, so I had to improvise a button out of two loose wires. This is just a reminder that I need to get myself a bigger breadboard soon.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
def my_callback(channel):
print "falling edge detected on 17"
def my_callback2(channel):
print "falling edge detected on 23"
GPIO.add_event_detect(17, GPIO.FALLING, callback=my_callback, bouncetime=300)
GPIO.add_event_detect(23, GPIO.FALLING, callback=my_callback2, bouncetime=300)
try:
GPIO.wait_for_edge(24, GPIO.RISING)
except KeyboardInterrupt:
GPIO.cleanup() # clean up GPIO on CTRL+C exit
GPIO.cleanup() # clean up GPIO on normal exit
There's a bouncetime command that was added to the GPIO.add_event_detect() function. It looks like this feature was added between the time that the second and third pages were written. There's a physical "bounce" when the button is pressed due to the flexing of the metal, and this can cause fluctuations in the voltage that could potentially be picked up as other button pushes. The bouncetime command tells Python to ignore all fluctuations for a certain period of time after the initial detection, and this avoids that bouncing.
What's interesting to me about the code is that there are two different functions that are defined. Next time, I'm going to play around to see if I can get that callback to happen in a single function by using an if-then or something like that. But for now, this is all I've got for the night.