Smart Button Debounce with Fast Response
Created: Nov 15, 2024 DISCLAIMER |

This Button Debounce software quickly exits bounce-Interrupts. It accepts rapid press speeds to 5+ per second. It adapts to varied hold-down times while separating one button-press from the next. And it delivers near instantaneous response.
A Timer-ISR combined with one or more button-ISR's makes this possible. Together they become an adaptive Input-Processing machine. Check this out...
Button Input Processing and Debounce
A momentary button-cycle has 4 distinct states; Idle, Press, Hold and Release. Contact bounce can occur after Press and Release. While each Press represents a valid Input, ensuing Bounce-caused signals represent false-input. See next...
From the diagram, we see where bounce can occur. But bounce is only part of a larger problem. To obtain valid Input from button signals, we must perform crucial Input Processing steps;
- Accept each Press as valid Input
- Reject bounce-Interrupts as Input.
- Adapt to human-variations of hold-time and press-to-press speed.
- Accurately separate one button-cycle from the next.
- Respond promptly to Press events.
Adaptive Button Debounce
Here's one way to accomplish Button Input Processing using a two ISR approach;
- A button sits idle. A 1st-contact press invokes it's ISR which tests a timeStamp for age. If older than 25 mSec, the Interrupt is treated as a new button cycle. The ISR overwrites the timeStamp using millis() -- then sets a button-ID before exit.
- The 1st-contact timeStamp now becomes a bounce-block filter. Subsequent bounce-Interrupts force the same timeStamp test. While age remains below 25 mSec, each Interrupt quickly exits. No false inputs are reported. CPU waste is low.
- A Timer-ISR also executes every 10 milliseconds. It too checks timeStamp age. If below 25 mSec, it then reads button port pins. If any pin is active, the Timer-ISR overwrites the timeStamp using millis(). This extends bounce blocking another 25 mSec. The Timer basically tracks button hold-time keeping bounce-block alive.
- After button-release (and bounces end), the timeStamp no longer receives updates. It soon ages past 25 mSec. At this point, the button-cycle is complete. Since the timeStamp has expired, the button-ISR becomes re-armed. Its ready to treat the next Interrupt as a new 1st-contact event.
Button Debounce Demo in Real-Time
The following snapshot illustrates ISR debouncing as it happens. To prove the code works, I added an extra 1-mSec Timer (timeStamp expire tests) and a bit more code to toggle some port-pins. The pins drive a Logic-Analyzer to show button debounce in real time. See next...
It doesn't matter how much time a button-cycle uses. Timer-ISR updates keep bounce-blocking active from Press-to-Hold-to-Release. The code literally adapts to the User.
Rapid Button Debounce Test
The next image shows a rapid multi-press test. The bottom trace goes LOW at button 1st-contact (down-arrows). It stays LOW while 10-mSec tests detect button activity. But after button release, the timeStamp expires some 25 mSec later. The bottom trace then goes HIGH (markers overlaid) indicating a completed button-cycle.
- The Image shows bounces can occur at Press, Release and sometimes Hold.
- The lower trace reveals -separation- between button-cycles with no false signals.
- Though button-cycle spacing varied in real-time, the code adapted.
Please know the start of each Bounce-Block cycle is where Input is detected -- execution quickly returns to main. This makes possible high-speed response since bounce-block and hold-tracking are exclusively handled by background Interrupt Service Routines.
Button Debounce Snippet
Here's sample ISR code for two buttons (a full sketch is available below). Other code was removed. These short ISR's perform nearly all needed Input processing including debounce!
void ISR_BUTTON_1() { // tests True @1st contact, False on bounces if ((millis() - timeStamp) > AgeExpiration) { // 1st contact --> overWrites timeStamp timeStamp = millis(); ButtonID = 1; NewButtonEvent = true; } } void ISR_BUTTON_2() { // tests True @1st contact, False on bounces if ((millis() - timeStamp) > AgeExpiration) { // 1st contact --> overWrites timeStamp timeStamp = millis(); ButtonID = 2; NewButtonEvent = true; } } // 10 mSec Timer ISR ISR(TIMER2_OVF_vect) { // Test timeStamp Age if ((millis() - timeStamp) < AgeExpiration) // True if BounceBlock active { // Test button Activity on two port-C pins, mask all except pins of interest if ((PINC & 0b00101000) != 0x28) // binary 00101000 equals 0x28 hex { // activity detected, extend timeStamp 25 mSec timeStamp = millis(); } } }
Button Debounce Sketch
A fully tested two button debounce sketch for Arduino Uno can be downloaded at bottom of this page. It may work on a Nano but I didn't try it. It will NOT work on a mega2560 (as written) -- different wiring needed.
The sketch uses two buttons as Input and Serial for output. Its coding style is event-driven. Code in loop() looks for newButtonEvent to go true. A switch-case block then decides which button-ID requires service. An associated button-count gets incremented and sent to Serial. You'll find response to button-press is quite fast.
- Even though Serial eats real-time -- at 115200 baud, we get a decent idea of button Input performance.
- Try pressing really slow, like once per 2-3 seconds. At release nothing seems to happen. Now try pressing at a faster rate while watching the numbers. I can hit one button 5-times rapidly (and see the counter increase by 5), I can do likewise for the other button and see the same increase on its output.
- You may think the sketch hiccups now and then. Be careful you're not accidentally missing -or- adding a valid press cycle. Give it a thorough test and I think you'll agree this code does the job.
Summary
We've seen how combining a Timer-ISR with a Button-ISR provides adaptive Button Debounce processing. Performance snapshots confirm bounce-block action and button-cycle separation. A downloadable demo-sketch rounds out proof for the concept.
I stumbled onto this debounce approach while developing another project. Its meant for use-cases of one button pressed at a time and separate button ISR's. For more buttons, add more ISR's.
See below to Download the Sketch.
Have fun debouncing your buttons,
Lee
Button-Debounce_Uno.zip CRC: --> 4 F 6 B D 3 4 3
Created: Nov 15, 2024 DISCLAIMER |