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:
This is a tiny little clicky 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