Electronics Basics · 12 November 2026
Button Debouncing Explained: Why One Press Counts as Three (and How to Fix It)
Mechanical switches bounce for a few milliseconds every press. Here's what that looks like on a scope, and three ways to debounce: a delay, millis(), and an RC filter.
Your counter sketch should add one for every press. Instead it jumps by two, sometimes three, and occasionally one. The code is right. The problem is physics: a push button is two pieces of metal slamming together, and they bounce.
What is switch bounce?
When the contacts meet, they don’t close once and stay closed. They hit, spring apart a tiny bit, hit again, and settle, all within roughly 1 to 20 milliseconds depending on the switch. On an oscilloscope the pin doesn’t go cleanly from HIGH to LOW; it looks like a short burst of noise before it settles.
A microcontroller reads its pins millions of times a second, so to it that burst is several clean presses in a row. Your counter faithfully counts every one.
The release bounces too, which is why an “on release” handler can misfire as well.
Fix 1: the delay (quick, blocking)
The simplest fix: when you see the first edge, wait longer than the bounce could last, then read again.
if (digitalRead(BTN) == LOW) { // pressed (pull-up wiring)
delay(30); // let it settle
if (digitalRead(BTN) == LOW) count++;
while (digitalRead(BTN) == LOW) {} // wait for release
}
It works, and it’s fine for a demo. The cost is that delay() freezes everything else: no LED animation, no sensor reads, nothing, for 30 ms per press. In anything real that matters.
Fix 2: millis() (non-blocking, the usual answer)
Instead of stopping, remember when the pin last changed, and only accept a new state once it has been stable for a while:
const unsigned long DEBOUNCE = 30; // ms
int stable = HIGH, lastRaw = HIGH;
unsigned long lastChange = 0;
void loop() {
int raw = digitalRead(BTN);
if (raw != lastRaw) { lastChange = millis(); lastRaw = raw; }
if (millis() - lastChange > DEBOUNCE && raw != stable) {
stable = raw;
if (stable == LOW) count++; // one clean press
}
// everything else keeps running
}
Every bounce resets the timer, so the state only updates after the contacts have been quiet for 30 ms. The loop never blocks. This is the pattern inside every “Bounce” library.
Fix 3: a capacitor (hardware debounce)
If you’d rather not debounce in code, or the signal feeds something with no code (a 555, a flip-flop, a clock pin), slow the edge down in hardware. With a pull-up in place, add a capacitor from the pin to ground:
- 10 kΩ pull-up + 100 nF capacitor → time constant RC = 1 ms
- The capacitor charges and discharges through the resistor, so the bounces get smoothed into one slow curve.
The catch is that a slow curve through the input threshold can itself trigger multiple times on a plain logic input. Pair it with a Schmitt trigger input (a 74HC14, or a microcontroller pin with hysteresis) and the ramp becomes one clean edge. That’s the textbook hardware debounce: RC plus Schmitt.
How long should the debounce time be?
| Switch type | Typical bounce | Safe debounce |
|---|---|---|
| Tactile push button | 1–5 ms | 10–20 ms |
| Toggle / rocker switch | 5–20 ms | 30–50 ms |
| Relay contacts | 10–50 ms | 50–100 ms |
Longer is safer but caps how fast a human can press: 50 ms allows 20 presses a second, which is more than anyone’s thumb manages.
Was this useful? The video version is on YouTube — a like or a comment there helps more people find it. New guides every week: subscribe to DigiCirq.
Topics: button debounce · debouncing arduino · switch bounce · millis debounce · RC debounce · contact bounce
Keep going
What Does a Pull-Up Resistor Do? (And Why Your Button Reads Random Values Without One)
A pull-up resistor gives an input pin a definite voltage when nothing drives it. Why a floating pin reads garbage, what value to use, and pull-up vs pull-down.
11 Nov 2026
How the 555 Timer Works: Three Resistors, Two Thirds, One Capacitor
Inside the 555: three resistors set ⅓ and ⅔ thresholds, two comparators watch a capacitor, a flip-flop makes it blink. Astable and monostable, with formulas.
13 Nov 2026