Skip to content

Instantly share code, notes, and snippets.

@skull-squadron
Created March 16, 2025 09:54
Show Gist options
  • Save skull-squadron/f8a9307b4bec00609401530b88d0866d to your computer and use it in GitHub Desktop.
Save skull-squadron/f8a9307b4bec00609401530b88d0866d to your computer and use it in GitHub Desktop.
[Arduino] Properly debounced button class
// Arduino proper switch debouncing
// Based on https://docs.arduino.cc/built-in-examples/digital/Debounce
//
// Button libraries that do not work properly:
// - Button - doesn't debounce
// - EZButton - doesn't debounce
// - ezButton - laggy
// Arduino Nano 5V
// 5V pin -> Vcc
// Gnd pin -> Gnd
// D2 pin -> SW0 -> 10K resistor -> Gnd
// D10 pin -> 20K resistor -> BJT NPN Collector (i.e, S9013)
// SW0 other side -> Vcc
// LED+ -> BJT NPN Base
// LED- -> Gnd
// BJT NPN Emitter -> 220 ohm resitor -> Vcc
#define __ASSERT_USE_STDERR
#include <assert.h>
const unsigned long SERIAL_BAUD = 250000;
void serial_begin() {
static volatile bool did = false;
if (!did) Serial.begin(SERIAL_BAUD);
did = true;
}
void __assert(const char *func, const char *file, int lineno, const char *sexp) {
serial_begin();
Serial.print("Assertion failed: ");
Serial.print(sexp);
Serial.print(' ');
Serial.print(func);
Serial.print(' ');
Serial.print(file);
Serial.print(':');
Serial.println(lineno);
Serial.flush();
abort();
}
const int SW0_PIN = 10;
const int LED_PIN = 2;
bool led = false;
class Button {
public:
Button(int pin) : Button(pin, 50) {}
Button(int pin, unsigned long debounce_delay) : _pin(pin) {
setDebounceDelay(debounce_delay);
pinMode(pin, INPUT_PULLUP);
}
bool isPressed() {
bool reading = read();
if (_lastButtonState != reading) {
_lastButtonState = reading;
_lastDebounceTime = millis();
}
if (millis() - _lastDebounceTime > _debounce_delay) {
if (_buttonState != reading) {
_buttonState = reading;
return reading;
}
}
return false;
}
void setDebounceDelay(unsigned long delay) {
assert(delay >= 2); // Must be >= 2 ms because humans can't type that fast
_debounce_delay = delay;
}
private:
int _pin;
bool _buttonState = false;
bool _lastButtonState = false;
unsigned long _lastDebounceTime = millis();
unsigned long _debounce_delay; // ms
bool read() {
return digitalRead(_pin) == HIGH;
}
};
Button sw0(SW0_PIN);
void setup() {
serial_begin();
pinMode(LED_PIN, OUTPUT);
// Flash the LED twice to show it's working
digitalWrite(LED_PIN, HIGH);
delay(250);
digitalWrite(LED_PIN, LOW);
delay(250);
digitalWrite(LED_PIN, HIGH);
delay(250);
digitalWrite(LED_PIN, LOW);
Serial.println("setup");
}
void sw0Pressed() {
Serial.println("pressed");
led = !led;
digitalWrite(LED_PIN, led);
delay(50);
}
void loop() {
if (sw0.isPressed())
sw0Pressed();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment