-
Notifications
You must be signed in to change notification settings - Fork 1
/
Pushbutton.cpp
173 lines (148 loc) · 5.18 KB
/
Pushbutton.cpp
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "Pushbutton.h"
// constructor; takes arguments specifying whether to enable internal pull-up
// and the default state of the pin that the button is connected to
Pushbutton::Pushbutton(unsigned char pin, unsigned char pullUp, unsigned char defaultState)
{
_pin = pin;
_pullUp = pullUp;
_defaultState = defaultState;
gsdpState = 0;
gsdrState = 0;
gsdpPrevTimeMillis = 0;
gsdrPrevTimeMillis = 0;
initialized = false;
}
// wait for button to be pressed
void Pushbutton::waitForPress()
{
init(); // initialize if necessary
do
{
while (!_isPressed()); // wait for button to be pressed
delay(10); // debounce the button press
}
while (!_isPressed()); // if button isn't still pressed, loop
}
// wait for button to be released
void Pushbutton::waitForRelease()
{
init(); // initialize if necessary
do
{
while (_isPressed()); // wait for button to be released
delay(10); // debounce the button release
}
while (_isPressed()); // if button isn't still released, loop
}
// wait for button to be pressed, then released
void Pushbutton::waitForButton()
{
waitForPress();
waitForRelease();
}
// indicates whether button is pressed
boolean Pushbutton::isPressed()
{
init(); // initialize if necessary
return _isPressed();
}
// Uses a finite state machine to detect a single button press and returns
// true to indicate the press (false otherwise). It requires the button to be
// released for at least 15 ms and then pressed for at least 15 ms before
// reporting the press. This function handles all necessary debouncing and
// should be called repeatedly in a loop.
boolean Pushbutton::getSingleDebouncedPress()
{
unsigned long timeMillis = millis();
init(); // initialize if necessary
switch (gsdpState)
{
case 0:
if (!_isPressed()) // if button is released
{
gsdpPrevTimeMillis = timeMillis;
gsdpState = 1; // proceed to next state
}
break;
case 1:
if ((timeMillis - gsdpPrevTimeMillis >= 15) && !_isPressed()) // if 15 ms or longer has elapsed and button is still released
gsdpState = 2; // proceed to next state
else if (_isPressed())
gsdpState = 0; // button is pressed or bouncing, so go back to previous (initial) state
break;
case 2:
if (_isPressed()) // if button is now pressed
{
gsdpPrevTimeMillis = timeMillis;
gsdpState = 3; // proceed to next state
}
break;
case 3:
if ((timeMillis - gsdpPrevTimeMillis >= 15) && _isPressed()) // if 15 ms or longer has elapsed and button is still pressed
{
gsdpState = 0; // next state becomes initial state
return true; // report button press
}
else if (!_isPressed())
gsdpState = 2; // button is released or bouncing, so go back to previous state
break;
}
return false;
}
// Uses a finite state machine to detect a single button release and returns
// true to indicate the release (false otherwise). It requires the button to be
// pressed for at least 15 ms and then released for at least 15 ms before
// reporting the release. This function handles all necessary debouncing and
// should be called repeatedly in a loop.
boolean Pushbutton::getSingleDebouncedRelease()
{
unsigned int timeMillis = millis();
init(); // initialize if necessary
switch (gsdrState)
{
case 0:
if (_isPressed()) // if button is pressed
{
gsdrPrevTimeMillis = timeMillis;
gsdrState = 1; // proceed to next state
}
break;
case 1:
if ((timeMillis - gsdrPrevTimeMillis >= 15) && _isPressed()) // if 15 ms or longer has elapsed and button is still pressed
gsdrState = 2; // proceed to next state
else if (!_isPressed())
gsdrState = 0; // button is released or bouncing, so go back to previous (initial) state
break;
case 2:
if (!_isPressed()) // if button is now released
{
gsdrPrevTimeMillis = timeMillis;
gsdrState = 3; // proceed to next state
}
break;
case 3:
if ((timeMillis - gsdrPrevTimeMillis >= 15) && !_isPressed()) // if 15 ms or longer has elapsed and button is still released
{
gsdrState = 0; // next state becomes initial state
return true; // report button release
}
else if (_isPressed())
gsdrState = 2; // button is pressed or bouncing, so go back to previous state
break;
}
return false;
}
// initializes I/O pin for use as button inputs
void Pushbutton::init2()
{
if (_pullUp == PULL_UP_ENABLED)
pinMode(_pin, INPUT_PULLUP);
else
pinMode(_pin, INPUT); // high impedance
delayMicroseconds(5); // give pull-up time to stabilize
}
// button is pressed if pin state differs from default state
inline boolean Pushbutton::_isPressed()
{
return (digitalRead(_pin) == LOW) ^ (_defaultState == DEFAULT_STATE_LOW);
}