Skip to main content
ZombieMutex

30 results · ↑ ↓ navigate · Enter open · Esc close

All maker projects

Arduino / Embedded programming / Robotics

Arduino button debounce with millis()

Original design study · no physical hardware validation

A pushbutton produces short, noisy electrical transitions when it changes state. A naive handler may count one physical press several times. This sample accepts a press only after the input remains unchanged for 35 ms. The loop never calls delay().

The matching debounce state machine has automated host-side tests, including timer rollover. The Arduino sketch is a reference only: no physical board build, wiring or compilation is claimed.

By Jeffrey Monica

How the example works

  1. 01Use a pull-up input

    On Arduino boards supporting INPUT_PULLUP, connect the normally open pushbutton between digital pin 2 and GND. Pressed is LOW. Confirm your board's pinout before wiring.

  2. 02Track the most recent transition

    Every time the raw input changes, reset changedAt to the current millis(). This ensures bouncing delays the decision.

  3. 03Count only a stable press

    After the reading holds for 35 ms, update stablePressed. Toggle the LED on entering pressed state, not on release.

  4. 04Inspect edge cases

    Test a press with short bounce, a held press, release bounce, a second press, and millis() rollover. Change the interval based on actual switch measurements.

Reference code

Arduino C++. Read the limitations below before using this code with real hardware or network services.

Arduino C++
// Reference sketch: button on pin 2 to GND.
const uint8_t buttonPin = 2;
const uint8_t ledPin = LED_BUILTIN;
const unsigned long debounceMs = 35;
bool lastRaw = false;
bool stablePressed = false;
unsigned long changedAt = 0;
bool ledOn = false;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  const unsigned long now = millis();
  const bool rawPressed = digitalRead(buttonPin) == LOW;
  if (rawPressed != lastRaw) changedAt = now;
  if ((unsigned long)(now - changedAt) >= debounceMs &&
      rawPressed != stablePressed) {
    stablePressed = rawPressed;
    if (stablePressed) {
      ledOn = !ledOn;
      digitalWrite(ledPin, ledOn ? HIGH : LOW);
    }
  }
  lastRaw = rawPressed;
}

Test cases to check

  • A burst of alternating raw samples shorter than 35 ms produces zero accepted presses.
  • One sustained press produces one accepted event, even if it is held for a long time.
  • Release bounce does not create another event; the next stable press counts once.
  • The unsigned time subtraction handles the normal millis() wraparound pattern.

Limits & safety

  • Host-side tests validate the state transitions only; this is not a claim of compilation or a completed hardware test.
  • Voltage and pin mapping vary by Arduino board; check its electrical specifications.
  • 35 ms is a demonstration interval, not an empirically verified value for every switch.

Official references

Public conversation / GitHub Discussions

Discuss this article

Read and reply using GitHub Discussions. A GitHub account is needed to post. Comments are public and subject to GitHub moderation.

For privacy, the external giscus widget does not load until you choose to open it. Opening it connects your browser to giscus and GitHub. Do not post credentials or private project data.