-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
120 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ | |
* EasyButton Button0AtPin2(true); | ||
* The macros INT0_PIN and INT1_PIN are set after the include. | ||
* | ||
* Copyright (C) 2018-2022 Armin Joachimsmeyer | ||
* Copyright (C) 2018-2024 Armin Joachimsmeyer | ||
* [email protected] | ||
* | ||
* This file is part of EasyButtonAtInt01 https://github.com/ArminJo/EasyButtonAtInt01. | ||
|
@@ -26,7 +26,7 @@ | |
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
* See the See the See the GNU General Public License for more details. | ||
* See the GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>. | ||
|
@@ -35,10 +35,10 @@ | |
#ifndef _EASY_BUTTON_AT_INT01_H | ||
#define _EASY_BUTTON_AT_INT01_H | ||
|
||
#define VERSION_EASY_BUTTON "3.3.2" | ||
#define VERSION_EASY_BUTTON "3.4.0" | ||
#define VERSION_EASY_BUTTON_MAJOR 3 | ||
#define VERSION_EASY_BUTTON_MINOR 3 | ||
#define VERSION_EASY_BUTTON_PATCH 2 | ||
#define VERSION_EASY_BUTTON_MINOR 4 | ||
#define VERSION_EASY_BUTTON_PATCH 0 | ||
// The change log is at the bottom of the file | ||
|
||
/* | ||
|
@@ -63,6 +63,10 @@ | |
* | ||
*/ | ||
|
||
// Return values for button state | ||
#define BUTTON_IS_ACTIVE true | ||
#define BUTTON_IS_INACTIVE false | ||
|
||
/* | ||
* Enable this if you buttons are active high. | ||
*/ | ||
|
@@ -291,6 +295,7 @@ class EasyButton { | |
bool checkForDoublePress(uint16_t aDoublePressDelayMillis = EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS); | ||
|
||
bool readButtonState(); | ||
bool getButtonStateIsActive(); // get private member | ||
bool readDebouncedButtonState(); | ||
bool updateButtonState(); | ||
uint16_t updateButtonPressDuration(); // Updates the ButtonPressDurationMillis by polling, since this cannot be done by interrupt. | ||
|
@@ -304,7 +309,6 @@ class EasyButton { | |
void handleINT01Interrupts(); // internal use only | ||
|
||
bool LastBounceWasChangeToInactive; // Internal state, reflects actual reading with spikes and bouncing. Negative logic: true / active means button pin is LOW | ||
volatile bool ButtonStateIsActive; // State at last change. Negative logic: true / active means button pin is LOW. If last press duration < BUTTON_DEBOUNCING_MILLIS it holds wrong value (true instead of false) :-( | ||
volatile bool ButtonToggleState; // Toggle is on press, not on release - initial value is false | ||
|
||
/* | ||
|
@@ -351,6 +355,13 @@ class EasyButton { | |
#if defined(USE_BUTTON_1) | ||
static EasyButton *sPointerToButton1ForISR; | ||
#endif | ||
|
||
private: | ||
/* | ||
* If last press duration < BUTTON_DEBOUNCING_MILLIS it holds wrong value (true instead of false), therefore it is private. | ||
* To get current state, use readButtonState(). | ||
*/ | ||
volatile bool ButtonStateIsActive; // State at last change. Negative logic: true / active means button pin is LOW. | ||
}; | ||
// end of class definition | ||
|
||
|
@@ -370,9 +381,12 @@ void __attribute__ ((weak)) handleINT1Interrupt(); | |
|
||
#endif // defined(__AVR__) | ||
|
||
/* | ||
* Version 3.3.2 - 9/2022 | ||
/* Version 3.4.1 - 12/2023 | ||
* - Avoid wrong double press detection if calling checkForDoublePress() after release of button. | ||
* | ||
* Version 3.4.0 - 10/2023 | ||
* - Added NO_INITIALIZE_IN_CONSTRUCTOR macro to enable late initializing. | ||
* - ButtonStateIsActive is now private, since it is not reliable after bouncing. Use readButtonState() or readDebouncedButtonState() instead. | ||
* | ||
* Version 3.3.1 - 2/2022 | ||
* - Avoid mistakenly double press detection after boot. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
* #include "EasyButtonAtInt01.hpp" | ||
* EasyButton Button0AtPin2(true); | ||
* | ||
* Copyright (C) 2018-2022 Armin Joachimsmeyer | ||
* Copyright (C) 2018-2024 Armin Joachimsmeyer | ||
* [email protected] | ||
* | ||
* This file is part of EasyButtonAtInt01 https://github.com/ArminJo/EasyButtonAtInt01. | ||
|
@@ -28,7 +28,7 @@ | |
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
* See the See the See the GNU General Public License for more details. | ||
* See the GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/gpl.html>. | ||
|
@@ -42,7 +42,7 @@ | |
* - USE_BUTTON_1 Enables code for button at INT1 (pin3 on 328P, PA3 on ATtiny167, PCINT0 / PCx for ATtinyX5). | ||
* - INT1_PIN It overrides the usage of pin at the processors INT1 pin. Thus, it is the pin number of the pin for button 1 to use with Pin Change Interrupts. | ||
* - NO_INITIALIZE_IN_CONSTRUCTOR Disables the auto initializing in all constructors without the aIsButtonAtINT0 parameter. | ||
* - BUTTON_IS_ACTIVE_HIGH Enable this if you buttons are active high. | ||
* - BUTTON_IS_ACTIVE_HIGH Enable this if your buttons are active high. | ||
* - USE_ATTACH_INTERRUPT This forces use of the arduino function attachInterrupt(). It is required if you get the error "multiple definition of __vector_1". | ||
* - NO_BUTTON_RELEASE_CALLBACK Disables the code for release callback. This saves 2 bytes RAM and 64 bytes program memory. | ||
* - BUTTON_DEBOUNCING_MILLIS With this you can adapt to the characteristic of your button. Default is 50. | ||
|
@@ -73,6 +73,12 @@ | |
* | ||
*/ | ||
|
||
#if defined(TRACE) | ||
#define LOCAL_TRACE | ||
#else | ||
//#define LOCAL_TRACE // This enables trace output only for this file | ||
#endif | ||
|
||
// For external measurement of code timing | ||
//#define MEASURE_EASY_BUTTON_INTERRUPT_TIMING | ||
#if defined(MEASURE_EASY_BUTTON_INTERRUPT_TIMING) || defined(BUTTON_LED_FEEDBACK) | ||
|
@@ -334,7 +340,9 @@ void EasyButton::init(bool aIsButtonAtINT0) { | |
} | ||
|
||
/* | ||
* Negative logic for readButtonState() true means button pin is LOW, if button is active low (default) | ||
* if NOT defined BUTTON_IS_ACTIVE_HIGH we have negative logic for readButtonState()! | ||
* In this case BUTTON_IS_ACTIVE (true) means button pin is LOW | ||
* @return BUTTON_IS_ACTIVE (true) or BUTTON_IS_INACTIVE (false) | ||
*/ | ||
bool EasyButton::readButtonState() { | ||
#if defined(USE_BUTTON_0) && not defined(USE_BUTTON_1) | ||
|
@@ -372,13 +380,20 @@ bool EasyButton::readButtonState() { | |
|
||
// @formatter:on | ||
|
||
bool EasyButton::getButtonStateIsActive() { | ||
return ButtonStateIsActive; | ||
|
||
} | ||
/* | ||
* Returns stored state if in debouncing period otherwise current state of button | ||
* If button is in bouncing period, we do not know button state, so it is only save to return BUTTON_IS_INACTIVE | ||
* @return BUTTON_IS_ACTIVE (true) or BUTTON_IS_INACTIVE (false) | ||
*/ | ||
bool EasyButton::readDebouncedButtonState() { | ||
// Check for bouncing period | ||
// Check if we are in bouncing period | ||
if (millis() - ButtonLastChangeMillis <= BUTTON_DEBOUNCING_MILLIS) { | ||
return ButtonStateIsActive; | ||
// If button is in bouncing period, we do not know button state, so it is only save to return BUTTON_IS_INACTIVE | ||
return BUTTON_IS_INACTIVE; | ||
} | ||
return readButtonState(); | ||
} | ||
|
@@ -390,7 +405,7 @@ bool EasyButton::readDebouncedButtonState() { | |
bool EasyButton::updateButtonState() { | ||
noInterrupts(); | ||
if (readDebouncedButtonState() != ButtonStateIsActive) { | ||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
if (LastBounceWasChangeToInactive) { | ||
Serial.print(F("Updated button state, assume last button press was shorter than debouncing period of ")); | ||
Serial.print(BUTTON_DEBOUNCING_MILLIS); | ||
|
@@ -430,6 +445,7 @@ uint16_t EasyButton::updateButtonPressDuration() { | |
/* | ||
* Used for long button press recognition, while button is still pressed! | ||
* !!! Consider to use button release callback handler and check the ButtonPressDurationMillis | ||
* You may use EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS which is 400 | ||
* returns EASY_BUTTON_LONG_PRESS_DETECTED, EASY_BUTTON_LONG_PRESS_STILL_POSSIBLE and EASY_BUTTON_LONG_PRESS_ABORT | ||
*/ | ||
uint8_t EasyButton::checkForLongPress(uint16_t aLongPressThresholdMillis) { | ||
|
@@ -474,6 +490,8 @@ bool EasyButton::checkForLongPressBlocking(uint16_t aLongPressThresholdMillis) { | |
* Double press detection by computing difference between current (active) timestamp ButtonLastChangeMillis | ||
* and last release timestamp ButtonReleaseMillis. | ||
* !!!Works only reliable if called early in ButtonPress callback function!!! | ||
* !!!Do not call it in ButtonRelease callback function, it makes no sense!!! | ||
* You may use EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS which is 400 | ||
* @return true if double press detected. | ||
*/ | ||
bool EasyButton::checkForDoublePress(uint16_t aDoublePressDelayMillis) { | ||
|
@@ -485,7 +503,14 @@ bool EasyButton::checkForDoublePress(uint16_t aDoublePressDelayMillis) { | |
if (ButtonReleaseMillis != 0) { | ||
// because ButtonReleaseMillis is initialized with 0 milliseconds, which is interpreted as the first press happened at the beginning of boot. | ||
unsigned long tReleaseToPressTimeMillis = ButtonLastChangeMillis - ButtonReleaseMillis; | ||
return (tReleaseToPressTimeMillis <= aDoublePressDelayMillis); | ||
#if defined(LOCAL_TRACE) | ||
Serial.print(F("DoublePressDelayMillis=")); | ||
Serial.print(aDoublePressDelayMillis); | ||
Serial.print(F(", ReleaseToPressTimeMillis=")); | ||
Serial.println(tReleaseToPressTimeMillis); | ||
#endif | ||
// tReleaseToPressTimeMillis != 0 adds 4 bytes, but avoids wrong double press detection if calling this function after release of button | ||
return (tReleaseToPressTimeMillis != 0 && tReleaseToPressTimeMillis <= aDoublePressDelayMillis); | ||
} | ||
return false; | ||
} | ||
|
@@ -533,7 +558,7 @@ void EasyButton::handleINT01Interrupts() { | |
tCurrentButtonStateIsActive = !tCurrentButtonStateIsActive; // negative logic for tCurrentButtonStateIsActive! true means button pin is LOW | ||
#endif | ||
|
||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
Serial.print(tCurrentButtonStateIsActive); | ||
Serial.print('-'); | ||
#endif | ||
|
@@ -579,7 +604,7 @@ void EasyButton::handleINT01Interrupts() { | |
if (tCurrentButtonStateIsActive && LastBounceWasChangeToInactive) { | ||
// We assume we had a very short press before (or a strange spike), which was handled as a bounce. -> must adjust last button state | ||
ButtonStateIsActive = false; | ||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
Serial.println(F("Preceding short press detected, which was handled as bounce")); | ||
#endif | ||
|
||
|
@@ -588,7 +613,7 @@ void EasyButton::handleINT01Interrupts() { | |
* tCurrentButtonStateIsActive == OldButtonStateIsActive. We had an interrupt, but nothing seems to have changed -> spike | ||
* Do nothing, ignore and wait for next interrupt | ||
*/ | ||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
Serial.println(F("Spike")); | ||
#endif | ||
} | ||
|
@@ -601,7 +626,7 @@ void EasyButton::handleINT01Interrupts() { | |
*/ | ||
ButtonLastChangeMillis = tMillis; | ||
LastBounceWasChangeToInactive = false; | ||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
Serial.println(F("Change")); | ||
#endif | ||
ButtonStateIsActive = tCurrentButtonStateIsActive; | ||
|
@@ -627,7 +652,7 @@ void EasyButton::handleINT01Interrupts() { | |
*/ | ||
if (!readButtonState()) { | ||
// button released now, so maintain status | ||
#if defined(TRACE) | ||
#if defined(LOCAL_TRACE) | ||
Serial.println(F("Button release during callback processing detected.")); | ||
#endif | ||
ButtonStateIsActive = false; | ||
|
@@ -657,7 +682,7 @@ void EasyButton::handleINT01Interrupts() { | |
*/ | ||
if (readButtonState()) { | ||
// button activated now, so maintain status | ||
# if defined(TRACE) | ||
# if defined(LOCAL_TRACE) | ||
Serial.println(F("Button active after callback processing detected.")); | ||
# endif | ||
ButtonStateIsActive = true; | ||
|
@@ -736,5 +761,9 @@ ISR(INT1_vect) | |
# endif | ||
#endif // not defined(USE_ATTACH_INTERRUPT) | ||
|
||
#if defined(LOCAL_TRACE) | ||
#undef LOCAL_TRACE | ||
#endif | ||
|
||
#endif // defined(__AVR__) | ||
#endif // _EASY_BUTTON_AT_INT01_HPP |
Oops, something went wrong.