Skip to content

Commit 30ffd66

Browse files
committed
Version 2.1.0 - long and double press revisited
1 parent 08b8def commit 30ffd66

File tree

13 files changed

+304
-489
lines changed

13 files changed

+304
-489
lines changed

.github/workflows/LibraryBuild.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66

77
# This is the name of the workflow, visible on GitHub UI.
88
name: LibraryBuild
9-
on: [push, pull_request] # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
9+
10+
on:
11+
push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
12+
paths:
13+
- '**.ino'
14+
- '**.cpp'
15+
- '**.h'
16+
- '**LibraryBuildWithAction.yml'
17+
pull_request:
1018

1119
jobs:
1220
build:

README.md

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# EasyButton
2-
### [Version 2.0.0](https://github.com/ArminJo/EasyButtonAtInt01/releases)
1+
# [EasyButton](https://github.com/ArminJo/EasyButtonAtInt01)
2+
Available as Arduino library "EasyButtonAtInt01"
3+
4+
### [Version 2.1.0](https://github.com/ArminJo/EasyButtonAtInt01/releases)
35

46
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
57
[![Installation instructions](https://www.ardu-badge.com/badge/EasyButtonAtInt01.svg?)](https://www.ardu-badge.com/EasyButtonAtInt01)
@@ -8,22 +10,24 @@
810
[![Hit Counter](https://hitcounter.pythonanywhere.com/count/tag.svg?url=https%3A%2F%2Fgithub.com%2FArminJo%2FEasyButtonAtInt01)](https://github.com/brentvollebregt/hit-counter)
911

1012
Arduino library for handling push buttons just connected between ground and INT0 and / or INT1 pin.<br/>
11-
12-
No external pullup, **no polling needed**.
13-
14-
The library is totally **based on interrupt** and **debouncing is implemented in a not blocking way**.
15-
Debouncing is merely done by ignoring a button change within the debouncing time. So **button state is instantly available** without debouncing delay!
16-
13+
- No external pullup, **no polling needed**.
14+
- The library is totally **based on interrupt** and **debouncing is implemented in a not blocking way**.
15+
Debouncing is merely done by ignoring a button change within the debouncing time (default 50 ms).
16+
So **button state is instantly available** without debouncing delay!
1717
- Each button press toggles a state variable, so **no external logic for implementing a toggle button is needed**.
18-
- Support for **double press detection** is included. See Callback example.
19-
- Support for **long press detection**, which needs some polling or blocking, is included. See EasyButtonExample example.
20-
21-
INT0 and INT1 are connected to:
22-
- Pin 2 / 3 on most Arduinos (ATmega328*).
23-
- PB6 / PA3 on ATtiny167. To use one of PA0 to PA7 instead of PA3 just (re)define INT1_PIN before including *EasyButtonAtInt01.cpp.h*. E.g. `#define INT1_PIN 7`. See EasyButtonExample.cpp.
24-
- Only PB2 / INT0 at on ATtinyX5.
18+
- Support for **double press detection** is included. See EasyButtonExample and Callback example.
19+
- Support for **long press detection**, is included. See EasyButtonExample example.
20+
- Support to **measure maximum bouncing period of a button**. See EasyButtonExample example.
2521

22+
## Table of available pins for the 2 buttons
23+
| CPU | Button 0 | Button 1 using INT1 | Button 1 using PCINT, if INT1_PIN is defined !=3 |
24+
|-|-|-|-|
25+
| ATmega328* | D2 | D3 | Pin 0 to 2, 4 to 7 |
26+
| ATtiny5x | PB2 | | PB0 - PB5 |
27+
| ATtiny167 | PB6 | PA3 | PA0 to PA2, PA4 to PA7 |
2628

29+
To use the PCINT buttons instead of the default one, just define INT1_PIN **before** including *EasyButtonAtInt01.cpp.h*.<br/>
30+
E.g. `#define INT1_PIN 7`. See [EasyButtonExample.cpp](examples/EasyButtonExample/EasyButtonExample.ino#L46).
2731

2832
## Usage
2933
To use a single button, it needs only:
@@ -36,32 +40,36 @@ EasyButton Button0AtPin2;
3640
void setup() {}
3741
void loop() {
3842
...
39-
digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState); // initial value is false
43+
digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState); // The value at the first call after first press is true
4044
...
4145
}
4246
```
4347
To use 2 buttons, it needs only:
48+
4449
```
4550
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
4651
#define USE_BUTTON_1 // Enable code for button at INT1 (pin3)
4752
#include "EasyButtonAtInt01.cpp.h"
4853
EasyButton Button0AtPin2(true); // true -> Button is connected to INT0 (pin2)
49-
EasyButton Button0AtPin3(false); // false -> Button is not connected to INT0 => connected to INT1 (pin3)
54+
EasyButton Button1AtPin3(false); // false -> Button is not connected to INT0 => connected to INT1 (pin3)
5055
5156
void setup() {}
5257
void loop() {
5358
...
5459
digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState);
55-
delay(50);
56-
digitalWrite(LED_BUILTIN, Button0AtPin3.ButtonToggleState);
57-
delay(50);
60+
delay(100);
61+
digitalWrite(LED_BUILTIN, Button1AtPin3.ButtonToggleState);
62+
delay(200);
5863
...
5964
}
6065
```
6166

6267
## Usage of callback function
6368
The callback function is is called on every button press with ButtonToggleState as parameter.<br/>
64-
Before callback function is called, interrupts are enabled! This allows the timer interrupt for millis() to work!
69+
**The value at the first call (after first press) is true**.<br/>
70+
The callback function runs in an interrupt service context, which means it should be as short as possible.
71+
But before callback function is called, interrupts are enabled.
72+
This allows the timer interrupt for millis() to work and therfore **delay() and millis() can be used in the callback function**.
6573

6674
```
6775
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
@@ -77,10 +85,49 @@ void setup() {}
7785
void loop() {}
7886
```
7987

80-
## Handling multiple definition error
81-
If you get the error "multiple definition of `__vector_1'" (or `__vector_2') because another library uses the attachInterrupt() function,
88+
## Long press detection
89+
Check it cyclical in your loop. Do not forget, that you will get a callback (if enabled) at the start of the long press.
90+
The blocking call only blocks if button is pressed, otherwise it returns immediately.
91+
92+
```
93+
void loop() {
94+
...
95+
// default long press period is 400 ms
96+
if (Button1AtPin3.checkForLongPressBlocking()) {
97+
doSomething();
98+
}
99+
...
100+
}
101+
```
102+
103+
## Double press detection
104+
Call checkForDoublePress() only from callback function. It will not work as expected called outside the callback function.
105+
106+
```
107+
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
108+
#include "EasyButtonAtInt01.cpp.h"
109+
110+
void printButtonToggleState(bool aButtonToggleState);
111+
EasyButton Button0AtPin2(&printButtonToggleState);
112+
113+
// initial value is false, so first call is with true
114+
void printButtonToggleState(bool aButtonToggleState) {
115+
digitalWrite(LED_BUILTIN, aButtonToggleState);
116+
// This function works reliable only if called in callback function
117+
if (Button0AtPin2.checkForDoublePress()) {
118+
Serial.println(F("Button 0 double press (< 400 ms) detected"));
119+
}
120+
}
121+
122+
void setup() {}
123+
void loop() {}
124+
```
125+
126+
## Handling the `multiple definition` error
127+
If you get the error `multiple definition of __vector_1` (or `__vector_2`) because another library uses the attachInterrupt() function,
82128
then comment out the line `#define USE_ATTACH_INTERRUPT` in *EasyButtonAtInt01.h* or
83129
define global symbol with `-DUSE_ATTACH_INTERRUPT` which is not yet possible in Arduino IDE:-(.<br/>
130+
84131
## Consider to use [Sloeber](http://eclipse.baeyens.it/stable.php?OS=Windows) as IDE<br/>
85132
If you are using Sloeber as your IDE, you can easily define global symbols at *Properties/Arduino/CompileOptions*.<br/>
86133

@@ -90,16 +137,22 @@ EasyButton(bool aIsButtonAtINT0); // Constructor
90137
EasyButton(bool aIsButtonAtINT0, void (*aButtonPressCallback)(bool aButtonToggleState)); // Constructor
91138
void init(); // used by constructors
92139
140+
#define EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS 400
141+
#define EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS 400
142+
93143
bool readButtonState();
94144
bool updateButtonState();
95145
uint16_t updateButtonPressDuration();
96-
uint8_t checkForLongPress(uint16_t aLongPressThresholdMillis);
97-
bool checkForLongPressBlocking(uint16_t aLongPressThresholdMillis);
98-
bool checkForDoublePress(uint16_t aDoublePressDelayMillis);
146+
uint8_t checkForLongPress(uint16_t aLongPressThresholdMillis = EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS);
147+
bool checkForLongPressBlocking(uint16_t aLongPressThresholdMillis = EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS);
148+
bool checkForDoublePress(uint16_t aDoublePressDelayMillis = EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS);
99149
bool checkForForButtonNotPressedTime(uint16_t aTimeoutMillis);
100150
```
101151

102152
# Revision History
153+
### Version 2.1.0
154+
- Avoid 1 ms delay for `checkForLongPressBlocking()` if button is not pressed.
155+
- Only one true result per press for `checkForLongPressBlocking()`.
103156

104157
### Version 2.0.0
105158
- Ported to ATtinyX5 and ATiny167.
@@ -114,7 +167,7 @@ bool checkForForButtonNotPressedTime(uint16_t aTimeoutMillis);
114167
- initial version for ATmega328.
115168

116169
# CI
117-
Since Travis CI is unreliable and slow, the library examples are now tested with GitHub Actions for the following boards:
170+
The library examples are tested with GitHub Actions for the following boards:
118171

119172
- arduino:avr:uno
120173
- arduino:avr:leonardo

examples/Callback/Callback.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
void showButtonToggleState(bool aButtonToggleState); // The callback function
3434
EasyButton Button0AtPin2(&showButtonToggleState); // Only 1. button (USE_BUTTON_0) enabled -> button is connected to INT0 (pin2)
3535

36-
#define VERSION_EXAMPLE "2.0"
36+
#define VERSION_EXAMPLE "2.1"
3737

3838
#if defined(ARDUINO_AVR_DIGISPARK)
3939
#define LED_BUILTIN PB1
@@ -69,7 +69,7 @@ void showButtonToggleState(bool aButtonToggleState) {
6969
/*
7070
* Double press (< 200 ms) detection by calling checkForForDoublePress() once at button press time.
7171
*/
72-
if (Button0AtPin2.checkForDoublePress(200)) {
73-
Serial.println(F("Double press (< 200 ms) detected"));
72+
if (Button0AtPin2.checkForDoublePress(300)) {
73+
Serial.println(F("Double press (< 300 ms) detected"));
7474
}
7575
}

examples/DebounceTest/DebounceTest.ino

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828

2929
//#define USE_ATTACH_INTERRUPT // enable it if you get the error " multiple definition of `__vector_1'" (or `__vector_2')
3030
//#define MEASURE_INTERRUPT_TIMING
31+
//#define DO_NOT_REQUIRE_LONG_AND_DOUBLE_PRESS
3132

33+
#define ANALYZE_MAX_BOUNCING_PERIOD
3234
#define BUTTON_DEBOUNCING_MILLIS 2
3335

3436
#define USE_BUTTON_0 // Enable code for 1. button at INT0

examples/EasyButtonExample/ATtinySerialOut.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -233,27 +233,27 @@ void writeByte(int8_t aByte) {
233233
writeStringSkipLeadingSpaces(tStringBuffer);
234234
}
235235

236-
void writeInt(int aInteger) {
236+
void writeInt(int16_t aInteger) {
237237
char tStringBuffer[7];
238238
itoa(aInteger, tStringBuffer, 10);
239239
writeStringSkipLeadingSpaces(tStringBuffer);
240240
}
241241

242-
void writeUnsignedInt(unsigned int aInteger) {
242+
void writeUnsignedInt(uint16_t aInteger) {
243243
char tStringBuffer[6];
244-
itoa(aInteger, tStringBuffer, 10);
244+
utoa(aInteger, tStringBuffer, 10);
245245
writeStringSkipLeadingSpaces(tStringBuffer);
246246
}
247247

248-
void writeLong(long aLong) {
248+
void writeLong(int32_t aLong) {
249249
char tStringBuffer[12];
250250
ltoa(aLong, tStringBuffer, 10);
251251
writeStringSkipLeadingSpaces(tStringBuffer);
252252
}
253253

254-
void writeUnsignedLong(unsigned long aLong) {
254+
void writeUnsignedLong(uint32_t aLong) {
255255
char tStringBuffer[11];
256-
ltoa(aLong, tStringBuffer, 10);
256+
ultoa(aLong, tStringBuffer, 10);
257257
writeStringSkipLeadingSpaces(tStringBuffer);
258258
}
259259

@@ -373,27 +373,27 @@ void TinySerialOut::print(uint8_t aByte, uint8_t aBase) {
373373
}
374374
}
375375

376-
void TinySerialOut::print(int aInteger, uint8_t aBase) {
376+
void TinySerialOut::print(int16_t aInteger, uint8_t aBase) {
377377
char tStringBuffer[7];
378378
itoa(aInteger, tStringBuffer, aBase);
379379
writeStringSkipLeadingSpaces(tStringBuffer);
380380
}
381381

382-
void TinySerialOut::print(unsigned int aInteger, uint8_t aBase) {
382+
void TinySerialOut::print(uint16_t aInteger, uint8_t aBase) {
383383
char tStringBuffer[6];
384-
itoa(aInteger, tStringBuffer, aBase);
384+
utoa(aInteger, tStringBuffer, aBase);
385385
writeStringSkipLeadingSpaces(tStringBuffer);
386386
}
387387

388-
void TinySerialOut::print(long aLong, uint8_t aBase) {
388+
void TinySerialOut::print(int32_t aLong, uint8_t aBase) {
389389
char tStringBuffer[12];
390390
ltoa(aLong, tStringBuffer, aBase);
391391
writeStringSkipLeadingSpaces(tStringBuffer);
392392
}
393393

394-
void TinySerialOut::print(unsigned long aLong, uint8_t aBase) {
394+
void TinySerialOut::print(uint32_t aLong, uint8_t aBase) {
395395
char tStringBuffer[11];
396-
ltoa(aLong, tStringBuffer, aBase);
396+
ultoa(aLong, tStringBuffer, aBase);
397397
writeStringSkipLeadingSpaces(tStringBuffer);
398398
}
399399

@@ -423,22 +423,22 @@ void TinySerialOut::println(uint8_t aByte, uint8_t aBase) {
423423
println();
424424
}
425425

426-
void TinySerialOut::println(int aInteger, uint8_t aBase) {
426+
void TinySerialOut::println(int16_t aInteger, uint8_t aBase) {
427427
print(aInteger, aBase);
428428
println();
429429
}
430430

431-
void TinySerialOut::println(unsigned int aInteger, uint8_t aBase) {
431+
void TinySerialOut::println(uint16_t aInteger, uint8_t aBase) {
432432
print(aInteger, aBase);
433433
println();
434434
}
435435

436-
void TinySerialOut::println(long aLong, uint8_t aBase) {
436+
void TinySerialOut::println(int32_t aLong, uint8_t aBase) {
437437
print(aLong, aBase);
438438
println();
439439
}
440440

441-
void TinySerialOut::println(unsigned long aLong, uint8_t aBase) {
441+
void TinySerialOut::println(uint32_t aLong, uint8_t aBase) {
442442
print(aLong, aBase);
443443
println();
444444
}

examples/EasyButtonExample/ATtinySerialOut.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,10 @@ void writeByte(int8_t aByte);
151151
void writeUnsignedByte(uint8_t aByte);
152152
void writeUnsignedByteHex(uint8_t aByte);
153153
void writeUnsignedByteHexWithPrefix(uint8_t aByte);
154-
void writeInt(int aInteger);
155-
void writeUnsignedInt(unsigned int aInteger);
156-
void writeLong(long aLong);
157-
void writeUnsignedLong(unsigned long aLong);
154+
void writeInt(int16_t aInteger);
155+
void writeUnsignedInt(uint16_t aInteger);
156+
void writeLong(int32_t aLong);
157+
void writeUnsignedLong(uint32_t aLong);
158158
void writeFloat(double aFloat);
159159
void writeFloat(double aFloat, uint8_t aDigits);
160160

@@ -185,20 +185,20 @@ class TinySerialOut
185185
void print(const char* aStringPtr);
186186
void print(char aChar);
187187
void print(uint8_t aByte, uint8_t aBase = 10);
188-
void print(int aInteger, uint8_t aBase = 10);
189-
void print(unsigned int aInteger, uint8_t aBase = 10);
190-
void print(long aLong, uint8_t aBase = 10);
191-
void print(unsigned long aLong, uint8_t aBase = 10);
188+
void print(int16_t aInteger, uint8_t aBase = 10);
189+
void print(uint16_t aInteger, uint8_t aBase = 10);
190+
void print(int32_t aLong, uint8_t aBase = 10);
191+
void print(uint32_t aLong, uint8_t aBase = 10);
192192
void print(double aFloat, uint8_t aDigits = 2);
193193

194194
void println(const char* aStringPtr);
195195
void println(const __FlashStringHelper * aStringPtr);
196196
void println(char aChar);
197197
void println(uint8_t aByte, uint8_t aBase = 10);
198-
void println(int aInteger, uint8_t aBase = 10);
199-
void println(unsigned int aInteger, uint8_t aBase = 10);
200-
void println(long aLong, uint8_t aBase = 10);
201-
void println(unsigned long aLong, uint8_t aBase = 10);
198+
void println(int16_t aInteger, uint8_t aBase = 10);
199+
void println(uint16_t aInteger, uint8_t aBase = 10);
200+
void println(int32_t aLong, uint8_t aBase = 10);
201+
void println(uint32_t aLong, uint8_t aBase = 10);
202202
void println(double aFloat, uint8_t aDigits = 2);
203203

204204
void println(void);

0 commit comments

Comments
 (0)