Skip to content
BoKSA

Debouncing Inputs

Debouncing Inputs

Introduction

A mechanical switch does not go cleanly from off to on. Metal contacts bounce — they make and break several times in a few milliseconds. Your MCU reads 1-0-1-0-1 instead of one press. Debouncing turns that mess into a single reliable transition for your firmware.

Every button, limit switch, and relay feedback line in robotics and embedded kits needs debouncing — in hardware, software, or both.


What bounce looks like

1
2
3
4
Ideal button:     ______|‾‾‾‾‾‾|______

Real button:      ______|‾|_|‾|__|‾‾|___
                           ^ bounce region (ms scale)

If your loop counts rising edges, one press becomes five. If you toggle a menu on each edge, users hate you.

In plain terms

Bounce is like a door that slams shut three times before staying closed. Debouncing is waiting until the door stops shaking before you say "it's closed."


Hardware debouncing

Method Idea
RC filter Capacitor smooths voltage — slow rise/fall
Schmitt trigger Clean square output from noisy input
Dedicated IC MAX6816-style debouncers

Hardware debouncing costs parts and design time. Many student boards use software or internal pull-ups only.


Software debouncing

Time-based (simplest)

After seeing a change, wait (e.g. 20–50 ms) and read again. If still stable, accept the new state.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#define DEBOUNCE_MS 30

bool read_button_debounced(gpio_pin_t pin, uint32_t now_ms) {
    static bool last_stable = false;
    static uint32_t last_change_ms = 0;
    static bool last_raw = false;

    bool raw = gpio_read(pin);
    if (raw != last_raw) {
        last_change_ms = now_ms;
        last_raw = raw;
    }
    if ((now_ms - last_change_ms) >= DEBOUNCE_MS) {
        last_stable = raw;
    }
    return last_stable;
}

Use a millisecond tick from a timer ISR or RTOS — not delay() in the main path if you care about real-time.

Edge detection

Track stable state; only fire one event when stable changes from 0→1 (press) or 1→0 (release).

Count-based

Require N consecutive equal reads before accepting change — works without timestamps if loop is fast and regular.


Where debouncing lives in architecture

Layer Responsibility
Driver Raw GPIO read
Input module Debounce, edge detect
Application React to BUTTON_PRESSED event

Put debouncing in the input module — not scattered in UI and motor code. See Firmware architecture.


Internal pull-up / pull-down

Floating pins pick up noise and bounce worse. Enable internal pull-up (common for buttons to GND) or external resistor — see Basics of electronics.


Videos — other ways to learn

Arduino-focused debounce

How to debounce a button for Arduino

Concept animation

Switch Debouncing

Another approach

Debounce a Switch

Use an oscilloscope or logic analyzer from Lab tools for prototyping to see bounce on your actual switch.


Relevant topics


Starting points

  1. Log raw pin in a tight loop — press once, count transitions.
  2. Add 30 ms debounce — press once, count again.
  3. Scope button pin — measure bounce duration in ms.
  4. Refactor to button_pressed_event() used by one consumer.

Focus points

  • Debounce time depends on switch — tactile switches often 5–20 ms.
  • Do not debounce in ISR with long delays — use timestamps.
  • Limit switches on robots — debounce + safety redundancy.
  • Encoder wheels need different filtering — not this simple model.

Key points

  • Mechanical contacts bounce — firmware must filter or wait.
  • Software debounce with time or consecutive samples is standard on MCU.
  • One input module should own debouncing before application logic.
  • Pull resistors and tools help verify real-world behavior.