Skip to content

Commit cee0985

Browse files
committed
Allow using OneButton with external input level.
1 parent ebfac8f commit cee0985

File tree

2 files changed

+147
-90
lines changed

2 files changed

+147
-90
lines changed

src/OneButton.cpp

+100-66
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,76 @@
1-
// -----
2-
// OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
3-
// This class is implemented for use with the Arduino environment.
4-
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
5-
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
6-
// More information on: http://www.mathertel.de/Arduino
7-
// -----
8-
// Changelog: see OneButton.h
9-
// -----
1+
/**
2+
* @file OneButton.cpp
3+
*
4+
* @brief Library for detecting button clicks, doubleclicks and long press
5+
* pattern on a single button.
6+
*
7+
* @author Matthias Hertel, https://www.mathertel.de
8+
* @Copyright Copyright (c) by Matthias Hertel, https://www.mathertel.de.
9+
*
10+
* This work is licensed under a BSD style license. See
11+
* http://www.mathertel.de/License.aspx
12+
*
13+
* More information on: https://www.mathertel.de/Arduino/OneButtonLibrary.aspx
14+
*
15+
* Changelog: see OneButton.h
16+
*/
1017

1118
#include "OneButton.h"
1219

1320
// ----- Initialization and Default Values -----
1421

22+
/**
23+
* @brief Construct a new OneButton object but not (yet) initialize the IO pin.
24+
*/
25+
OneButton::OneButton()
26+
{
27+
_pin = -1;
28+
// further initialization has moved to OneButton.h
29+
}
30+
1531
OneButton::OneButton(int pin, int activeLow, bool pullupActive)
1632
{
33+
// OneButton();
1734
_pin = pin;
1835

19-
_debounceTicks = 50; // number of millisec that have to pass by before a click is assumed as safe.
20-
_clickTicks = 600; // number of millisec that have to pass by before a click is detected.
21-
_pressTicks = 1000; // number of millisec that have to pass by before a long button press is detected.
22-
23-
_state = 0; // starting with state 0: waiting for button to be pressed
24-
_isLongPressed = false; // Keep track of long press state
25-
2636
if (activeLow) {
2737
// the button connects the input pin to GND when pressed.
28-
_buttonReleased = HIGH; // notPressed
2938
_buttonPressed = LOW;
3039

31-
// use the given pin as input and activate internal PULLUP resistor.
32-
if(pullupActive)
33-
pinMode( pin, INPUT_PULLUP );
34-
else
35-
pinMode( pin, INPUT );
36-
3740
} else {
3841
// the button connects the input pin to VCC when pressed.
39-
_buttonReleased = LOW;
4042
_buttonPressed = HIGH;
43+
} // if
4144

45+
if (pullupActive) {
46+
// use the given pin as input and activate internal PULLUP resistor.
47+
pinMode(pin, INPUT_PULLUP);
48+
} else {
4249
// use the given pin as input
4350
pinMode(pin, INPUT);
4451
} // if
45-
46-
// no functions attached yet: clear all function pointers.
47-
_clickFunc = NULL;
48-
_doubleClickFunc = NULL;
49-
_pressFunc = NULL;
50-
_longPressStartFunc = NULL;
51-
_longPressStopFunc = NULL;
52-
_duringLongPressFunc = NULL;
5352
} // OneButton
5453

5554

56-
// explicitly set the number of millisec that have to pass by before a click is assumed as safe.
57-
void OneButton::setDebounceTicks(int ticks) {
55+
// explicitly set the number of millisec that have to pass by before a click is
56+
// assumed as safe.
57+
void OneButton::setDebounceTicks(int ticks)
58+
{
5859
_debounceTicks = ticks;
5960
} // setDebounceTicks
6061

61-
// explicitly set the number of millisec that have to pass by before a click is detected.
62-
void OneButton::setClickTicks(int ticks) {
62+
// explicitly set the number of millisec that have to pass by before a click is
63+
// detected.
64+
void OneButton::setClickTicks(int ticks)
65+
{
6366
_clickTicks = ticks;
6467
} // setClickTicks
6568

6669

67-
// explicitly set the number of millisec that have to pass by before a long button press is detected.
68-
void OneButton::setPressTicks(int ticks) {
70+
// explicitly set the number of millisec that have to pass by before a long
71+
// button press is detected.
72+
void OneButton::setPressTicks(int ticks)
73+
{
6974
_pressTicks = ticks;
7075
} // setPressTicks
7176

@@ -85,7 +90,8 @@ void OneButton::attachDoubleClick(callbackFunction newFunction)
8590

8691

8792
// save function for press event
88-
// DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress,
93+
// DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop,
94+
// attachDuringLongPress,
8995
void OneButton::attachPress(callbackFunction newFunction)
9096
{
9197
_pressFunc = newFunction;
@@ -125,73 +131,101 @@ void OneButton::reset(void){
125131
_isLongPressed = false;
126132
}
127133

134+
135+
/**
136+
* @brief Check input of the configured pin and then advance the finite state
137+
* machine (FSM).
138+
*/
128139
void OneButton::tick(void)
129140
{
130-
// Detect the input information
131-
int buttonLevel = digitalRead(_pin); // current button signal.
141+
if (_pin >= 0) {
142+
tick(digitalRead(_pin) == _buttonPressed);
143+
}
144+
}
145+
146+
147+
/**
148+
* @brief Advance the finite state machine (FSM) using the given level.
149+
*/
150+
void OneButton::tick(bool activeLevel)
151+
{
132152
unsigned long now = millis(); // current (relative) time in msecs.
133153

134154
// Implementation of the state machine
155+
135156
if (_state == 0) { // waiting for menu pin being pressed.
136-
if (buttonLevel == _buttonPressed) {
157+
if (activeLevel) {
137158
_state = 1; // step to state 1
138159
_startTime = now; // remember starting time
139160
} // if
140161

141162
} else if (_state == 1) { // waiting for menu pin being released.
142163

143-
if ((buttonLevel == _buttonReleased) && ((unsigned long)(now - _startTime) < _debounceTicks)) {
164+
if ((!activeLevel) &&
165+
((unsigned long)(now - _startTime) < _debounceTicks)) {
144166
// button was released to quickly so I assume some debouncing.
145-
// go back to state 0 without calling a function.
167+
// go back to state 0 without calling a function.
146168
_state = 0;
147169

148-
} else if (buttonLevel == _buttonReleased) {
170+
} else if (!activeLevel) {
149171
_state = 2; // step to state 2
150172
_stopTime = now; // remember stopping time
151173

152-
} else if ((buttonLevel == _buttonPressed) && ((unsigned long)(now - _startTime) > _pressTicks)) {
153-
_isLongPressed = true; // Keep track of long press state
154-
if (_pressFunc) _pressFunc();
155-
if (_longPressStartFunc) _longPressStartFunc();
156-
if (_duringLongPressFunc) _duringLongPressFunc();
174+
} else if ((activeLevel) &&
175+
((unsigned long)(now - _startTime) > _pressTicks)) {
176+
_isLongPressed = true; // Keep track of long press state
177+
if (_pressFunc)
178+
_pressFunc();
179+
if (_longPressStartFunc)
180+
_longPressStartFunc();
181+
if (_duringLongPressFunc)
182+
_duringLongPressFunc();
157183
_state = 6; // step to state 6
158184
_stopTime = now; // remember stopping time
159185
} else {
160186
// wait. Stay in this state.
161187
} // if
162188

163-
} else if (_state == 2) { // waiting for menu pin being pressed the second time or timeout.
164-
if (_doubleClickFunc == NULL || (unsigned long)(now - _startTime) > _clickTicks) {
189+
} else if (_state == 2) {
190+
// waiting for menu pin being pressed the second time or timeout.
191+
if (_doubleClickFunc == NULL ||
192+
(unsigned long)(now - _startTime) > _clickTicks) {
165193
// this was only a single short click
166-
if (_clickFunc) _clickFunc();
194+
if (_clickFunc)
195+
_clickFunc();
167196
_state = 0; // restart.
168197

169-
} else if ((buttonLevel == _buttonPressed) && ((unsigned long)(now - _stopTime) > _debounceTicks)) {
198+
} else if ((activeLevel) &&
199+
((unsigned long)(now - _stopTime) > _debounceTicks)) {
170200
_state = 3; // step to state 3
171201
_startTime = now; // remember starting time
172202
} // if
173203

174204
} else if (_state == 3) { // waiting for menu pin being released finally.
175-
// Stay here for at least _debounceTicks because else we might end up in state 1 if the
176-
// button bounces for too long.
177-
if (buttonLevel == _buttonReleased && ((unsigned long)(now - _startTime) > _debounceTicks)) {
205+
// Stay here for at least _debounceTicks because else we might end up in
206+
// state 1 if the button bounces for too long.
207+
if ((!activeLevel) &&
208+
((unsigned long)(now - _startTime) > _debounceTicks)) {
178209
// this was a 2 click sequence.
179-
if (_doubleClickFunc) _doubleClickFunc();
210+
if (_doubleClickFunc)
211+
_doubleClickFunc();
180212
_state = 0; // restart.
181213
_stopTime = now; // remember stopping time
182-
183214
} // if
184215

185-
} else if (_state == 6) { // waiting for menu pin being release after long press.
186-
if (buttonLevel == _buttonReleased) {
187-
_isLongPressed = false; // Keep track of long press state
188-
if(_longPressStopFunc) _longPressStopFunc();
216+
} else if (_state == 6) {
217+
// waiting for menu pin being release after long press.
218+
if (!activeLevel) {
219+
_isLongPressed = false; // Keep track of long press state
220+
if (_longPressStopFunc)
221+
_longPressStopFunc();
189222
_state = 0; // restart.
190223
_stopTime = now; // remember stopping time
191224
} else {
192-
// button is being long pressed
193-
_isLongPressed = true; // Keep track of long press state
194-
if (_duringLongPressFunc) _duringLongPressFunc();
225+
// button is being long pressed
226+
_isLongPressed = true; // Keep track of long press state
227+
if (_duringLongPressFunc)
228+
_duringLongPressFunc();
195229
} // if
196230

197231
} // if

src/OneButton.h

+47-24
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
// -----
2-
// OneButton.h - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
3-
// This class is implemented for use with the Arduino environment.
4-
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
5-
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
6-
// More information on: http://www.mathertel.de/Arduino
2+
// OneButton.h - Library for detecting button clicks, doubleclicks and long
3+
// press pattern on a single button. This class is implemented for use with the
4+
// Arduino environment. Copyright (c) by Matthias Hertel,
5+
// http://www.mathertel.de This work is licensed under a BSD style license. See
6+
// http://www.mathertel.de/License.aspx More information on:
7+
// http://www.mathertel.de/Arduino
78
// -----
89
// 02.10.2010 created by Matthias Hertel
910
// 21.04.2011 transformed into a library
1011
// 01.12.2011 include file changed to work with the Arduino 1.0 environment
11-
// 23.03.2014 Enhanced long press functionalities by adding longPressStart and longPressStop callbacks
12+
// 23.03.2014 Enhanced long press functionalities by adding longPressStart and
13+
// longPressStop callbacks
1214
// 21.09.2015 A simple way for debounce detection added.
1315
// 14.05.2017 Debouncing improvements.
1416
// 25.06.2018 Optional third parameter for deactivating pullup.
17+
// 26.09.2018 Anatoli Arkhipenko: Included solution to use library with other
18+
// sources of input.
19+
// 26.09.2018 Initialization moved into class declaration.
1520
// -----
1621

1722
#ifndef OneButton_h
@@ -22,14 +27,16 @@
2227
// ----- Callback function types -----
2328

2429
extern "C" {
25-
typedef void (*callbackFunction)(void);
30+
typedef void (*callbackFunction)(void);
2631
}
2732

2833

2934
class OneButton
3035
{
3136
public:
3237
// ----- Constructor -----
38+
OneButton();
39+
3340
OneButton(int pin, int active, bool pullupActive = true);
3441

3542
// ----- Set runtime parameters -----
@@ -43,44 +50,60 @@ class OneButton
4350
// set # millisec after press is assumed.
4451
void setPressTicks(int ticks);
4552

46-
// attach functions that will be called when button was pressed in the specified way.
53+
// attach functions that will be called when button was pressed in the
54+
// specified way.
4755
void attachClick(callbackFunction newFunction);
4856
void attachDoubleClick(callbackFunction newFunction);
49-
void attachPress(callbackFunction newFunction); // DEPRECATED, replaced by longPressStart, longPressStop and duringLongPress
57+
void attachPress(
58+
callbackFunction newFunction); // DEPRECATED, replaced by longPressStart,
59+
// longPressStop and duringLongPress
5060
void attachLongPressStart(callbackFunction newFunction);
5161
void attachLongPressStop(callbackFunction newFunction);
5262
void attachDuringLongPress(callbackFunction newFunction);
5363

5464
// ----- State machine functions -----
5565

56-
// call this function every some milliseconds for handling button events.
66+
/**
67+
* @brief Call this function every some milliseconds for checking the input
68+
* level at the initialized digital pin.
69+
*/
5770
void tick(void);
71+
72+
/**
73+
* @brief Call this function every time the input level has changed.
74+
* Using this function no digital input pin is checked because the current
75+
* level is given by the parameter.
76+
*/
77+
void tick(bool level);
78+
5879
bool isLongPressed();
5980
int getPressedTicks();
6081
void reset(void);
6182

6283
private:
63-
int _pin; // hardware pin number.
64-
int _debounceTicks; // number of ticks for debounce times.
65-
int _clickTicks; // number of ticks that have to pass by before a click is detected
66-
int _pressTicks; // number of ticks that have to pass by before a long button press is detected
84+
int _pin; // hardware pin number.
85+
int _debounceTicks = 50; // number of ticks for debounce times.
86+
int _clickTicks = 600; // number of ticks that have to pass by
87+
// before a click is detected.
88+
int _pressTicks = 1000; // number of ticks that have to pass by before a long
89+
// button press is detected
6790

68-
int _buttonReleased;
6991
int _buttonPressed;
7092

71-
bool _isLongPressed;
93+
bool _isLongPressed = false;
7294

7395
// These variables will hold functions acting as event source.
74-
callbackFunction _clickFunc;
75-
callbackFunction _doubleClickFunc;
76-
callbackFunction _pressFunc;
77-
callbackFunction _longPressStartFunc;
78-
callbackFunction _longPressStopFunc;
79-
callbackFunction _duringLongPressFunc;
96+
callbackFunction _clickFunc = NULL;
97+
callbackFunction _doubleClickFunc = NULL;
98+
callbackFunction _pressFunc = NULL;
99+
callbackFunction _longPressStartFunc = NULL;
100+
callbackFunction _longPressStopFunc = NULL;
101+
callbackFunction _duringLongPressFunc = NULL;
80102

81103
// These variables that hold information across the upcoming tick calls.
82-
// They are initialized once on program start and are updated every time the tick function is called.
83-
int _state;
104+
// They are initialized once on program start and are updated every time the
105+
// tick function is called.
106+
int _state = 0;
84107
unsigned long _startTime; // will be set in state 1
85108
unsigned long _stopTime; // will be set in state 2
86109
};

0 commit comments

Comments
 (0)