switch software debounce  - Page 1
Forum section: electronics / general

author: BlogRahul
author_rank: Regular Contributor
timestamp: September 11, 2021, 01:12:11 am
content: HiI am just trying to understand switch software debounce let's say if TACT switch has maximum bounce time of 5-8ms then it is stable. How many successive reading need to consider switch is in stable state ? At what time interval should we take readings ?

author: pqass
author_rank: Super Contributor
timestamp: September 11, 2021, 03:15:06 am
content: A very good read on switch debouncing can be found here:http://www.ganssle.com/debouncing.htmYou'll find your answer under "Debouncing in Firmware" in Part 2.

author: BlogRahul
author_rank: Regular Contributor
timestamp: September 11, 2021, 04:00:51 am
content: If I am understanding the information given in the tutorial correctly counting algorithm. Switch is being read every 5ms. Two successive reading show that switch is pressed and debounced. 20 successive reading show that switch is released and debounced

author: pqass
author_rank: Super Contributor
timestamp: September 11, 2021, 04:31:17 am
content: Quote from: BlogRahul on September 11, 2021, 04:00:51 amYes.Keep in mind that the DebounceSwitch1() function is constantly being called every 5ms in a timer interrupt.Your code elsewhere can just check the value of a local copy (pointed to by *Key_pressed parameter) knowing that the value is debounced.

author: AaronLee
author_rank: Regular Contributor
timestamp: September 11, 2021, 07:48:42 am
content: I didn't spend time to read the link, so probably what I'm about to say was already covered.What I generally do is just have a debounce timer that counts down in a timer interrupt function. I like to use 50ms for the debounce timer, which is probably excessive, but I've yet to have any issues with that value. I typically can just poll the keys, and detect if there's a difference in the value of any key between the read value, and if so, set the debounce timer. Once the debounce timer has expired (and sets the appropriate flag), it means there's been no change in any of the keys for that period of time, and in the key polling task I check that flag and then process any pressed keys. None of my applications need to work with n-key rollover or multiple keys being pressed at one time, so one debounce timer is sufficient.

author: harerod
author_rank: Frequent Contributor
timestamp: September 11, 2021, 12:03:25 pm
content: The EMC requirements for many real world applications will require some protection between switch and MCU. This might not be for every design, but I usually do low volume, high profit stuff. In that case it is always cheaper to spend some extra cents per device, than swallow the thousands of dollars a second visit to the notified body after respinning the design would cost.A couple of resistors, a capacitor and an ESD-diode or dual-diode to the supply rails (depends on application) will protect the design from immissions, reduce emissions and form a low pass that makes firmware debouncing simpler, if not unnecessary.

author: bson
author_rank: Unknown
timestamp: September 11, 2021, 08:18:06 pm
content: If the switch is debounced, then any change to it indicates a change of state. This is the initial voltage change.Followingthis may there be bounce. But the initial pulse is never a bounce, it's always a physical press or release. The way to handle it is to react to the initial pulse, then impose a quiet period where you ignore the switch. If you poll it every 5ms, then this is by definition going to be ≤5ms. If the switch can bounce for longer than 5ms, then you need a longer poll interval. But why would you poll it every 5ms? Nobody can press a switch that fast anyway, 20 presses/s would only require a 50ms poll interval.

author: pqass
author_rank: Super Contributor
timestamp: September 12, 2021, 07:17:18 pm
content: This post reminded me of the occasional button bouncing issue in one of my projects so I decided to explore the last algorithm at the bottom of Part 2 of the article here (http://www.ganssle.com/debouncing.htm) and scope how well it works (see screenshots below).It's easier/faster than the first algorithm but limited to the same waiting period on button press vs. release (I don't think it really matters). Also, I've changed it such that the static state information is removed from the routine itself thus can be used over any number of buttons where each is attached to a separate pin. See Arduino code below.The test hardware is an ATmega644A (w/ 16MHz xtal) on a breadboard with outputs on PA0 (pin 40) and PA1 (pin 39). Input is on PA7 (pin 33) with internal pull-up enabled. The input hardware is a (tiny, 4-legged PCB-type) monentary button attached to PA7 with other pair to GND. I've intentionally left out the 100nF cap I'd normally put on the input pin.Scope probes:YELLOW is on PA7 (pin 33), showing the raw button wave,GREEN is on PA1 (pin 39), showing high whenever code is in the interrupt routine, andBLUE is on PA0 (pin 40), showing the current debounced state of the button.The first screenshot shows the overall momentary press/release event.The second screenshot shows a closer look at the press-part; first half of the event. You can see the regular timer tick in GREEN. The tick is only 2us wide and 5ms apart. Notice that there are 8 green ticks before the debounced state of the button changes (BLUE).The third screenshot shows a closer look at the release-part; last half of the event. Again, 8 GREEN ticks occur before the BLUE state changes.I like this approach because I can use my existing multiplexed display timer event to also read button state and execute debounce logic. Currently, it fires every 3.3ms (or 300/s; for 5 7-seg displays * 60Hz). If I call DebouncePin() every other tick (6.6ms) then the debounce period is 53ms before the final state of the button is decided.

author: Rick Law
author_rank: Super Contributor
timestamp: September 12, 2021, 08:00:39 pm
content: Quote from: BlogRahul on September 11, 2021, 01:12:11 amI think it is a bit of over optimism to look at the maximum bounce time of a switch. It varies too much switch by switch. Besides, if you are going to tap your fingers on the table top, you would have a hard time reaching 15 taps a second. I believe it would be rarer than hen's teeth to find a person who can do even 15 taps/second.Say you agree with what I just said above, 15 key presses is more than one can expect unless you go with a machine to auto-press the switch. That 15/second translates to 33 ms between key presses.MCU speed varies too much, so the best would be to actually first get a sense of your MCU binary I/O read time. I suspect 1 or 2 ms would likely be enough, but just to be complete, letsay your MCU takes T seconds to do a binary read. So you wait (33ms-T) and do the read.Any switch that is still bouncing after that should probable be thrown away. Say you are still uncomfortable, wait (33ms-3T), take 3 readings and majority rule. For me, I am a bit lazy. Rather than doing all that testing,I would just pick 30ms wait, and read the darn thing.Now about the 1st paragraph, there are backings to my claims (this is really for if you need to justify to your boss and need some backing): Switch bounce time varying too much (30ms-ish is enough):One may be able to find even worst, the worst bounce I have been able to find is 157 ms by the article already cited by previous reply: The Ganssle Group. They tested 18 switches. The 157ms is the worst, and second worst is 11.3ms.The rest of the 16 out of 18 bounced average at 1.557ms. Worst in this group of 16 was 6.2ms.So, two bad switches in my book, and if it bounce more than 20ms (about 3x the tested worst in the 16 "good" switch), it probably should be considered a bad switch for the garbage bin.This same article also shows 3.3ms to trigger the display, so reading the binary switch open/close would certainly have T<3ms. Is 15 taps per second really the human limit?Interestingly, there is a study by the University of Houston (Texas, USA) about that subject. "Decoding repetitive finger movements with brain activity acquired via non-invasive electroencephalography" published 2014.In this study of 5 young adults (25+-2 years old, 4 males, 1 female), with each trial being 3 taps (or other movements defined by the test) in a row. Repeated finger tap exhibits an EEG brainwave of 0.1Hz to 3Hz (see table 1 in the study). So nothing in any of the movement involved in doing a tap was happening faster than 0.1Hz (10 per second), even if extending the finger or palm is included. So my take is in their study group of five, max they could tap would not exceed 10 per second.It is of course difficult to extend 5 individuals to the entire button pressing humans. 15 taps may not be the human limit but looks like a reasonable upper limit for average button-pressing users.Link to actual article: Decoding repetitive finger movements with brain activity acquired via non-invasive electroencephalography. March 2014, authors: Andrew Y. Paek, Harshavardhan A. Agashe and José L. Contreras-Vidal; Laboratory for Non-invasive Brain-Machine Interface Systems,Department of Electrical and Computer Engineering, University of Houston, Houston, TX, USAhttps://www.frontiersin.org/articles/10.3389/fneng.2014.00003/full

author: ledtester
author_rank: Super Contributor
timestamp: September 26, 2021, 10:10:22 am
content: Quote from: pqass on September 12, 2021, 07:17:18 pmHi pqass...I'm curious what switch you're using in this test. Where did you get it from and does it have a part number/datasheet? Is it brand new or has it been used a lot?It's just that in the testing I've done with my collection of tactile switches I've never seen one that generated so much bounce.

author: DavidAlfa
author_rank: Super Contributor
timestamp: September 26, 2021, 02:35:20 pm
content: Whenever I need to seriously filter some inputs, I do something like this, provides a very neat and compact code :(This example is for stm32)Code:#define BUTTONS 3 // Number of buttons to be filtered#define DEBOUNCE 20 // Debounce timetypedef enum { button_A=0, button_B=1, button_C=2 }button_t; // Translation between button names and index numbertypedef struct { // Input filter structureuint8_t state;uint8_t last;uint16_t pin;uint32_t timer;GPIO_TypeDef *port;}inputFilter_t;inputFilter_t buttons = { // Button structure initialization = {.port = GPIOA,.pin = GPIO_PIN_0,}, = {.port = GPIOA,.pin = GPIO_PIN_8,}, = {.port = GPIOC,.pin = GPIO_PIN_5,},};void updateButtons(void){ // To be called periodically by main or some interrupt every few msuint8_t current;uint32_t time = HAL_GetTick();for(uint8_t b=0; b<BUTTONS;b++){ // Scan buttonscurrent = (buttons.port->IDR & buttons.pin) && 1; // Store booleanif(buttons.last != current){ // If button changedbuttons.last = current; // Update last statebuttons.timer = time; // Restart timer}else if(buttons.timer){ // If timer activeif((time-buttons.timer)>DEBOUNCE ){ // Check if button was stable for the specified timebuttons.state = current; // Update statebuttons.timer = 0; // Disable timer until the value changes again}}}}uint8_t readButton(button_t b){ // To be called when the program wants to read a buttonreturn buttons.state;}void someFunction(void){ // Example:if(readButton(button_A)){Do_something();}}

author: pqass
author_rank: Super Contributor
timestamp: September 28, 2021, 07:37:00 pm
content: Quote from: ledtester on September 26, 2021, 10:10:22 amIt was pulled off an old board. No idea on the provenance.I tried a few and that was the worst.

author: AaronD
author_rank: Frequent Contributor
timestamp: October 08, 2021, 04:34:52 pm
content: What I find interesting in all this is: Yes, switches are bouncy, but humans are slow enough that you can just read a button at that slow rate and not have to worry about it. Only a truly awful button in need of replacement will fool that, in which case a fast-reading debouncer will probably be fooled too.The two cases to consider when sampling slowly are: a) taking a reading on either side of the noise with none during, or b) taking one reading *during* the noise. The first case is trivial, and the second falls into 2 more categories, depending on whether the noisy reading matches the previous or next reading.Regardless, the software still sees a clean transition, and it becomes random whether you have an additional sampling delay or not in the response. But again, user interfaces are typically slow enough that that delay doesn't matter.For other applications - perhaps a limit switch, for example, that can be destroyed if the motion doesn't stop - then you want to sample it faster just to get a fast response. But you probably only care about the edge in that case and not the level. By the time you've finished stopping the machine, the switch has stabilized and you can safely switch to being level-sensitive without a debouncer.Or perhaps you can have an asymmetrical debouncer, which is simply a timer that requires it to be "okay" for that long before it's recognized, while "not okay" happens instantly.This "time" could be a number of clocks (actual time), or a number of samples like the DSP world uses, or whatever periodic thing you happen to have handy.A possible way to make an asymmetrical debouncer might be like this:Code:if (button){output = DEBOUNCE_TIME;}if (output){output--;}Call that at regular intervals, and the output will follow the button at that sampling rate, but stretch the falling edge by DEBOUNCE_TIME-2 number of samples. (reverse the order to make it DEBOUNCE_TIME-1) Then somewhere else in your code:Code:if (output){//button high}else{//button low}(this takes advantage of zero being FALSE and anything non-zero being TRUE)You can expand this concept to make it symmetrical, but it's not quite as clean. (there's only one "convenient value" - zero - and you now have two to keep track of, so the other one isn't quite as nice)Another DSP-related method is to convert the binary input to whatever extreme values you want to use, and then lowpass that. Compare the result to some appropriate thresholds, and you again have a debounced button. (this is essentially what the analog RC version does, using the fixed logic thresholds of a digital input) The interesting thing about this approach is that the debounce time for each direction varies according to the amount of time spent in each state recently. That can be good for rejecting glitches, not so good for other things.