[ACCEPTED]-Simple Debounce Routine-embedded
I think you could learn a lot about this 4 here: http://www.ganssle.com/debouncing.pdf
Your best bet is always to do this 3 in hardware if possible, but there are some 2 thoughts on software in there as well.
Simple 1 example code from TFA:
#define CHECK_MSEC 5 // Read hardware every 5 msec
#define PRESS_MSEC 10 // Stable time before registering pressed
#define RELEASE_MSEC 100 // Stable time before registering released
// This function reads the key state from the hardware.
extern bool_t RawKeyPressed();
// This holds the debounced state of the key.
bool_t DebouncedKeyPress = false;
// Service routine called every CHECK_MSEC to
// debounce both edges
void DebounceSwitch1(bool_t *Key_changed, bool_t *Key_pressed)
{
static uint8_t Count = RELEASE_MSEC / CHECK_MSEC;
bool_t RawState;
*Key_changed = false;
*Key_pressed = DebouncedKeyPress;
RawState = RawKeyPressed();
if (RawState == DebouncedKeyPress) {
// Set the timer which allows a change from current state.
if (DebouncedKeyPress) Count = RELEASE_MSEC / CHECK_MSEC;
else Count = PRESS_MSEC / CHECK_MSEC;
} else {
// Key has changed - wait for new state to become stable.
if (--Count == 0) {
// Timer expired - accept the change.
DebouncedKeyPress = RawState;
*Key_changed=true;
*Key_pressed=DebouncedKeyPress;
// And reset the timer.
if (DebouncedKeyPress) Count = RELEASE_MSEC / CHECK_MSEC;
else Count = PRESS_MSEC / CHECK_MSEC;
}
}
}
Simplest solutions are often the best, and 19 I've found that simply only reading the 18 switch state every N millseconds (between 17 10 and 50, depending on switches) has always 16 worked for me.
I've stripped out broken 15 and complex debounce routines and replaced 14 them with a simple slow poll, and the results 13 have always been good enough that way.
To 12 implement it, you'll need a simple periodic 11 timer interrupt on your system (assuming 10 no RTOS support), but if you're used to 9 programming it at the bare metal, that shouldn't 8 be difficult to arrange.
Note that this simple 7 approach adds a delay to detection of the 6 change in state. If a switch takes T ms 5 to reach a new steady state, and it's polled 4 every X ms, then the worst case delay for 3 detecting the press is T+X ms. Your polling 2 interval X must be larger than the worst-case 1 bounce time T.
There's no single simple solution that works 7 for all types of buttons. No matter what 6 someone here tells you to use, you'll have 5 to try it with your hardware, and see how 4 well it works. And look at the signals 3 on a scope, to make sure you really know 2 what's going on. Rich B's link to the pdf 1 looks like a good place to start.
I have used a majority vote method to debounce 11 an input. I set up a simple three state 10 shift register type of data structure, and 9 shift each sample and take the best two 8 out of three as the "correct" value. This 7 is obviously a function of either your interrupt 6 handler, or a poller, depending on what 5 method is used to actually read the hardware.
But, the 4 best advice is to ask your friendly hardware 3 designer to "latch" the value and allow 2 you to clear this value when you get to 1 it.
To debounce, you want to ignore any switch 3 up that lasts under a certain threshold. You 2 can set a hardware timer on switch up, or 1 use a flag set via periodic interrupt.
If you can get away with it, the best solution 6 in hardware is to have the switch have two 5 distinct states with no state between. That 4 is, use a SPDT switch, with each pole feeding 3 either the R or S lines of a flip/flop. Wired 2 that way, the output of the flip/flop should 1 be debounced.
What I usually do is have three or so variables 11 the width of the input register. Every 10 poll, usually from an interrupt, shift the 9 values up one to make way for the new sample. Then 8 I have a debounced variable formed by setting 7 the logical-and of the samples, and clearing 6 the inverse logical-or. i.e. (untested, from 5 memory)
input3 = input2;
input2 = input1;
input1 = (*PORTA);
debounced |= input1 & input2 & input3;
debounced &= (input1 | input2 | input3);
Here's an example:
debounced has xxxx 4 (where 'x' is "whatever")
input1 = 0110,
input2 = 1100,
input3 = 0100
With the information 3 above,
We need to switch only bit 2 to 1, and 2 bit 0 to 0. The rest are still "bouncing".
debounced |= (0100); //set only bit 2
debounced &= (1110); //clear only bit 0
The 1 result is that now debounced = x1x0
The algorithm from ganssle.com could have 3 a bug in it. I have the impression the following 2 line
static uint8_t Count = RELEASE_MSEC / CHECK_MSEC;
should read
static uint8_t Count = PRESS_MSEC / CHECK_MSEC;
in order to debounce correctly 1 the initial press.
At the hardware level the basic debouncing 48 routine has to take into account the following 47 segments of a physical key's (or switch's) behavior:
Key 46 sitting quietly->finger touches key and 45 begins pushing down->key reaches bottom 44 of travel and finger holds it there->finger 43 begins releasing key and spring pushes key 42 back up->finger releases key and key vibrates 41 a bit until it quiesces
All of these stages 40 involve 2 pieces of metal scraping and rubbing 39 and bumping against each other, jiggling 38 the voltage up and down from 0 to maximum 37 over periods of milliseconds, so there is 36 electrical noise every step of the way:
(1) Noise 35 while the key is not being touched, caused 34 by environmental issues like humidity, vibration, temperature 33 changes, etc. causing voltage changes in 32 the key contacts
(2) Noise caused as the 31 key is being pressed down
(3) Noise as the 30 key is being held down
(4) Noise as the key 29 is being released
(5) Noise as the key vibrates 28 after being released
Here's the algorithm 27 by which we basically guess that the key 26 is being pressed by a person:
read the state 25 of the key, which can be "might be pressed", "definitely 24 is pressed", "definitely is not pressed", "might 23 not be pressed" (we're never really sure)
loop 22 while key "might be" pressed (if dealing 21 with hardware, this is a voltage sample 20 greater than some threshold value), until 19 is is "definitely not" pressed (lower than 18 the threshold voltage) (this is initialization, waiting 17 for noise to quiesce, definition of "might 16 be" and "definitely not" is dependent on 15 specific application)
loop while key is "definitely 14 not" pressed, until key "might be" pressed
when 13 key "might be" pressed, begin looping and 12 sampling the state of the key, and keep 11 track of how long the key "might be" pressed 10 - if the key goes back to "might not be" or 9 "definitely is not" pressed state before 8 a certain amount of time, restart the procedure - at 7 a certain time (number of milliseconds) that 6 you have chosen (usually through experimenting 5 with different values) you decide that the 4 sample value is no longer caused by noise, but 3 is very likely caused by the key actually 2 being held down by a human finger and you 1 return the value "pressed"
while(keyvalue = maybepressed){
//loop - wait for transition to notpressed
sample keyvalue here;
maybe require it to be "notpressed" a number of times before you assume
it's really notpressed;
}
while(keyvalue = notpressed){
//loop - wait for transition to maybepressed
sample keyvalue
again, maybe require a "maybepressed" value a number of times before you
transition
}
while(keyvalue=maybepressed){
presstime+=1;
if presstime>required_presstime return pressed_affirmative
}
}
return pressed_negative
use integration and you'll be a happy camper. Works 5 well for all switches.
just increment a counter 4 when read as high and decrement it when 3 read as low and when the integrator reaches 2 a limit (upper or lower) call the state 1 (high or low).
The whole concept is described well by Jack 40 Ganssle. His solution posted as an answer 39 to the original question is very good, but 38 I find part of it not so clear how does 37 it work.
There are three main ways how to 36 deal with switch bouncing: - using polling 35 - using interrupts - combination of 34 interrupts and pooling.
As I deal mostly 33 with embedded systems that are low-power 32 or tend to be low-power so the answer from 31 Keith to integrate is very reasonable to 30 me.
If you work with SPST push button type 29 switch with one mechanically stable position 28 then I would prefer the solution which works 27 using a combination of interrupt and pooling.
Like 26 this: use GPIO input interrupt to detect 25 first edge (falling or rising, the opposite 24 direction of un-actuated switch state). Under 23 GPIO input ISR set flag about detection.
Use 22 another interrupt for measuring time (ie. general 21 purpose timer or SysTick) to count milliseconds.
On 20 every SysTick increment (1 ms):
IF buttonFlag 19 is true then call function to poll the state 18 of push button (polling).
Do this for N 17 consecutive SysTick increments then clear 16 the flag.
When you poll the button state 15 use logic as you wish to decide button state 14 like M consecutive readings same, average 13 more than Z, count if the state, last X 12 readings the same, etc.
I think this approach 11 should benefit from responsiveness on interrupt 10 and lower power usage as there will be no 9 button polling after N SysTick increments. There 8 are no complicated interrupt modifications 7 between various interrupts so the program 6 code should be fairly simple and readable.
Take 5 into consideration things like: do you need 4 to "release" button, do you need to detect 3 long press and do you need action on button 2 release. I don't like button action on button 1 release, but some solutions work that way.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.