A robust 16-bit pattern-based button debouncing library for ESP32 microcontrollers using the Arduino framework.
- 16-bit pattern recognition for superior noise immunity
- Non-blocking operation - works with polling or hardware timer interrupts
- Advanced press pattern detection:
- Single press detection
- Double press detection with configurable time window
- Long press detection with configurable threshold
- Optional callback system for event-driven programming
- Multiple button support with efficient resource management
- Configurable timing parameters for different use cases
- Download the library as a ZIP file
- In Arduino IDE, go to Sketch → Include Library → Add .ZIP Library
- Select the downloaded ZIP file
- Restart Arduino IDE
- Copy the
debouncefolder to your project'slibdirectory - The library will be automatically detected and included
VCC ----o o---- GPIO_PIN
↑
Button
GPIO_PIN ----[10kΩ]---- GND
Pull-down
GPIO_PIN ----o o---- GND
↑
Button
VCC ----[10kΩ]---- GPIO_PIN
Pull-up
Or use internal pull-up:
// Library automatically configures INPUT_PULLUP for active LOW
Debounce16 button(PIN_BUTTON, LOW);#include <Debounce16.h>
const uint8_t PIN_BUTTON = 17;
const uint8_t PIN_LED = 15;
Debounce16 button(PIN_BUTTON, HIGH); // Active HIGH
void setup() {
pinMode(PIN_LED, OUTPUT);
}
void loop() {
static unsigned long lastUpdate = 0;
// Update button state every 1ms
if (millis() - lastUpdate >= 1) {
lastUpdate = millis();
button.update();
}
// Check for button press
if (button.isPressed()) {
digitalWrite(PIN_LED, !digitalRead(PIN_LED));
}
}#include <Debounce16.h>
const uint8_t PIN_BUTTON = 17;
Debounce16 button(PIN_BUTTON, HIGH);
hw_timer_t *timer = NULL;
void IRAM_ATTR onTimer() {
button.update(); // Update at precise 1ms intervals
}
void setup() {
// Configure timer for 1ms interrupts
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
}
void loop() {
if (button.isPressed()) {
// Handle button press
}
}#include <Debounce16.h>
Debounce16 button(17, HIGH);
void setup() {
button.enableDoublePressDetection(true);
button.setDoublePressWindow(300); // 300ms window
}
void loop() {
button.update();
if (button.isDoublePressed()) {
// Handle double press
}
// Or check click count
uint8_t clicks = button.getClickCount();
if (clicks == 1) {
// Single press
} else if (clicks == 2) {
// Double press
}
}#include <Debounce16.h>
Debounce16 button(17, HIGH);
void setup() {
button.enableLongPressDetection(true);
button.setLongPressThreshold(1000); // 1 second
}
void loop() {
button.update();
if (button.isLongPressed()) {
// Button is being held down
}
}#include <Debounce16.h>
Debounce16 button(17, HIGH);
void onButtonPress() {
Serial.println("Button pressed!");
}
void onButtonRelease() {
Serial.println("Button released!");
}
void setup() {
Serial.begin(115200);
button.onPress(onButtonPress);
button.onRelease(onButtonRelease);
}
void loop() {
button.update();
}Debounce16(uint8_t pin, bool activeLevel = HIGH)pin: GPIO pin number where button is connectedactiveLevel: Logic level when button is pressed (HIGH or LOW)
void update() // Update button state (call every 1ms)
bool isPressed() // Returns true on press event
bool isReleased() // Returns true on release event
bool isDown() // Returns true if button is held down
bool isUp() // Returns true if button is releasedvoid enableDoublePressDetection(bool enable = true)
void setDoublePressWindow(uint16_t windowMs)
void enableLongPressDetection(bool enable = true)
void setLongPressThreshold(uint16_t thresholdMs)bool isDoublePressed() // Returns true on double-press event
bool isLongPressed() // Returns true when long-press active
uint8_t getClickCount() // Returns current click countvoid onPress(void (*callback)())
void onRelease(void (*callback)())
void onDoublePress(void (*callback)())
void onLongPressStart(void (*callback)())
void onLongPressEnd(void (*callback)())The library uses a 16-bit shift register to store the last 16 button state readings. When update() is called (every 1ms), the register shifts left and adds the current button state.
A press is detected when the last 6 bits are all HIGH (button pressed) after being LOW:
0b0000000000111111 = 0x003F
This means the button must be consistently pressed for at least 6ms before being recognized.
A release is detected when the first 6 bits are all HIGH (button was pressed) and the rest are LOW:
0b1111110000000000 = 0xFC00
This provides excellent noise immunity while maintaining fast response times.
This library is based on:
- Jack Ganssle's "A Guide to Debouncing"
- Elliot Williams' "Ultimate Debouncer"
- Memory: ~44 bytes per button (with all features enabled)
- CPU: ~0.04% per button @ 240MHz (polling at 1ms intervals)
- Response Time: ~6ms from physical press to detection
This library is licensed under the MIT License. See the LICENSE file for details.
Copyright (c) 2025 Brooks
Contributions are welcome! Please feel free to submit pull requests or open issues.
- Based on research by Jack Ganssle
- Inspired by Elliot Williams' "Ultimate Debouncer"
- Implemented for ESP32 Arduino framework