Page 1 of 1
GPIO debounce
Posted: Thu Feb 25, 2016 3:06 pm
by mmkw43
I have some code using python that sets up the pins as inputs and was wondering if anyone has had experience with any debounce advantage that using a falling edge may provide. Right now I have resistor pullups on my switches which are soldered and .1 caps to ground on each and 99.9% of the time I don't have a problem -- the switches are scanned in a fast loop (100 milliseconds).
But I also "try" to get a debounce and can sometimes -- but before I test using falling edge instead of just "input", thought I'd ask.
so that's question 1
Also, just trying to get my head around why you can't "configure" the inputs in a setup just once rather than doing each time. What I mean is --
GPIO.setup(3,GPIO.IN) # I get that and yes, I can do that just once and initialize it in my class,
but why is it you can't also ? --
self.var = GPIO.input(3) # I have to include this line in my loop when I scan the inputs (seems kind of redundant)
if self.var == 1:
do this
And -- if I were to change GPIO.input(3) to utilize falling edge it becomes --
GPIO.add_event_detect(3,GPIO.FALLING) # can this be stated once in initialize?
then
GPIO.wait_for_edge(3,GPIO_FALLING,timeout=10) # has to run in the loop also? (wow?)
Hope I'm making sense -- just seems like your asking the cpu to do a lot (over and over again) just to sense an input.
Thanks.
Re: GPIO debounce
Posted: Thu Feb 25, 2016 3:35 pm
by joan
Switch? With RPI.GPIO I'd do the following.
Set up a callback for the edge of interest using add_event_detect.
In the callback do a busy spin read of the GPIO for the debounce period. If it changed state during the debounce period just return with no state change. If it was steady for the debounce period declare a state change.
I wouldn't use capacitors. Using the wrong values can cause more problems than it solves.
Re: GPIO debounce
Posted: Thu Feb 25, 2016 5:15 pm
by mmkw43
probably should have posted this in python -- sorry about that.
forgot to mention that these contacts I'm monitoring are momentary and I need to detect even the slightest contact from a either switches, relays, open collector etc. I thought about how to debounce in my code but couldn't think of anything because after all, I need to "catch" the slightest contact closure. In fact, I changed my loop to time.sleep 100 milliseconds from 200 because it made a big difference. (I put a delay at the end because it keeps the cpu happy).
Re: GPIO debounce
Posted: Thu Feb 25, 2016 5:35 pm
by joan
mmkw43 wrote:probably should have posted this in python -- sorry about that.
forgot to mention that these contacts I'm monitoring are momentary and I need to detect even the slightest contact from a either switches, relays, open collector etc. I thought about how to debounce in my code but couldn't think of anything because after all, I need to "catch" the slightest contact closure. In fact, I changed my loop to time.sleep 100 milliseconds from 200 because it made a big difference. (I put a delay at the end because it keeps the cpu happy).
Catching the slightest contact closure and debounce aren't really compatible. A mechanical switch may well bounce a dozen times in a millisecond when opened or closed. Does that count as none, one, or a dozen events?
Re: GPIO debounce
Posted: Thu Feb 25, 2016 8:26 pm
by mmkw43
Catching the slightest contact closure and debounce aren't really compatible.
right -- hence, my dilemma. using an optoisolator with a transistor output to interface the PI. I suppose I'll just have to get rid of any debounce in the circuit -- was hoping early on I could do it in software. -- oh well
Re: GPIO debounce
Posted: Thu Feb 25, 2016 8:42 pm
by joan
mmkw43 wrote:Catching the slightest contact closure and debounce aren't really compatible.
right -- hence, my dilemma. using an optoisolator with a transistor output to interface the PI. I suppose I'll just have to get rid of any debounce in the circuit -- was hoping early on I could do it in software. -- oh well
You can debounce in software. But you have to know what you are trying to achieve. How long must an edge last before you want it to be treated as a true transition? A nanosecond, microsecond, millisecond? You need to know the answer to that before you can filter the edge in software.
Re: GPIO debounce
Posted: Thu Feb 25, 2016 8:59 pm
by mmkw43
Ok -- (by the way, I'm a hobbyist programmer) -- so if I say 10 milliseconds, trying to figure out how I can do something in code. Right now my loop is
Code: Select all
def loop(self):
while True:
self.ch1 = GPIO.input(pin)
ch2
ch3
etc
if self.ch1 == 0:
anotherclass.cl1 = 1
if self.ch2
etc
time.sleep(.100)
the momentary closure at the GPIO makes cl1 (which is another class) a 1 (until I reset it later on) I can't do anything in the loop because I don't want to slow it down. thanks for the interest joan -- I'll figure this out.
Re: GPIO debounce
Posted: Thu Feb 25, 2016 9:50 pm
by davidcoton
mmkw43 wrote:Ok -- (by the way, I'm a hobbyist programmer) -- so if I say 10 milliseconds, trying to figure out how I can do something in code.
...
the momentary closure at the GPIO makes cl1 (which is another class) a 1 (until I reset it later on) I can't do anything in the loop because I don't want to slow it down. thanks for the interest joan -- I'll figure this out.
You shouldn't be anywhere near out of time in the loop -- and unless you write multiprocessor code to run on a Pi2, doing stuff in the loop or out will make no difference -- all the code must run on the single processor. To check, print out times of entry and of reaching the sleep statement so you can see exactly how long the code takes.
To debounce entirely in software, looking for a pulse of 10mS minimum, you need to run the loop every 2 mS and look for five low levels in a row. Similarly the switch has opened with five (or whatever) high levels. There is no change to the debounced state if changes occur after four or less scans. You need this to know when to start counting lows again, even if the switch opening does not reset the output variable. (You might also consider what needs to happen if your debounce detects a second switch closure before the rest of the software has processed the first one.) Make sure the sleep takes account of the time used -- don't use a fixed sleep period. (exercise for the reader -- difficulty moderate).
There is a long thread with interesting observations
here which is well worth reading and understanding if you need to get serious with debounce.
Re: GPIO debounce
Posted: Fri Feb 26, 2016 2:52 pm
by mmkw43
Awesome -- thank you very much. Learning all the time.
Re: GPIO debounce
Posted: Fri Feb 26, 2016 2:59 pm
by joan
A simple method.
Code: Select all
#!/usr/bin/env python
import time
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
def cbf(gpio, level, tick):
print("{:2d}->{} at {}".format(gpio, level, tick))
GPIO=4
GLITCH=0
SLEEP=60
pi = pigpio.pi()
if not pi.connected:
exit(0)
pi.set_mode(GPIO, pigpio.INPUT)
# Ignore edges shorter than GLITCH microseconds.
pi.set_glitch_filter(GPIO, GLITCH)
cb = pi.callback(GPIO, pigpio.EITHER_EDGE, cbf)
time.sleep(SLEEP)
cb.cancel()
pi.stop()
All you need to do is choose a value of GLITCH such that any edge lasting less than GLITCH microseconds is to be ignored.
Re: GPIO debounce
Posted: Fri Feb 26, 2016 3:01 pm
by Massi
why do not use callbacks? why do not use pigpio's "glitch filter" for debounce?
http://abyz.co.uk/rpi/pigpio/python.html#callback
http://abyz.co.uk/rpi/pigpio/python.htm ... tch_filter
Edit: LOL joan is too fast for me.. but at least we thought to the same exact thing

Re: GPIO debounce
Posted: Sat Dec 03, 2016 12:19 pm
by jonesmerc
Hi there
First thanks for the hints above. I think this is exactly what I need.
But unfortunately I don't understand how this callback Function is used.
As far as I understand I define all GPIO pins with the new method of the pigpio library, I set a glitch_filter and now whenever a GPIO edge (is it just a state change?) is detected and it is not filtered by the glitch time period it will call the callback Function. Right?
If an state change is detected I want to check a button's state and if pressed I want to start some music and set a relay pin to high. I came up with this so far:
Code: Select all
import RPi.GPIO as GPIO
import time
import pygame
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
# set up the mixer
freq = 44100 # audio CD quality
bitsize = -16 # unsigned 16 bit
channels = 1 # 1 is mono, 2 is stereo
buffer = 1024 # number of samples (experiment to get right sound)
pygame.mixer.init(freq, bitsize, channels, buffer)
pygame.mixer.music.set_volume(0.3)
pygame.mixer.music.load("audio/c3.wav")
pygame.mixer.music.play(-1)
pygame.mixer.music.pause()
paused = True
# set vars for pigpio use. E.g.: write(PIN, LOW)
LOW = 0;
HIGH = 1;
RELAY_PIN = 18 # Relay Control Pin
BUTTON_PIN = 24 # Input Pin
# set up debounce variables
GLITCH = 3000
SLEEP = 200
# callback Function on GPIO change detection
def callbackFunction(gpio, level, tick):
global paused
print("{:2d}->{} at {}".format(gpio, level, tick))
# check button
if (pi.read(BUTTON_PIN)):
# print("Button Pressed")
pi.write(RELAY_PIN, HIGH)
if (paused == True):
paused = False
pygame.mixer.music.unpause()
else:
pi.write(RELAY_PIN, LOW)
if (paused == False):
paused = True
pygame.mixer.music.pause()
# Init pigpio module for GPIO control
pi = pigpio.pi()
if not pi.connected:
exit(0)
# sets BUTTON PIN as Input
pi.set_mode(BUTTON_PIN, pigpio.INPUT)
# Ignore edges shorter than GLITCH microseconds.
pi.set_glitch_filter(BUTTON_PIN, GLITCH)
# Set up the GPIO pin for output
pi.set_mode(RELAY_PIN, pigpio.OUTPUT)
# set callback when GPIO edge is detected
cb = pi.callback(BUTTON_PIN, pigpio.EITHER_EDGE, callbackFunction)
time.sleep(SLEEP)
cb.cancel()
pi.stop()
I now don't see any effect, although my glitch is set to 3000ms (is it milliseconds anyway?).
I also don't understand what the SLEEP is for. Is this just a line to get the code running for 200ms? Why would it not stop immediately. And the cb.cancel and the pi.stop is unnecessary until I want the programm to stop, right?
Sorry for all those questions, but if someone could help out that would be great.
Thanks in advance.
Cheers
Re: GPIO debounce
Posted: Sat Dec 03, 2016 3:07 pm
by joan
The glitch filter value is in microseconds, so 3000 is actually 3 milliseconds.
http://abyz.co.uk/rpi/pigpio/python.htm ... tch_filter
The maximum settable value is 300000 or 0.3 seconds.
Suppose the button state is low (0). A value of 3000 means that a change to high (1) which lasts 2999 µs or less will be ignored. Your software won't be told about it, i.e. you will not get a callback.
I would not use the read() function to check the button state in the callback. You already know the button state, it is the level parameter passed to the callback.
So use
if level:
rather than
if (pi.read(BUTTON_PIN)):
The sleep() simply allows the script to run. Otherwise the script will terminate straight away. It would be fairly normal to have a while loop there for your main program to carry out other functions.
Yes the cancel() and stop() only need to be called at the end of the script.
You should also probably add pi.set_glitch_filter(BUTTON_PIN, 0) just after the sleep() to disable the glitch filter (the value will stay set otherwise).
Note that pigpio only uses Broadcom GPIO numbers. If it doesn't act as expected that might be the problem.
To test the script without hardware you could set the GPIO levels external to the script (in a console window).
pigs w 24 0 # set button low
pigs w 24 1 # set button high