Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 663e251

Browse files
committed
Add MultiPurposeButton
1 parent 2f6c742 commit 663e251

File tree

3 files changed

+211
-5
lines changed

3 files changed

+211
-5
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* This examples shows how to use the MultiPurposeButton class to detect
3+
* different kinds of push button events.
4+
*
5+
* @boards AVR, AVR USB, Nano Every, Nano 33 IoT, Nano 33 BLE, Due, Teensy 3.x, ESP8266, ESP32
6+
*
7+
* Connections
8+
* -----------
9+
*
10+
* - 2: Momentary push button (other pin to ground)
11+
*
12+
* The internal pull-up resistor will be enabled.
13+
*
14+
* Behavior
15+
* --------
16+
*
17+
* - Short presses, long presses, multiple presses, etc. are printed to the
18+
* Serial monitor.
19+
*
20+
* Written by PieterP, 2022-05-07
21+
* https://github.com/tttapa/Arduino-Helpers
22+
*/
23+
24+
#include <Arduino_Helpers.h> // https://github.com/tttapa/Arduino-Helpers
25+
26+
#include <AH/Hardware/MultiPurposeButton.hpp>
27+
28+
// Create a Button object that reads a push button connected to pin 2:
29+
MultiPurposeButton btn{2};
30+
31+
void setup() {
32+
Serial.begin(115200);
33+
btn.setLongPressDelay(1000);
34+
btn.setMultiPressDelay(400);
35+
btn.begin();
36+
}
37+
38+
void loop() {
39+
auto longPressTime = btn.getLongPressedTime();
40+
switch (btn.update()) {
41+
case btn.None: break;
42+
case btn.PressStart: Serial << "Pressed" << endl; break;
43+
case btn.ShortPressRelease:
44+
Serial << "Released after short press" << endl;
45+
break;
46+
case btn.LongPress: Serial << "Long press" << endl; break;
47+
case btn.LongPressRelease:
48+
Serial << "Released after long press (" << longPressTime << " ms)"
49+
<< endl;
50+
break;
51+
case btn.MultiPress:
52+
Serial << "Consecutive presses: " << btn.getCurrentMultiPressCount() + 1
53+
<< endl;
54+
break;
55+
case btn.MultiPressDone:
56+
Serial << "Counted " << btn.getMultiPressCount() + 1
57+
<< " consecutive presses" << endl;
58+
break;
59+
}
60+
}

src/AH/Hardware/Button.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,20 @@ class Button {
7373
* States:
7474
* HIGH ────────────────┐ ┌─────────────────
7575
* LOW └──────────────────┘
76-
* RELEASED FALLING PRESSED RISING
76+
* Released Falling Pressed Rising
7777
* ```
7878
*
79-
* @return The state of the button, either Button::PRESSED,
80-
* Button::RELEASED, Button::FALLING or Button::RISING.
79+
* @return The state of the button, either Button::Pressed,
80+
* Button::Released, Button::Falling or Button::Rising.
8181
*/
8282
State update();
8383

8484
/**
8585
* @brief Get the state of the button, without updating it.
8686
* Returns the same value as the last call to @ref update.
8787
*
88-
* @return The state of the button, either Button::PRESSED,
89-
* Button::RELEASED, Button::FALLING or Button::RISING.
88+
* @return The state of the button, either Button::Pressed,
89+
* Button::Released, Button::Falling or Button::Rising.
9090
*/
9191
State getState() const;
9292

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**/
2+
3+
#pragma once
4+
5+
#include <AH/Settings/Warnings.hpp>
6+
AH_DIAGNOSTIC_WERROR() // Enable errors on warnings
7+
8+
#include "Button.hpp"
9+
10+
BEGIN_AH_NAMESPACE
11+
12+
/**
13+
* @brief Class for detecting short/long button presses and double clicks.
14+
*/
15+
class MultiPurposeButton {
16+
public:
17+
MultiPurposeButton(pin_t pin) : button(pin) {}
18+
19+
enum Event {
20+
None, ///< Nothing changed
21+
PressStart, ///< The button was just pressed
22+
ShortPressRelease, ///< The button was released after a short press
23+
LongPress, ///< The button has been pressed for some time
24+
LongPressRelease, ///< The button was released after a long press
25+
MultiPress, ///< The button was pressed in quick succession of
26+
///< the previous release.
27+
MultiPressDone, ///< The button has been released for long enough to
28+
///< rule out another MultiPress.
29+
};
30+
31+
/// @see @ref Button::begin()
32+
void begin() { button.begin(); }
33+
34+
/// Read the button state and return the @ref Event (if any).
35+
Event update() {
36+
Event event = None;
37+
auto now = millis();
38+
auto stableTime = button.stableTime(now);
39+
switch (button.update()) {
40+
case Button::Released: {
41+
if (multiPressCountNew > 0 && stableTime > multiPressDelay) {
42+
multiPressCount = multiPressCountNew;
43+
multiPressCountNew = 0;
44+
event = MultiPressDone;
45+
}
46+
} break;
47+
case Button::Falling: {
48+
event = (stableTime <= multiPressDelay) ? MultiPress //
49+
: PressStart;
50+
multiPressCountNew += event == MultiPress;
51+
} break;
52+
case Button::Pressed: {
53+
if (not longPress && stableTime >= longPressDelay) {
54+
event = LongPress;
55+
longPress = true;
56+
}
57+
} break;
58+
case Button::Rising: {
59+
event = longPress ? LongPressRelease : ShortPressRelease;
60+
longPress = false;
61+
} break;
62+
}
63+
return event;
64+
}
65+
66+
/// Get the number of times the button was pressed in quick succession
67+
/// (after MultiPressDone), this is the final count.
68+
uint8_t getMultiPressCount() const { return multiPressCount; }
69+
/// Get the number of times the button was pressed in quick succession,
70+
/// while the button is being pressed (before MultiPressDone).
71+
/// The count could still increase if the user keeps on pressing the button.
72+
uint8_t getCurrentMultiPressCount() const { return multiPressCountNew; }
73+
74+
/// Get the number of milliseconds after which a press is considered a long
75+
/// press.
76+
unsigned long getLongPressDelay() const { return longPressDelay; }
77+
/// Set the number of milliseconds after which a press is considered a long
78+
/// press.
79+
void setLongPressDelay(unsigned long longPressDelay) {
80+
this->longPressDelay = longPressDelay;
81+
}
82+
83+
/// Get the number of milliseconds between multipresses.
84+
unsigned long getMultiPressDelay() const { return multiPressDelay; }
85+
/// Set the number of milliseconds between multipresses.
86+
void setMultiPressDelay(unsigned long multiPressDelay) {
87+
this->multiPressDelay = multiPressDelay;
88+
}
89+
90+
/// @see @ref Button::previousBounceTime()
91+
unsigned long previousBounceTime() const {
92+
return button.previousBounceTime();
93+
}
94+
/// @see @ref Button::stableTime()
95+
unsigned long stableTime() const { return button.stableTime(); }
96+
/// @see @ref Button::stableTime(unsigned long)
97+
unsigned long stableTime(unsigned long now) const {
98+
return button.stableTime(now);
99+
}
100+
101+
/// Get the number of milliseconds the button has been pressed for. Returns
102+
/// 0 if the button is not currently pressed.
103+
unsigned long getPressedTime() const {
104+
return getButtonState() == Button::Pressed ? stableTime() : 0;
105+
}
106+
/// Get the number of milliseconds the button has been pressed for. Returns
107+
/// 0 if the button is not currently pressed or if the current press is not
108+
/// a long press (yet).
109+
unsigned long getLongPressedTime() const {
110+
return longPress ? stableTime() : 0;
111+
}
112+
113+
/// Return the name of the event as a string.
114+
static FlashString_t getName(Event ev) { return to_string(ev); }
115+
116+
/// @see @ref Button::getState()
117+
Button::State getButtonState() const { return button.getState(); }
118+
/// @see @ref Button::invert()
119+
void invert() { button.invert(); }
120+
121+
protected:
122+
Button button;
123+
unsigned long longPressDelay = 1000;
124+
unsigned long multiPressDelay = 400;
125+
bool longPress = false;
126+
uint8_t multiPressCountNew = 0;
127+
uint8_t multiPressCount = 0;
128+
129+
public:
130+
friend FlashString_t to_string(Event ev) {
131+
switch (ev) {
132+
case None: return F("None");
133+
case PressStart: return F("PressStart");
134+
case ShortPressRelease: return F("ShortPressRelease");
135+
case LongPress: return F("LongPress");
136+
case LongPressRelease: return F("LongPressRelease");
137+
case MultiPress: return F("MultiPress");
138+
case MultiPressDone: return F("MultiPressDone");
139+
}
140+
return F("<invalid>");
141+
}
142+
};
143+
144+
END_AH_NAMESPACE
145+
146+
AH_DIAGNOSTIC_POP()

0 commit comments

Comments
 (0)