-
Notifications
You must be signed in to change notification settings - Fork 127
Expand file tree
/
Copy pathbutton.h
More file actions
89 lines (80 loc) · 2.81 KB
/
button.h
File metadata and controls
89 lines (80 loc) · 2.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#pragma once
#include <functional>
template <uint8_t PIN, bool IDLELOW>
class Button
{
private:
// Constants
static constexpr uint32_t MS_DEBOUNCE = 25; // how long the switch must change state to be considered
static constexpr uint32_t MS_LONG = 500; // duration held to be considered a long press (repeats)
static constexpr uint32_t MS_MULTI_TIMEOUT = 500; // duration without a press before the short count is reset
static constexpr unsigned STATE_IDLE = 0b111;
static constexpr unsigned STATE_FALL = 0b100;
static constexpr unsigned STATE_RISE = 0b011;
static constexpr unsigned STATE_HELD = 0b000;
// State
uint32_t _lastCheck; // millis of last pin read
uint32_t _lastFallingEdge; // millis of last debounced falling edge
uint8_t _state; // pin history
bool _isLongPress; // true if last press was a long
uint8_t _longCount; // number of times long press has repeated
uint8_t _pressCount; // number of short presses before timeout
public:
// Callbacks
std::function<void ()>OnShortPress;
std::function<void ()>OnLongPress;
// Properties
uint8_t getCount() const { return _pressCount; }
uint8_t getLongCount() const { return _longCount; }
bool isPressed() const { return _state == STATE_HELD; }
bool isIdle() const { return _state == STATE_IDLE; }
Button() :
_lastCheck(0), _lastFallingEdge(0), _state(STATE_IDLE),
_isLongPress(false), _longCount(0), _pressCount(0)
{
pinMode(PIN, IDLELOW ? INPUT : INPUT_PULLUP);
}
// Call this in loop()
int update()
{
const uint32_t now = millis();
// Reset press count if it has been too long since last rising edge
if (now - _lastFallingEdge > MS_MULTI_TIMEOUT)
_pressCount = 0;
_state = (_state << 1) & 0b110;
_state |= digitalRead(PIN) ^ IDLELOW;
// If rising edge (release)
if (_state == STATE_RISE)
{
if (!_isLongPress)
{
DBGLN("Button short");
++_pressCount;
if (OnShortPress)
OnShortPress();
}
_isLongPress = false;
}
// Two low in a row
else if (_state == STATE_FALL)
{
_lastFallingEdge = now;
_longCount = 0;
}
// Three or more low in a row
else if (_state == STATE_HELD)
{
if (now - _lastFallingEdge > MS_LONG)
{
DBGLN("Button long %d", _longCount);
_isLongPress = true;
if (OnLongPress)
OnLongPress();
// Reset time so long can fire again
_lastFallingEdge = now;
_longCount++;
}
}
return MS_DEBOUNCE;
}
};