Skip to content

Commit

Permalink
version 3.4.0 - ButtonStateIsActive is now private
Browse files Browse the repository at this point in the history
  • Loading branch information
ArminJo committed Oct 15, 2023
1 parent 2bf373f commit a437c44
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/LibraryBuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,5 @@ jobs:
platform-url: ${{ matrix.platform-url }}
# sketches-exclude: ${{ matrix.sketches-exclude }}
build-properties: ${{ toJson(matrix.build-properties) }}
cli-version: 0.33.0 # to avoid errors for ATTinyCore

98 changes: 62 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
<div align = center>

# [EasyButton](https://github.com/ArminJo/EasyButtonAtInt01)
Lightweight Arduino library for handling push buttons just connected between ground and INT0 and / or INT1 pin.
Lightweight Arduino library for handling push buttons just connected between ground and INT0 and / or INT1 or any other PCINT pin.

[![Badge License: GPLv3](https://img.shields.io/badge/License-GPLv3-brightgreen.svg)](https://www.gnu.org/licenses/gpl-3.0)
&nbsp; &nbsp;
[![Badge Version](https://img.shields.io/github/v/release/ArminJo/EasyButtonAtInt01?include_prereleases&color=yellow&logo=DocuSign&logoColor=white)](https://github.com/ArminJo/EasyButtonAtInt01/releases/latest)
&nbsp; &nbsp;
[![Badge Commits since latest](https://img.shields.io/github/commits-since/ArminJo/EasyButtonAtInt01/latest?color=yellow)](https://github.com/ArminJo/EasyButtonAtInt01/commits/master)
&nbsp; &nbsp;
[![Badge Build Status](https://github.com/ArminJo/EasyButtonAtInt01/workflows/LibraryBuild/badge.svg)](https://github.com/ArminJo/EasyButtonAtInt01/actions)
&nbsp; &nbsp;
![Badge Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=ArminJo_EasyButtonAtInt01)
<br/>
<br/>
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)

Available as [Arduino library "EasyButtonAtInt01"](https://www.arduinolibraries.info/libraries/easy-button-at-int01).

### [Version 3.3.2](https://github.com/ArminJo/EasyButtonAtInt01/releases) - work in progress
[![Button Install](https://img.shields.io/badge/Install-brightgreen?logoColor=white&logo=GitBook)](https://www.ardu-badge.com/EasyButtonAtInt01)
&nbsp; &nbsp;
[![Button Changelog](https://img.shields.io/badge/Changelog-blue?logoColor=white&logo=AzureArtifacts)](https://github.com/ArminJo/EasyButtonAtInt01#revision-history)

[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Installation instructions](https://www.ardu-badge.com/badge/EasyButtonAtInt01.svg?)](https://www.ardu-badge.com/EasyButtonAtInt01)
[![Commits since latest](https://img.shields.io/github/commits-since/ArminJo/EasyButtonAtInt01/latest)](https://github.com/ArminJo/EasyButtonAtInt01/commits/master)
[![Build Status](https://github.com/ArminJo/EasyButtonAtInt01/workflows/LibraryBuild/badge.svg)](https://github.com/ArminJo/EasyButtonAtInt01/actions)
![Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=ArminJo_EasyButtonAtInt01)
</div>

Available as [Arduino library "EasyButtonAtInt01"](https://www.arduinolibraries.info/libraries/easy-button-at-int01).
#### If you find this library useful, please give it a star.

<br/>

# Features
- No external pullup, **no polling needed**.
Expand Down Expand Up @@ -97,7 +114,7 @@ void loop() {}
```
## Long press detection
The easiest way is to check it in the button release handler. Do not forget, that you will get a press callback (if enabled) at the start of the long press.
The easiest way is to use the button release handler. Keep in mind, that you will get a press callback at the start of the long press.
```c++
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
Expand All @@ -116,13 +133,33 @@ handleButtonRelease(bool aButtonToggleState, uint16_t aButtonPressDurationMillis
void setup() {}
void loop() {}
```

Or check in loop, this enables to react with feedback as soon as long press duration is reached.

```c++
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
#include "EasyButtonAtInt01.hpp"

bool sLongPressMessageSent = false;
void handleButtonPress(bool aButtonToggleState, uint16_t aButtonPressDurationMillis) {sLongPressMessageSent = false};
EasyButton Button0AtPin2(&handleButtonPress); // Button is connected to INT0 (pin2)

void setup() {}
void loop() {
if (!sLongPressMessageSent && Button0AtPin2.checkForLongPress(1000) == EASY_BUTTON_LONG_PRESS_DETECTED) {
Serial.println(F("Long press of 1000 ms just detected"));
sLongPressMessageSent = true; // Print message only once per long press
}

```
if (sLCDDisplayPage == POWER_METER_PAGE_INFO && PageButtonAtPin3.checkForLongPress(1000) == EASY_BUTTON_LONG_PRESS_DETECTED) {
## Double press detection
Call checkForDoublePress() only from button press callback function. It will not work as expected called outside this callback function.
Be aware, that the first press after booting may be detected as double press!
This is because the "last time of press" `ButtonReleaseMillis` is initialized with 0 milliseconds, which is interpreted as the first press happened at the beginning of boot.
**Call checkForDoublePress() only from button press callback function**. It will not work as expected, if called outside this callback function.
```c++
#define USE_BUTTON_0 // Enable code for button at INT0 (pin2)
Expand All @@ -144,10 +181,13 @@ void setup() {}
void loop() {}
```

## Handling the `multiple definition` error
<br/>

# Handling the `multiple definition` error
If you get the error `multiple definition of __vector_1` (or `__vector_2`) because another library uses the attachInterrupt() function,
then activate the line `#define USE_ATTACH_INTERRUPT` in *EasyButtonAtInt01.h* or
define global symbol with `-DUSE_ATTACH_INTERRUPT` which is not yet possible in Arduino IDE :disappointed:.<br/>
then insert the line `#define USE_ATTACH_INTERRUPT` in your program **before** the line `#include "EasyButtonAtInt01.hpp"`.

<br/>


# Compile options / macros for this library
Expand All @@ -156,7 +196,7 @@ These macros must be defined in your program **before** the line `#include "Easy
Modify them by enabling / disabling them, or change the values if applicable.

| Name | Default value | Description |
|-|-|-|
|-|-:|-|
| `USE_BUTTON_0` | disabled | Enables code for button at INT0 (pin2 on 328P, PB6 on ATtiny167, PB2 on ATtinyX5). The macro INT0_PIN is set after the include. |
| `USE_BUTTON_1` | disabled | Enables code for button at INT1 (pin3 on 328P, PA3 on ATtiny167, PCINT0 / PCx for ATtinyX5). The macro INT1_PIN is set after the include. |
| `INT1_PIN` | % | It overrides the usage of pin at the processors INT1 pin. Thus, it is the pin number of the pin for button 1 to use with Pin Change Interrupts. |
Expand All @@ -172,20 +212,6 @@ Modify them by enabling / disabling them, or change the values if applicable.

The exact pin numbers of the buttons used internally are available by the macros INT0_PIN and INT1_PIN, which are set after the include.

### Changing include (*.h) files with Arduino IDE
First, use *Sketch > Show Sketch Folder (Ctrl+K)*.<br/>
If you have not yet saved the example as your own sketch, then you are instantly in the right library folder.<br/>
Otherwise you have to navigate to the parallel `libraries` folder and select the library you want to access.<br/>
In both cases the library source and include files are located in the libraries `src` directory.<br/>
The modification must be renewed for each new library version!
### Modifying compile options / macros with PlatformIO
If you are using PlatformIO, you can define the macros in the *[platformio.ini](https://docs.platformio.org/en/latest/projectconf/section_env_build.html)* file with `build_flags = -D MACRO_NAME` or `build_flags = -D MACRO_NAME=macroValue`.
### Modifying compile options / macros with Sloeber IDE
If you are using [Sloeber](https://eclipse.baeyens.it) as your IDE, you can easily define global symbols with *Properties > Arduino > CompileOptions*.<br/>
![Sloeber settings](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/pictures/SloeberDefineSymbols.png)
## Class methods
```c++
EasyButton(); // Constructor for button at INT0
Expand All @@ -200,6 +226,7 @@ void init(); // used by constructors
#define EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS 400

bool readButtonState();
bool readDebouncedButtonState();
bool updateButtonState();
uint16_t updateButtonPressDuration();
uint8_t checkForLongPress(uint16_t aLongPressThresholdMillis = EASY_BUTTON_LONG_PRESS_DEFAULT_MILLIS);
Expand All @@ -209,7 +236,11 @@ bool checkForForButtonNotPressedTime(uint16_t aTimeoutMillis);
```
# Revision History
### Version 3.3.2 - work in progress
### Version 3.4.1 - work in progress
### Version 3.4.0
- Added `NO_INITIALIZE_IN_CONSTRUCTOR` macro to enable late initializing.
- `ButtonStateIsActive` is now private, since it is not reliable after bouncing. Use `readButtonState()` or `readDebouncedButtonState()` instead.
### Version 3.3.1
- Avoid mistakenly double press detection after boot.
Expand Down Expand Up @@ -255,8 +286,3 @@ The library examples are tested with GitHub Actions for the following boards:
- digistump:avr:digispark-tiny1
- digistump:avr:digispark-pro
- ATTinyCore:avr:attinyx5:chip=85,clock=1internal

## Requests for modifications / extensions
Please write me a PM including your motivation/problem if you need a modification or an extension e.g. PCINT* support for ATtiny85.

#### If you find this library useful, please give it a star.
2 changes: 1 addition & 1 deletion examples/DebounceTest/DebounceTest.ino
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void loop() {
* Print new status
*/
Serial.print(F("Button1 IsActive="));
Serial.print(Button0AtPin2.ButtonStateIsActive);
Serial.print(Button0AtPin2.getButtonStateIsActive());
Serial.print(F(" ToggleState="));
Serial.println(Button0AtPin2.ButtonToggleState);
}
Expand Down
20 changes: 17 additions & 3 deletions examples/TwoButtons/TwoButtons.ino
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@

#include "EasyButtonAtInt01.hpp"

// The callback function for button 0
void handleButtonPress(bool aButtonToggleState);
void handleButtonPress(bool aButtonToggleState); // The callback function for button 0
EasyButton Button0AtPin2(&handleButtonPress); // Only callback parameter -> button is connected to INT0
EasyButton Button1AtPin3(BUTTON_AT_INT1_OR_PCINT); // Button is connected to INT1 or INT1_PIN if INT1_PIN is defined.
#define LONG_PRESS_BUTTON_DURATION_MILLIS 1000
bool sLongPressMessageSent = false;

long sOldDeltaMillis;

Expand All @@ -86,6 +87,17 @@ void setup() {

void loop() {

/*
* Check for long press of button 0
*/
if (!sLongPressMessageSent
&& Button0AtPin2.checkForLongPress(LONG_PRESS_BUTTON_DURATION_MILLIS) == EASY_BUTTON_LONG_PRESS_DETECTED) {
Serial.print(F("Long press of "));
Serial.print(LONG_PRESS_BUTTON_DURATION_MILLIS);
Serial.println(F(" ms just detected"));
sLongPressMessageSent = true; // Print message only once per long press
}

/*
* Button 1 - check manually here as demonstration, but it would be easier to just use a callback function like we do for button 0
*/
Expand All @@ -99,7 +111,7 @@ void loop() {
* Print new status
*/
Serial.print(F("Button 1 IsActive="));
Serial.print(Button1AtPin3.ButtonStateIsActive);
Serial.print(Button1AtPin3.getButtonStateIsActive());
Serial.print(F(" ToggleState="));
Serial.print(Button1AtPin3.ButtonToggleState);
if (!Button1AtPin3.readDebouncedButtonState()) {
Expand All @@ -112,6 +124,8 @@ void loop() {
}

void handleButtonPress(bool aButtonToggleState) {
sLongPressMessageSent = false; // reset flag

/*
* checkForDoublePress() works reliable only, if called early in press callback function
*/
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/ArminJo/EasyButtonAtInt01"
},
"version": "3.3.1",
"version": "3.4.0",
"exclude": "pictures",
"authors": {
"name": "Armin Joachimsmeyer",
Expand Down
6 changes: 3 additions & 3 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=EasyButtonAtInt01
version=3.3.1
version=3.4.0
author=Armin Joachimsmeyer
maintainer=Armin Joachimsmeyer <[email protected]>
sentence=Small and easy to use Arduino library for using push buttons at INT0/pin2 and / or any PinChangeInterrupt pin.<br/>Functions for long and double press detection are included.<br/><br/>Just connect buttons between ground and any pin of your Arduino - that's it<br/><br/><b>No call</b> of begin() or polling function like update() required. No blocking debouncing delay.<br/>
paragraph=<br/>Define an EasyButtonIn in you main program and use <i>ButtonStateIsActive</i> or <i>ButtonToggleState</i> to determine your action.<br/>Or use a <b>callback function</b> which will be called once on every button press or release.<br/><br/>Usage:<pre>#define USE_BUTTON_0<br/>#include "EasyButtonAtInt01.hpp"<br/>EasyButton Button0AtPin2;<br/><br/>void setup() {}<br/>void loop() {<br/>...<br/> digitalWrite(LED_BUILTIN, Button0AtPin2.ButtonToggleState);<br/>...<br/>}</pre><br/><br/><b>New: </b>Avoid mistakenly double press detection after boot.</b><br/>
sentence=Small and easy to use Arduino library for using push buttons at any PinChangeInterrupt pin. Automatic debouncing, no delay required. Functions for long and double press detection are included.
paragraph=Define an EasyButton in you main program and use a callback function which will be called once on every button press or release.
category=Signal Input/Output
url=https://github.com/ArminJo/EasyButtonAtInt01
architectures=avr
Expand Down
18 changes: 13 additions & 5 deletions src/EasyButtonAtInt01.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
#ifndef _EASY_BUTTON_AT_INT01_H
#define _EASY_BUTTON_AT_INT01_H

#define VERSION_EASY_BUTTON "3.3.2"
#define VERSION_EASY_BUTTON "3.4.0"
#define VERSION_EASY_BUTTON_MAJOR 3
#define VERSION_EASY_BUTTON_MINOR 3
#define VERSION_EASY_BUTTON_PATCH 2
#define VERSION_EASY_BUTTON_MINOR 4
#define VERSION_EASY_BUTTON_PATCH 0
// The change log is at the bottom of the file

/*
Expand Down Expand Up @@ -291,6 +291,7 @@ class EasyButton {
bool checkForDoublePress(uint16_t aDoublePressDelayMillis = EASY_BUTTON_DOUBLE_PRESS_DEFAULT_MILLIS);

bool readButtonState();
bool getButtonStateIsActive(); // get private member
bool readDebouncedButtonState();
bool updateButtonState();
uint16_t updateButtonPressDuration(); // Updates the ButtonPressDurationMillis by polling, since this cannot be done by interrupt.
Expand All @@ -304,7 +305,6 @@ class EasyButton {
void handleINT01Interrupts(); // internal use only

bool LastBounceWasChangeToInactive; // Internal state, reflects actual reading with spikes and bouncing. Negative logic: true / active means button pin is LOW
volatile bool ButtonStateIsActive; // State at last change. Negative logic: true / active means button pin is LOW. If last press duration < BUTTON_DEBOUNCING_MILLIS it holds wrong value (true instead of false) :-(
volatile bool ButtonToggleState; // Toggle is on press, not on release - initial value is false

/*
Expand Down Expand Up @@ -351,6 +351,13 @@ class EasyButton {
#if defined(USE_BUTTON_1)
static EasyButton *sPointerToButton1ForISR;
#endif

private:
/*
* If last press duration < BUTTON_DEBOUNCING_MILLIS it holds wrong value (true instead of false), therefore it is private.
* To get current state, use readButtonState().
*/
volatile bool ButtonStateIsActive; // State at last change. Negative logic: true / active means button pin is LOW.
};
// end of class definition

Expand All @@ -371,8 +378,9 @@ void __attribute__ ((weak)) handleINT1Interrupt();
#endif // defined(__AVR__)

/*
* Version 3.3.2 - 9/2022
* Version 3.3.2 - 10/2023
* - Added NO_INITIALIZE_IN_CONSTRUCTOR macro to enable late initializing.
* - ButtonStateIsActive is now private, since it is not reliable after bouncing. Use readButtonState() or readDebouncedButtonState() instead.
*
* Version 3.3.1 - 2/2022
* - Avoid mistakenly double press detection after boot.
Expand Down
4 changes: 4 additions & 0 deletions src/EasyButtonAtInt01.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,10 @@ bool EasyButton::readButtonState() {

// @formatter:on

bool EasyButton::getButtonStateIsActive() {
return ButtonStateIsActive;

}
/*
* Returns stored state if in debouncing period otherwise current state of button
*/
Expand Down

0 comments on commit a437c44

Please sign in to comment.