Skip to content

Commit 1ff89b0

Browse files
committed
Update
New pressCode() function and example. Readme updated.
1 parent c8c39a6 commit 1ff89b0

File tree

7 files changed

+158
-60
lines changed

7 files changed

+158
-60
lines changed

README.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,26 @@
11
# Toggle [![arduino-library-badge](https://www.ardu-badge.com/badge/Toggle.svg?)](https://www.ardu-badge.com/Toggle) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/dlloydev/library/Toggle.svg)](https://registry.platformio.org/libraries/dlloydev/Toggle)
22

3-
Arduino bounce library for deglitching and debouncing hardware, signals and data. Works with all switch types, port expander and other 8-bit data sources. Three algorithm modes available. Robust mode ignores up to several consecutive spurious transitions.
3+
Arduino button library for deglitching and debouncing switch contacts and logic data. Works with all switch types, port expander and other 8-bit data sources. Three algorithm modes available that can ignore up to several consecutive spurious transitions.
44

55
## Features
66

77
### Flexible Inputs
88

9-
The inputs can be from a single pin or several pins allowing the use of 2 or 3-position switches and up to seven debounced states. When linking to a data (byte) input, the debouncer can work with any selected bit or it can debounce all 8-bits in one Toggle instance. This method can be used for debouncing serial data from I/O expanders, sensors or stored values. Examples: [`Input_Bit_Test.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Bit_Test/Input_Bit_Test.ino) , [`Input_Bit.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Bit/Input_Bit.ino), [`Input_Port_Test.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Port_Test/Input_Port_Test.ino) and [`Input_Port.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Port/Input_Port.ino).
10-
11-
From the `Input_Port_Test.ino` example, this is the serial output with leading 0's added:
12-
13-
```c++
14-
In: 00000000 Out: 00000000
15-
In: 10000001 Out: 00000000
16-
In: 10100011 Out: 00000000
17-
In: 00100111 Out: 00000001
18-
In: 00001110 Out: 00000011
19-
In: 00011110 Out: 00000111
20-
In: 00101111 Out: 00001111
21-
In: 01110110 Out: 00001111
22-
In: 11111100 Out: 00101111
23-
In: 11011000 Out: 01111110
24-
In: 01110000 Out: 01111100
25-
In: 01100011 Out: 01111000
26-
In: 11000000 Out: 01110000
27-
In: 10000100 Out: 01100000
28-
In: 00000000 Out: 01000000
29-
```
30-
31-
Looking at the columns (bit data) top to bottom, it can be seen that the debounced `Out` data lags by only 2 samples (rows). It also can be seen that the input debouncer can tolerate a very noisy signal with up to 2 consecutive 1's or 0's that are anomalous or spurious in the `In` data.
9+
The inputs can be from a single pin or several pins allowing the use of 2 or 3-position switches and up to seven debounced states. When linking to a data (byte) input, the debouncer can work with any selected bit or it can debounce all 8-bits in one Toggle instance. Examples: [`Input_Bit_Test.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Bit_Test/Input_Bit_Test.ino) , [`Input_Bit.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Bit/Input_Bit.ino), [`Input_Port_Test.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Port_Test/Input_Port_Test.ino) and [`Input_Port.ino`](https://github.com/Dlloydev/Toggle/blob/main/examples/Input_Port/Input_Port.ino).
3210

3311
### Algorithms
3412

3513
```c++
3614
setAlgorithm(2); // Robust Mode, 2 glitches ignored
37-
setAlgorithm(1); // Normal Mode, 1 glitch ignored
38-
setAlgorithm(0); // Quick Mode, responds to spurious transitions
15+
setAlgorithm(1); // Average Mode, 1 glitch ignored
16+
setAlgorithm(0); // Common Mode, can respond to spurious transitions
3917
```
4018
4119
In Robust Mode, the algorithm adds only 2 sample periods of time lag to the output signal. A 3-sample stable period is required for an output bit to change. Therefore, to set an output bit, 3 consecutive 1's are required. When 3 consecutive 0's are detected, that bit value is cleared.
4220
4321
### Sampling
4422
45-
Rather than use a basic timer strategy, the Toggle library uses sampling and only requires up to three samples on the input to to provide a clean (debounced) output. The sample period defaults to 5000μs (5ms) which works well the default Robust Mode. With these defaults, only 15ms is required for detecting a button switch being pressed or released. This may seem low when thinking of regular debouncig, but in order for this method to falsely detect a transition, it would require that there be a gap of greater than 15ms between bounces. From *[A Guide to Debouncing](http://www.ganssle.com/item/debouncing-switches-contacts-code.htm)*, (Anatomy of a Bounce):
23+
Rather than use a basic timer strategy, the Toggle library uses sampling and only requires up to three samples on the input to to provide a clean (debounced) output. The sample period defaults to 5000 μs (5 ms) which works well the default Robust Mode. With these defaults, only 15ms is required for detecting a button switch being pressed or released. This may seem low when thinking of regular debouncig, but in order for this method to falsely detect a transition, it would require that there be a gap of greater than 15ms between bounces. From *[A Guide to Debouncing](http://www.ganssle.com/item/debouncing-switches-contacts-code.htm)*, (Anatomy of a Bounce):
4624
4725
> *Consider switch E again, that one with the pretty face that hides a vicious 157 msec bouncing heart. One test showed the switch going to a solid one for 81 msec, after which it dropped to a perfect zero for 42 msec before finally assuming its correct high state. Think what that would do to pretty much any debounce code!*
4826
@@ -394,6 +372,30 @@ if (retrigger(500)) {
394372

395373

396374

375+
## pressCode()
376+
377+
##### Description
378+
379+
- Up to 225 possible codes with one button. The returned code (*byte*) is easy to interpret when viewed in hex format. For example, `47` is 4 long, 7 short presses. `F2` is double-click, `F7` is 7 `F`ast clicks.
380+
- Fast-click mode is detected if the first 2 clicks (presses) are less than 0.4 sec, then counts any extra presses if the duration is less than 1 sec, up to 15 max (code `FF`)
381+
- Detection of long (greater than 1 sec) presses and short (less than 1 sec) presses occurs if the first press is 0.4 sec or longer.
382+
- Detect up to 15 short presses
383+
- Detect up to 14 long presses
384+
- Returns code after button is released for 1.4 sec
385+
- simplifies your code while adding maximum functionality to one button
386+
387+
##### Example
388+
389+
```c++
390+
byte pCode = sw1.pressCode(1); // (1) serial print results
391+
```
392+
393+
##### Example Sketch
394+
395+
[Press_Code.ino](https://github.com/Dlloydev/Toggle/blob/main/examples/Press_Code/Press_Code.ino)
396+
397+
398+
397399
## Set and Get Functions
398400

399401

@@ -511,8 +513,8 @@ Elapsed milliseconds *(unsigned int)*.
511513
Sets the debouncer algorithm to one of three modes.
512514

513515
- **Robust Mode (2):** This is the default mode where up to 2 spurious signal transitions (glitches) are ignored. This adds 2 sample periods time lag to the output signal.
514-
- **Normal Response (1):** This is mode ignores up to 1 spurious signal transition (glitch) and adds 1 sample period time lag to the output signal.
515-
- **Quick Response (0):** This is mode is similar to most debouncers where the response is near instant to a button or switch press, and the release won't be recognized until a debounce time period has expired. In this case, the debounce time period is calculated and set at 10 times the sample period.
516+
- **Average Mode (1):** This is mode ignores up to 1 spurious signal transition (glitch) and adds 1 sample period time lag to the output signal.
517+
- **Common Mode (0):** This is mode is similar to most debouncers where the response is near instant to a button or switch press, and the release won't be recognized until a debounce time period has expired. In this case, the debounce time period is calculated and set at 10 times the sample period.
516518

517519
##### Syntax
518520

examples/Press_Code/Press_Code.ino

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/************************************************************************
2+
Press Code Example:
3+
===================
4+
A simple example that demonstrates how fast-clicks, short presses and
5+
long presses can be automatically detected and combined into a byte code.
6+
In debug mode, the serial monitor shows timing results and code.
7+
***********************************************************************/
8+
9+
#include <Toggle.h>
10+
11+
const byte buttonPin = 2;
12+
byte code;
13+
14+
Toggle sw1(buttonPin);
15+
16+
void setup() {
17+
while (!Serial) { }; // Leonardo
18+
Serial.begin(115200);
19+
sw1.begin(buttonPin);
20+
}
21+
22+
void loop() {
23+
sw1.poll();
24+
sw1.pressCode(1); // open serial monitor to view results
25+
//code = sw1.pressCode(); // no debug
26+
}

keywords.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ setInvertMode KEYWORD2
3131
setSamplePeriodUs KEYWORD2
3232
setTimerMode KEYWORD2
3333
getTimerMode KEYWORD2
34-
clearTimer KEYWORD2
3534
getElapsedMs KEYWORD2
3635
isPressed KEYWORD2
3736
isReleased KEYWORD2
@@ -43,7 +42,8 @@ blink KEYWORD2
4342
pressedFor KEYWORD2
4443
releasedFor KEYWORD2
4544
retrigger KEYWORD2
46-
debounceInput KEYWORD2
45+
retrigger KEYWORD2
46+
pressCode KEYWORD2
4747
isUP KEYWORD2
4848
isMID KEYWORD2
4949
isDN KEYWORD2
@@ -61,3 +61,5 @@ input_pullup LITERAL1
6161
input_pulldown LITERAL1
6262
input_bit LITERAL1
6363
input_port LITERAL1
64+
MULTI LITERAL1
65+
LONG LITERAL1

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "Toggle",
3-
"version": "3.0.2",
3+
"version": "3.1.0",
44
"description": "Arduino bounce library for deglitching and debouncing hardware, signals and data. Works with all switch types, port expander and other 8-bit data sources. Flexible algorithm with Robust, Normal and Quick response modes.",
55
"keywords": "debounce, toggle, button, switch, data, deglitch",
66
"repository":

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Toggle
2-
version=3.0.2
2+
version=3.1.0
33
author=David Lloyd
44
maintainer=David Lloyd <dlloydev@testcor.ca>
55
sentence=Arduino bounce library for deglitching and debouncing hardware, signals and data. Works with all switch types, port expander and other 8-bit data sources.

src/Toggle.cpp

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/************************************************
2-
Toggle Library for Arduino - Version 3.0.2
2+
Toggle Library for Arduino - Version 3.1.0
33
by dlloydev https://github.com/Dlloydev/Toggle
44
Licensed under the MIT License.
55
************************************************/
@@ -15,7 +15,8 @@ void Toggle::begin(uint8_t inA, uint8_t inB) {
1515
csr &= ~0b00001000; // clear first run
1616
_inA = inA;
1717
_inB = inB;
18-
sampleUs = micros();
18+
us_timestamp = micros();
19+
startUs = us_timestamp;
1920
if (_inA != 255) {
2021
if (_inputMode == inMode::input_pullup) pinMode(_inA, INPUT_PULLUP);
2122
else if (_inputMode == inMode::input) pinMode(_inA, INPUT);
@@ -35,9 +36,8 @@ void Toggle::begin(uint8_t inA, uint8_t inB) {
3536

3637
void Toggle::poll(uint8_t bit) {
3738
begin(_inA, _inB); // runs one only
38-
if (micros() - sampleUs > _samplePeriodUs) {
39-
sampleUs += _samplePeriodUs;
40-
sampleCount++;
39+
if (micros() - us_timestamp > us_period) {
40+
us_timestamp += us_period;
4141
if (_inputMode == inMode::input || _inputMode == inMode::input_pullup || _inputMode == inMode::input_pulldown) {
4242
if (_inA) dat = digitalRead(_inA);
4343
if (_inB) dat += digitalRead(_inB) * 2;
@@ -70,8 +70,8 @@ void Toggle::setInvertMode(bool invert) {
7070
else csr &= ~0b00000100; //clear
7171
}
7272

73-
void Toggle::setSamplePeriodUs(uint16_t samplePeriodUs) {
74-
_samplePeriodUs = samplePeriodUs;
73+
void Toggle::setSamplePeriodUs(uint16_t period) {
74+
us_period = period;
7575
}
7676

7777
/************* button state functions ****************/
@@ -134,17 +134,6 @@ uint8_t Toggle::getTimerMode() {
134134
return (lsr & 0b11000000) >> 6;
135135
}
136136

137-
void Toggle::clearTimer() {
138-
if (getTimerMode() == 0 && (onChange() == 1)) sampleCount = 0; // onPress
139-
else if (getTimerMode() == 1 && (onChange() == 2)) sampleCount = 0; // onRelease
140-
else if (getTimerMode() == 2 && onChange()) sampleCount = 0; // onChange
141-
}
142-
143-
uint16_t Toggle::getElapsedMs() {
144-
if ((sampleCount * (_samplePeriodUs >> 10)) > 60000) sampleCount--;
145-
return sampleCount * (_samplePeriodUs >> 10);
146-
}
147-
148137
bool Toggle::blink(uint16_t ms) {
149138
return (bool)(ms > (getElapsedMs()));
150139
}
@@ -168,12 +157,80 @@ bool Toggle::releasedFor(uint16_t ms) {
168157
bool Toggle::retrigger(uint16_t ms) {
169158
if (getTimerMode()) setTimerMode(0); // start onPress
170159
if (isPressed() && getElapsedMs() > ms) {
171-
clearTimer();
160+
//clearTimer();
172161
return true;
173162
}
174163
return false;
175164
}
176165

166+
uint32_t Toggle::getElapsedMs() {
167+
return (micros() - startUs) * 0.001;
168+
}
169+
170+
uint8_t Toggle::pressCode() {
171+
static uint8_t pCode = 0, code = 0;
172+
static uint32_t elapsedMs = 0;
173+
174+
//Serial.print(F(" startUs: ")); Serial.print(startUs); Serial.print(F(" "));
175+
//Serial.print(F(" elapsedMS: ")); Serial.print(getElapsedMs()); Serial.print(F(" "));
176+
//Serial.print(F(" pCode: ")); Serial.print(pCode, HEX); Serial.print(F(" "));
177+
178+
switch (_state) {
179+
case PB_DEFAULT:
180+
setTimerMode(2); // onChange
181+
elapsedMs = getElapsedMs();
182+
if (pCode && (elapsedMs > CLICK::LONG)) _state = PB_DONE;
183+
if (onChange()) startUs = micros();
184+
if (onPress()) {
185+
//Serial.print(F(" releasedMs: ")); Serial.print(elapsedMs); Serial.print(F(" "));
186+
_state = PB_ON_PRESS;
187+
}
188+
if (onRelease()) {
189+
//Serial.print(F(" pressedMs: ")); Serial.print(elapsedMs); Serial.print(F(" "));
190+
_state = PB_ON_RELEASE;
191+
}
192+
break;
193+
194+
case PB_ON_PRESS:
195+
_state = PB_DEFAULT;
196+
break;
197+
198+
case PB_ON_RELEASE:
199+
if ((elapsedMs < CLICK::MULTI) && (!pCode || (pCode > 0xEF))) _state = PB_MULTI_CLICKS;
200+
else if (elapsedMs < CLICK::LONG) _state = PB_SHORT_CLICKS;
201+
else _state = PB_LONG_CLICKS;
202+
break;
203+
204+
case PB_MULTI_CLICKS:
205+
pCode |= 0xF0;
206+
if ((pCode & 0x0F) < 0x0F) pCode += 1;
207+
_state = PB_DEFAULT;
208+
break;
209+
210+
case PB_SHORT_CLICKS:
211+
if ((pCode & 0x0F) < 0x0F) pCode += 1;
212+
_state = PB_DEFAULT;
213+
break;
214+
215+
case PB_LONG_CLICKS:
216+
if ((pCode & 0xE0) < 0xE0) pCode += 0x10;
217+
_state = PB_DEFAULT;
218+
break;
219+
220+
case PB_DONE:
221+
code = pCode;
222+
pCode = 0;
223+
_state = PB_DEFAULT;
224+
return code;
225+
break;
226+
227+
default:
228+
_state = PB_DEFAULT;
229+
break;
230+
}
231+
return code;
232+
}
233+
177234
/************** debouncer ***********************************************************************
178235
The debounceInput() function by default uses a robust algorithm that ignores up to 2 spurious
179236
signal transitions (glitches) and only adds up to 2 sample periods time lag to the output signal.
@@ -208,12 +265,10 @@ uint8_t Toggle::debounceInput(uint8_t bit) {
208265
if ((pOut & (1 << bit)) && !isReleased(bit)) {
209266
lsr |= 0b00000001; // set onPress
210267
lsr &= ~0b00000010; // clear onRelease
211-
clearTimer();
212268
} else {
213269
if ((!(pOut & (1 << bit))) && isReleased(bit)) {
214270
lsr |= 0b00000010; // set onRelease
215271
lsr &= ~0b00000001; // clear onPress
216-
clearTimer();
217272
}
218273
}
219274
ppDat = pDat;

src/Toggle.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Toggle {
99

1010
enum class inMode : uint8_t {input = 0, input_pullup = 2, input_pulldown = 9, input_bit = 250, input_port = 251};
1111

12-
Toggle(); // default constructor
12+
Toggle();
1313
Toggle(uint8_t *in);
1414
Toggle(uint8_t inA, uint8_t inB = 255) {
1515
_inA = inA;
@@ -25,8 +25,7 @@ class Toggle {
2525
void setSamplePeriodUs(uint16_t samplePeriodUs); // sample period in microseconds
2626
void setTimerMode(uint8_t mode = 0); // start onPress(0), onRelease(1), onChange(2)
2727
uint8_t getTimerMode(); // start onPress(0), onRelease(1), onChange(2)
28-
void clearTimer(); // clears timer count on specified state change mode
29-
uint16_t getElapsedMs(); // get elapsed ms since the last state change selected by timer mode
28+
uint32_t getElapsedMs(); // get elapsed ms since the last state change selected by timer mode
3029

3130
bool isPressed(uint8_t bit = 0); // returns true if pressed
3231
bool isReleased(uint8_t bit = 0); // returns true if released
@@ -39,6 +38,7 @@ class Toggle {
3938
bool pressedFor(uint16_t ms); // returns true if pressed for at least the given ms
4039
bool releasedFor(uint16_t ms); // returns true if released for at least the given ms
4140
bool retrigger(uint16_t ms); // returns true each time the given ms expires while the button is pressed
41+
uint8_t pressCode(); // returns byte code for number of fast, short and long clicks
4242

4343
bool isUP(); // functions for using 2 inputs with 3-position switches
4444
bool isMID();
@@ -50,15 +50,28 @@ class Toggle {
5050

5151
private:
5252

53+
enum CLICK : uint32_t {MULTI = 400, LONG = 1000};
54+
enum fsm_t : uint8_t { // finite state machine
55+
PB_DEFAULT = 0,
56+
PB_ON_PRESS = 1,
57+
PB_ON_RELEASE = 2,
58+
PB_MULTI_CLICKS = 3,
59+
PB_SHORT_CLICKS = 4,
60+
PB_LONG_CLICKS = 5,
61+
PB_DONE = 6
62+
};
63+
64+
fsm_t _state = PB_DEFAULT;
65+
5366
uint8_t debounceInput(uint8_t bit = 0); // input debouncer
5467

5568
inMode _inputMode = inMode::input_pullup; // input mode
5669
uint8_t _inA, _inB; // input pin
5770
uint8_t *_in; // referenced to input variable
5871
uint8_t dat, pDat, ppDat; // current, previous and 2nd previos input data
59-
uint16_t _samplePeriodUs = 5000; // sample period μs
60-
uint16_t sampleCount; // sample count
61-
uint32_t sampleUs; // sample time μs
72+
uint16_t us_period = 5000; // sample period μs
73+
uint32_t startUs = 0; // for timing transitions
74+
uint32_t us_timestamp; // most recent sample time μs
6275
uint8_t out = 0xFF, pOut = 0xFF; // debounced output and previous debounced output
6376
uint8_t csr = 0b10101010; // B7-B4: debounceCount, B3: first run B2: invert, B1-B0 algorithm
6477
uint8_t lsr = 0b00000000; // B7-6: mode, B5 lastState, B4 toggle, B1 onRelease, B0 onPress

0 commit comments

Comments
 (0)