Behold the Debouncinator!

When you throw a switch or press a button, you expect that device to transition definitively and atomically from one state to the other. The switch is either open or it is closed, the button either is pressed or it is not. But in the course of those transitions, the metal contacts of the underlying switch can gain and lose connectivity many times. This is referred to as “bouncing”.

I grabbed some quick measurements with a USB scope (an MSO-19). This is a toggle switch:
switch

This is a tiny little clicky button:
button

If you are polling one of these switches with a microcontroller, you may wind up with short bursts of fluctuating measurements at each open and close. The fix for this is to “debounce” the switch by waiting for it to settle down before you decide that it has actually changed state.

#define DEBOUNCE_TIME 50 //milliseconds
unsigned long switchClosedTime = 0;
int state = HIGH;

void loop() {
  if (digitalRead(PIN) == LOW) {
    if (state == HIGH) {
      if (switchClosedTime == 0) {
        switchClosedTime = millis();
      } else if (millis() - switchClosedTime > DEBOUNCE_TIME) {
        state = LOW;
      }
    }
  } else {
    state = HIGH;
    switchClosedTime = 0;
  }
  if (state == LOW) {
    // The switch is flipped!  Do a thing!
  }
}

This is a basic debounce pattern. If the switch has been in the trigger state for a long time, then decide that it is done changing state. If you see it in the opposite state, then forget it, and start the measurement over when you next see it in the transition state.

I found myself implementing this same pattern in project after project, and eventually I wrote a little Arduino library for it (I used it in the NeoPixel Control Panel project). The Debouncinator makes it simple and convenient to debounce all of your inputs.

#include <Debouncinator.h>

Debouncinator db;

void setup() {
  // pin, initial state, trigger state
  db.init(5, HIGH, LOW);

  // same as 5, HIGH and LOW are the defaults
  db.init(6);

  // this pin triggers when it goes HIGH
  db.init(7, LOW, HIGH);
}

void loop() {
  if (db.read(5)) {
    // pin 5 has been debounced and is LOW
  }
  if (db.read(7)) {
    // pin 7 has been debounced and is HIGH
  }
  db.read(6);
  if (db.fired(6)) {
    // this will be true once for every time the pin
    // debounces to the trigger state
  }
}

You can find the Debouncinator on github: https://github.com/erickhammersmark/Debouncinator

Leave a comment