From 668247708c7b61328ab9dd96eb4e06de0f98affb Mon Sep 17 00:00:00 2001 From: Bryce Boe Date: Wed, 4 Dec 2024 23:43:16 -0800 Subject: [PATCH] Fix bug where isPressed returns True a second time As currently implemented, if the button is pressed and immediately released before the next `loop` call, e.g., due to a blocking action like a `delay` call, the subsequent `loop` call will still consider the button as pressed. The same behavior occurs with unpressed when holding the button, and only momentarily releasing it. To fix this issue, we need to do away with the `previousSteadyState` variable so that it does not require two calls to `loop` in order to change the state. --- src/ezButton.cpp | 38 ++++++++++++++------------------------ src/ezButton.h | 10 ++++++++-- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/ezButton.cpp b/src/ezButton.cpp index 2d05825..4cf502d 100644 --- a/src/ezButton.cpp +++ b/src/ezButton.cpp @@ -38,6 +38,7 @@ ezButton::ezButton(int pin, int mode) { debounceTime = 0; count = 0; countMode = COUNT_FALLING; + transition = NEITHER; if (mode == INTERNAL_PULLUP || mode == INTERNAL_PULLDOWN) { pinMode(btnPin, mode); @@ -54,9 +55,8 @@ ezButton::ezButton(int pin, int mode) { unpressedState = HIGH; } - previousSteadyState = digitalRead(btnPin); - lastSteadyState = previousSteadyState; - lastFlickerableState = previousSteadyState; + lastSteadyState = digitalRead(btnPin); + lastFlickerableState = lastSteadyState; lastDebounceTime = 0; } @@ -74,17 +74,11 @@ int ezButton::getStateRaw(void) { } bool ezButton::isPressed(void) { - if(previousSteadyState == unpressedState && lastSteadyState == pressedState) - return true; - else - return false; + return transition == PRESSED; } bool ezButton::isReleased(void) { - if(previousSteadyState == pressedState && lastSteadyState == unpressedState) - return true; - else - return false; + return transition == UNPRESSED; } void ezButton::setCountMode(int mode) { @@ -116,25 +110,21 @@ void ezButton::loop(void) { lastFlickerableState = currentState; } - if ((currentTime - lastDebounceTime) >= debounceTime) { + if ((currentTime - lastDebounceTime) >= debounceTime && currentState != lastSteadyState) { // whatever the reading is at, it's been there for longer than the debounce // delay, so take it as the actual current state: - // save the the steady state - previousSteadyState = lastSteadyState; + // save the the steady state and set the transition lastSteadyState = currentState; - } + transition = currentState == pressedState ? PRESSED : UNPRESSED; - if(previousSteadyState != lastSteadyState){ if(countMode == COUNT_BOTH) count++; - else if(countMode == COUNT_FALLING){ - if(previousSteadyState == HIGH && lastSteadyState == LOW) - count++; - } - else if(countMode == COUNT_RISING){ - if(previousSteadyState == LOW && lastSteadyState == HIGH) - count++; - } + else if(countMode == COUNT_FALLING && currentState == LOW) + count++; + else if(countMode == COUNT_RISING && currentState == HIGH) + count++; + } else { + transition = NEITHER; } } diff --git a/src/ezButton.h b/src/ezButton.h index 8e4eeee..0872f69 100644 --- a/src/ezButton.h +++ b/src/ezButton.h @@ -49,6 +49,12 @@ #define EXTERNAL_PULLUP 0xFE #define EXTERNAL_PULLDOWN 0xFF +enum Transition : byte { + NEITHER, + PRESSED, + UNPRESSED +}; + class ezButton { private: @@ -59,9 +65,9 @@ class ezButton int pressedState; // the state when the button is considered pressed int unpressedState; // the state when the button is considered unpressed - int previousSteadyState; // the previous steady state from the input pin, used to detect pressed and released event - int lastSteadyState; // the last steady state from the input pin + int lastSteadyState; // the last steady state from the input pin, used to detect pressed and released event int lastFlickerableState; // the last flickerable state from the input pin + Transition transition; unsigned long lastDebounceTime; // the last time the output pin was toggled