There are several things going on in your code. I suspect that what's really causing the problem is that you need to exit the interrupt handler before another interrupt callback can be triggered...but there is also a confusing mix of callback-based handlers and the GPIO.event_detected method.
I think you can simplify things by performing less manipulation of your interrupt configuration. Just have a state variable that starts at 0, increment it to 1 on the first interrupt, so the next time the interrupt method is called you know it's the second interrupt. No need to try setting multiple handlers like that.
Keeping in mind that I don't actually know what you're trying to do...I imagine something like this:
import RPi.GPIO as GPIO
import time
state = 0
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def interrupt_handler(channel):
global state
print("interrupt handler")
if channel == 19:
if state == 1:
state = 0
print("state reset by event on pin 19")
elif channel == 26:
if state == 0:
state = 1
print("state set by event on pin 26")
GPIO.add_event_detect(26, GPIO.RISING,
callback=interrupt_handler,
bouncetime=200)
GPIO.add_event_detect(19, GPIO.RISING,
callback=interrupt_handler,
bouncetime=200)
while (True):
time.sleep(0)
Answer from larsks on Stack Overflowgpio - How do I implement an interrupt service routine on Raspberry Pi? - Raspberry Pi Stack Exchange
hardware - How can I write a GPIO interrupt driver? - Raspberry Pi Stack Exchange
python - RPi.GPIO interrupt - Raspberry Pi Stack Exchange
Raspberry Pi- GPIO Events in Python - Stack Overflow
Videos
There are several things going on in your code. I suspect that what's really causing the problem is that you need to exit the interrupt handler before another interrupt callback can be triggered...but there is also a confusing mix of callback-based handlers and the GPIO.event_detected method.
I think you can simplify things by performing less manipulation of your interrupt configuration. Just have a state variable that starts at 0, increment it to 1 on the first interrupt, so the next time the interrupt method is called you know it's the second interrupt. No need to try setting multiple handlers like that.
Keeping in mind that I don't actually know what you're trying to do...I imagine something like this:
import RPi.GPIO as GPIO
import time
state = 0
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def interrupt_handler(channel):
global state
print("interrupt handler")
if channel == 19:
if state == 1:
state = 0
print("state reset by event on pin 19")
elif channel == 26:
if state == 0:
state = 1
print("state set by event on pin 26")
GPIO.add_event_detect(26, GPIO.RISING,
callback=interrupt_handler,
bouncetime=200)
GPIO.add_event_detect(19, GPIO.RISING,
callback=interrupt_handler,
bouncetime=200)
while (True):
time.sleep(0)
That sleep(0) just causes the process to idle there while waiting for switch interrupts. Since nothing in there programmatically ends the process, doing a Ctl-C will stop it.
There is no way to call userspace code from an ISR. Unlike system calls which run on the stack of the userspace program, interrupt handlers use internal kernel memory for the stack. Since that memory is not visible in userspace, the system would crash the moment your ISR userspace function finishes or tries to use the stack for local variables (if not before, due to other reasons I have overlooked).
If you need to play with interrupts, you need to write a kernel driver.
wiringPi uses interrupts, e.g. with the wiringPiISR function.
pigpio uses interrupts, e.g. with the gpioSetISRFunc function.
lgpio uses interrupts. e.g. with the gGpioSetAlertsFunc function.
None of the above use polling or busy waits. I can only assume you are confused because at a low level they use a Linux function called poll. But this function does not poll the GPIO in the sense you mean.
Linux handles interrupts. As part of its interrupt handling it will eventually schedule one of the above functions.
pigpio can additionally use GPIO polling via DMA which happens to be more accurate and reliable for short (few µs) level changes.
You should probably go for an Arduino if performance is really important to you. There are many ways you can get a Raspberry Pi to communicate with an Arduino if you need a Pi to be in your project.
If you have decided on using a Raspberry Pi only, you can use WiringPi if you want to control the GPIO pins with C/C++. You can read the documentation for it here. For more info on programming the GPIO Pins with C/C++, you should read the "Programming with GPIO" section on the Official GPIO Docs. I also found a blog post with instructions on how to go about using C/C++ to work with the GPIO pins.
You may want to have a look at the Raspberry Pi Python package RPi.GPIO. It monitors the GPIO pins and allows you to specify callback functions that are called when the pin state changes.
The RPi.GPIO Python library now supports Events, which are explained in the Interrupts and Edge detection paragraph.
So after updating your Raspberry Pi with sudo rpi-update to get the latest version of the library, you can change your code to:
from time import sleep
import RPi.GPIO as GPIO
var=1
counter = 0
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
def my_callback(channel):
if var == 1:
sleep(1.5) # confirm the movement by waiting 1.5 sec
if GPIO.input(7): # and check again the input
print("Movement!")
captureImage()
# stop detection for 20 sec
GPIO.remove_event_detect(7)
sleep(20)
GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)
GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)
# you can continue doing other stuff here
while True:
pass
I chose the Threaded callbacks method because I suppose that your program does some other things in parallel to change the value of var.
Now the RPi GPIO library has inbuilt interrupt driven GPIO control which can happen in separate thread freeing up resources. You may wish to read the following http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3
It may be a known fault. See https://sourceforge.net/p/raspberry-gpio-python/tickets/121/
On a general point there is little reason to expect that the level of the GPIO when read in the callback has any relationship to the level which caused the callback.
The callback code may be executed many milliseconds after the actual event during which time the switch level may have changed.
use this === GPIO.add_event_detect(25, GPIO.RISING, callback=my_callback)
you are using GPIO.BOTH thats why you are getting the "Rising edge detected" message on both the push and release.