Skip to content

Instantly share code, notes, and snippets.

@jorticus
Created June 5, 2023 05:00
Show Gist options
  • Save jorticus/36c14c1061682e0349005b203dfc6e7c to your computer and use it in GitHub Desktop.
Save jorticus/36c14c1061682e0349005b203dfc6e7c to your computer and use it in GitHub Desktop.
Arduino C++ Button Debouncing Template Helper
#include <functional>
template <int _pin, uint8_t _level = HIGH>
struct Btn {
public:
static constexpr int pin = _pin;
static constexpr uint8_t level = _level;
};
// Variadic buttons template
// Usage:
// Buttons<Btn<BTN1_PIN>, Btn<BTN1_PIN>> buttons;
// if (buttons[0]) { ... }
template <typename ... buttons>
class Buttons {
typedef std::function<void(int)> onButton_t;
private:
static constexpr int N = sizeof...(buttons);
int pins[N] = { buttons::pin... };
uint8_t levels[N] = { buttons::level... };
bool states[N] = { 0 };
uint32_t ts[N] = { 0 };
onButton_t cb_onButtonPress;
onButton_t cb_onButtonRelease;
public:
Buttons() :
cb_onButtonPress(),
cb_onButtonRelease()
{ }
// Initialize button GPIOs
void Setup() {
for (int i = 0; i < N; i++) {
pinMode(pins[i], INPUT);
}
}
// De-bounce buttons
// https://pubweb.eng.utah.edu/~cs5780/debouncing.pdf
void Process(int press_interval_ms = 10, int release_interval_ms = 10) {
for (int i = 0; i < N; i++) {
auto& state = states[i];
auto& lastTime = ts[i];
const bool currState = (digitalRead(pins[i]) == levels[i]) ? true : false;
if (currState == state) {
lastTime = millis() + ((state) ?
press_interval_ms : // Press counter
release_interval_ms); // Release counter
}
else {
// State has changed - wait for signal to become stable (rollover-safe)
if ((millis() - lastTime) >= 0) {
state = currState;
if (state) {
if (cb_onButtonPress) cb_onButtonPress(i);
} else {
if (cb_onButtonRelease) cb_onButtonRelease(i);
}
// Reset the timer
lastTime = millis() + ((state) ?
press_interval_ms : // Press counter
release_interval_ms); // Release counter
}
}
}
}
void onButtonPress(onButton_t cb) {
cb_onButtonPress = cb;
}
void onButtonRelease(onButton_t cb) {
cb_onButtonRelease = cb;
}
// The current button state
bool operator[] (int i) {
if (i >= 0 && i < N) {
return states[i];
} else {
return false;
}
}
};
// Convenience wrapper - assumes all buttons are active HIGH
// Usage:
// Buttons<BTN1_PIN, BTN2_PIN>
// template <int ... pin>
// class Buttons : public Buttons<Btn<pin..., HIGH>> { };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment