Skip to content

Commit 07f9012

Browse files
authored
Merge pull request #118 from IhorNehrutsa/debounce
Debouncing in one point. Thanks for the contribution - I like this change debouncing at the input only.
2 parents dc4dac2 + b5a883c commit 07f9012

File tree

3 files changed

+59
-52
lines changed

3 files changed

+59
-52
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
22
.idea/
33
.vscode
4-
_*
4+
_*
5+
build

src/OneButton.cpp

+27-36
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*
77
* @author Matthias Hertel, https://www.mathertel.de
88
* @Copyright Copyright (c) by Matthias Hertel, https://www.mathertel.de.
9+
* Ihor Nehrutsa, [email protected]
910
*
1011
* This work is licensed under a BSD style license. See
1112
* http://www.mathertel.de/License.aspx
@@ -36,7 +37,6 @@ OneButton::OneButton()
3637
*/
3738
OneButton::OneButton(const int pin, const boolean activeLow, const bool pullupActive)
3839
{
39-
// OneButton();
4040
_pin = pin;
4141

4242
if (activeLow) {
@@ -46,36 +46,36 @@ OneButton::OneButton(const int pin, const boolean activeLow, const bool pullupAc
4646
} else {
4747
// the button connects the input pin to VCC when pressed.
4848
_buttonPressed = HIGH;
49-
} // if
49+
}
5050

5151
if (pullupActive) {
5252
// use the given pin as input and activate internal PULLUP resistor.
5353
pinMode(pin, INPUT_PULLUP);
5454
} else {
5555
// use the given pin as input
5656
pinMode(pin, INPUT);
57-
} // if
57+
}
5858
} // OneButton
5959

6060

6161
// explicitly set the number of millisec that have to pass by before a click is assumed stable.
62-
void OneButton::setDebounceTicks(const int ticks)
62+
void OneButton::setDebounceTicks(const unsigned int ms)
6363
{
64-
_debounceTicks = ticks;
64+
_debounce_ms = ms;
6565
} // setDebounceTicks
6666

6767

6868
// explicitly set the number of millisec that have to pass by before a click is detected.
69-
void OneButton::setClickTicks(const int ticks)
69+
void OneButton::setClickTicks(const unsigned int ms)
7070
{
71-
_clickTicks = ticks;
71+
_click_ms = ms;
7272
} // setClickTicks
7373

7474

7575
// explicitly set the number of millisec that have to pass by before a long button press is detected.
76-
void OneButton::setPressTicks(const int ticks)
76+
void OneButton::setPressTicks(const unsigned int ms)
7777
{
78-
_pressTicks = ticks;
78+
_press_ms = ms;
7979
} // setPressTicks
8080

8181

@@ -176,7 +176,6 @@ void OneButton::attachDuringLongPress(parameterizedCallbackFunction newFunction,
176176
void OneButton::reset(void)
177177
{
178178
_state = OneButton::OCS_INIT;
179-
_lastState = OneButton::OCS_INIT;
180179
_nClicks = 0;
181180
_startTime = 0;
182181
}
@@ -190,23 +189,32 @@ int OneButton::getNumberClicks(void)
190189

191190

192191
/**
193-
* @brief Check input of the configured pin and then advance the finite state
194-
* machine (FSM).
192+
* @brief Check input of the configured pin,
193+
* debounce input pin level and then
194+
* advance the finite state machine (FSM).
195195
*/
196196
void OneButton::tick(void)
197197
{
198198
if (_pin >= 0) {
199-
tick(digitalRead(_pin) == _buttonPressed);
199+
int pinLevel = digitalRead(_pin);
200+
now = millis(); // current (relative) time in msecs.
201+
if (_lastDebouncePinLevel == pinLevel) {
202+
if ((now - _lastDebounceTime) >= _debounce_ms) {
203+
tick(pinLevel == _buttonPressed); // pinLevel is debounced here
204+
}
205+
} else {
206+
_lastDebouncePinLevel = pinLevel;
207+
_lastDebounceTime = now;
208+
}
200209
}
201-
}
210+
} // tick()
202211

203212

204213
/**
205214
* @brief Advance to a new state and save the last one to come back in cas of bouncing detection.
206215
*/
207216
void OneButton::_newState(stateMachine_t nextState)
208217
{
209-
_lastState = _state;
210218
_state = nextState;
211219
} // _newState()
212220

@@ -216,7 +224,6 @@ void OneButton::_newState(stateMachine_t nextState)
216224
*/
217225
void OneButton::tick(bool activeLevel)
218226
{
219-
unsigned long now = millis(); // current (relative) time in msecs.
220227
unsigned long waitTime = (now - _startTime);
221228

222229
// Implementation of the state machine
@@ -233,15 +240,11 @@ void OneButton::tick(bool activeLevel)
233240
case OneButton::OCS_DOWN:
234241
// waiting for level to become inactive.
235242

236-
if ((!activeLevel) && (waitTime < _debounceTicks)) {
237-
// button was released to quickly so I assume some bouncing.
238-
_newState(_lastState);
239-
240-
} else if (!activeLevel) {
243+
if (!activeLevel) {
241244
_newState(OneButton::OCS_UP);
242245
_startTime = now; // remember starting time
243246

244-
} else if ((activeLevel) && (waitTime > _pressTicks)) {
247+
} else if ((activeLevel) && (waitTime > _press_ms)) {
245248
if (_longPressStartFunc) _longPressStartFunc();
246249
if (_paramLongPressStartFunc) _paramLongPressStartFunc(_longPressStartFuncParam);
247250
_newState(OneButton::OCS_PRESS);
@@ -251,15 +254,9 @@ void OneButton::tick(bool activeLevel)
251254
case OneButton::OCS_UP:
252255
// level is inactive
253256

254-
if ((activeLevel) && (waitTime < _debounceTicks)) {
255-
// button was pressed to quickly so I assume some bouncing.
256-
_newState(_lastState); // go back
257-
258-
} else if (waitTime >= _debounceTicks) {
259257
// count as a short button down
260258
_nClicks++;
261259
_newState(OneButton::OCS_COUNT);
262-
} // if
263260
break;
264261

265262
case OneButton::OCS_COUNT:
@@ -270,7 +267,7 @@ void OneButton::tick(bool activeLevel)
270267
_newState(OneButton::OCS_DOWN);
271268
_startTime = now; // remember starting time
272269

273-
} else if ((waitTime > _clickTicks) || (_nClicks == _maxClicks)) {
270+
} else if ((waitTime >= _click_ms) || (_nClicks == _maxClicks)) {
274271
// now we know how many clicks have been made.
275272

276273
if (_nClicks == 1) {
@@ -294,7 +291,7 @@ void OneButton::tick(bool activeLevel)
294291
break;
295292

296293
case OneButton::OCS_PRESS:
297-
// waiting for menu pin being release after long press.
294+
// waiting for pin being release after long press.
298295

299296
if (!activeLevel) {
300297
_newState(OneButton::OCS_PRESSEND);
@@ -310,15 +307,9 @@ void OneButton::tick(bool activeLevel)
310307
case OneButton::OCS_PRESSEND:
311308
// button was released.
312309

313-
if ((activeLevel) && (waitTime < _debounceTicks)) {
314-
// button was released to quickly so I assume some bouncing.
315-
_newState(_lastState); // go back
316-
317-
} else if (waitTime >= _debounceTicks) {
318310
if (_longPressStopFunc) _longPressStopFunc();
319311
if (_paramLongPressStopFunc) _paramLongPressStopFunc(_longPressStopFuncParam);
320312
reset();
321-
}
322313
break;
323314

324315
default:

src/OneButton.h

+30-15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
// 26.09.2018 Initialization moved into class declaration.
2020
// 26.09.2018 Jay M Ericsson: compiler warnings removed.
2121
// 29.01.2020 improvements from ShaggyDog18
22+
// 07.05.2023 Debouncing in one point. #118
2223
// -----
2324

2425
#ifndef OneButton_h
@@ -53,17 +54,22 @@ class OneButton
5354
/**
5455
* set # millisec after safe click is assumed.
5556
*/
56-
void setDebounceTicks(const int ticks);
57+
void setDebounceTicks(const unsigned int ms); // obsolete
58+
void setDebounceMs(const unsigned int ms) { setDebounceTicks(ms); };
5759

5860
/**
5961
* set # millisec after single click is assumed.
6062
*/
61-
void setClickTicks(const int ticks);
63+
void setClickTicks(const unsigned int ms); // obsolete
64+
void setClickMs(const unsigned int ms) { setClickTicks(ms); };
6265

6366
/**
6467
* set # millisec after press is assumed.
6568
*/
66-
void setPressTicks(const int ticks);
69+
void setPressTicks(const unsigned int ms); // obsolete
70+
void setPressMs(const unsigned int ms) { setPressTicks(ms); };
71+
72+
// ----- Attach events functions -----
6773

6874
/**
6975
* Attach an event to be called when a single click is detected.
@@ -115,15 +121,16 @@ class OneButton
115121
*/
116122
void tick(void);
117123

118-
119124
/**
120125
* @brief Call this function every time the input level has changed.
121126
* Using this function no digital input pin is checked because the current
122127
* level is given by the parameter.
128+
* Run the finite state machine (FSM) using the given level.
123129
*/
124130
void tick(bool level);
125131

126132

133+
public:
127134
/**
128135
* Reset the button state machine.
129136
*/
@@ -149,12 +156,14 @@ class OneButton
149156

150157

151158
private:
152-
int _pin = 0; // hardware pin number.
153-
unsigned int _debounceTicks = 50; // number of ticks for debounce times.
154-
unsigned int _clickTicks = 400; // number of msecs before a click is detected.
155-
unsigned int _pressTicks = 800; // number of msecs before a long button press is detected
159+
int _pin = -1; // hardware pin number.
160+
unsigned int _debounce_ms = 50; // number of msecs for debounce times.
161+
unsigned int _click_ms = 400; // number of msecs before a click is detected.
162+
unsigned int _press_ms = 800; // number of msecs before a long button press is detected
156163

157-
int _buttonPressed = 0;
164+
int _buttonPressed = 0; // this is the level of the input pin when the button is pressed.
165+
// LOW if the button connects the input pin to GND when pressed.
166+
// HIGH if the button connects the input pin to VCC when pressed.
158167

159168
// These variables will hold functions acting as event source.
160169
callbackFunction _clickFunc = NULL;
@@ -188,25 +197,31 @@ class OneButton
188197
// define FiniteStateMachine
189198
enum stateMachine_t : int {
190199
OCS_INIT = 0,
191-
OCS_DOWN = 1,
192-
OCS_UP = 2,
200+
OCS_DOWN = 1, // button is down
201+
OCS_UP = 2, // button is up
193202
OCS_COUNT = 3,
194-
OCS_PRESS = 6,
203+
OCS_PRESS = 6, // button is hold down
195204
OCS_PRESSEND = 7,
196-
UNKNOWN = 99
197205
};
198206

199207
/**
200-
* Advance to a new state and save the last one to come back in cas of bouncing detection.
208+
* Advance to a new state.
201209
*/
202210
void _newState(stateMachine_t nextState);
203211

204212
stateMachine_t _state = OCS_INIT;
205-
stateMachine_t _lastState = OCS_INIT; // used for debouncing
213+
214+
int _lastDebouncePinLevel = -1; // used for pin debouncing
215+
unsigned long _lastDebounceTime = 0; // millis()
216+
unsigned long now = 0; // millis()
206217

207218
unsigned long _startTime = 0; // start of current input change to checking debouncing
208219
int _nClicks = 0; // count the number of clicks with this variable
209220
int _maxClicks = 1; // max number (1, 2, multi=3) of clicks of interest by registration of event functions.
221+
222+
public:
223+
int pin() const { return _pin; };
224+
stateMachine_t state() const { return _state; };
210225
};
211226

212227
#endif

0 commit comments

Comments
 (0)