/*
Forum: https://forum.arduino.cc/t/need-beginner-help-with-debounce-logic/1425853
Wokwi: https://wokwi.com/projects/453676692512664577
ec2021
Example for reading buttons with "acceleration" of returned
(btn.down() == True)
AccelBtnClass provides the ability to set a minimum and maximum interval
to receive true from the function btn.down() while the button is pressed.
The time to return true is decremented by a given value "decrement" in btn.init(...).
Once the button has been released the interval is reset to maxInterval
again.
2026/01/20
A counter has been added that is incremented and decremented by pressing the two
buttons. To further speed up the process, the increment and decrement values are
calculated based on the time the respective button is held down.
*/
constexpr byte buttonPin[] {2, 3};
constexpr int buttons = sizeof(buttonPin) / sizeof(buttonPin[0]);
class AccelBtnClass {
private:
byte pin;
byte state;
byte lastState;
unsigned long lastChange;
unsigned long lastPressTime;
unsigned long lastCheckTime;
unsigned long startDownTime;
unsigned long accelInterval;
unsigned long minInterval;
unsigned long maxInterval;
unsigned long decrement;
public:
init(byte p, unsigned long minIntv, unsigned long maxIntv, unsigned long decr) {
pin = p;
pinMode(pin, INPUT_PULLUP);
lastPressTime = 0;
lastCheckTime = 0;
minInterval = min(minIntv, maxIntv);
maxInterval = max(minIntv, maxIntv);
accelInterval = maxInterval;
decrement = decr;
}
unsigned long getLastPressTime() {
return lastPressTime;
};
unsigned long getLastCheckTime() {
return lastCheckTime;
};
void reset() {
lastPressTime = 0;
}
boolean isReleased() {
return state;
}
unsigned long getDownInterval() {
return lastCheckTime - startDownTime;
}
boolean pressed() {
byte actState = digitalRead(pin);
if (actState != lastState) {
lastChange = millis();
lastState = actState;
};
if (actState != state && millis() - lastChange > 30) {
state = actState;
if (!state) lastPressTime = lastChange;
return !state;
}
return false;
}
boolean down() {
if (!digitalRead(pin)) {
if (millis() - lastCheckTime >= accelInterval) {
state = LOW;
lastCheckTime = millis();
if (accelInterval == maxInterval) {
startDownTime = lastCheckTime;
}
if (accelInterval >= minInterval + decrement) {
accelInterval -= decrement;
}
return true;
} else {
return false;
}
} else {
accelInterval = maxInterval;
state = HIGH;
return false;
}
}
};
AccelBtnClass button[buttons];
long counter = 0;
long increment = 1;
long decrement = 1;
void setup() {
Serial.begin(115200);
for (int i = 0; i < buttons; i++) {
// Pin No, minInterval, maxInterval, decrement
button[i].init(buttonPin[i], 50, 300, 50);
}
}
void loop() {
doSomething();
}
void doSomething() {
if (button[0].down()) {
counter += increment;
Serial.print(counter);
Serial.print("\t\t");
Serial.println(increment);
// The following line changes the increment depending
// on the time the button is held down
increment = pow(2, button[0].getDownInterval() / 1000);
}
if (button[1].down()) {
counter -= decrement;
Serial.print(counter);
Serial.print("\t\t");
Serial.println(decrement);
// The following line changes the decrement depending
// on the time the button is held down
decrement = pow(2, button[1].getDownInterval() / 1000);
}
// The following lines set the increment to 1
// when button[0] is not down
if (button[0].isReleased()) {
increment = 1;
}
// The following lines set the decrement to 1
// when button[1] is not down
if (button[1].isReleased()) {
decrement = 1;
}
}