├── .github └── FUNDING.yml ├── assets └── social-media │ ├── social-media.png │ └── social-media.afdesign ├── library.properties ├── src ├── EasyButtonVirtual.h ├── EasyButtonTouch.cpp ├── Sequence.cpp ├── EasyButtonTouch.h ├── Sequence.h ├── EasyButton.h ├── EasyButtonVirtual.cpp ├── EasyButtonBase.cpp ├── EasyButton.cpp └── EasyButtonBase.h ├── library.json ├── examples ├── Pressed │ └── Pressed.ino ├── TouchButton │ └── TouchButton.ino ├── Sequence │ └── Sequence.ino ├── PressedForDuration │ └── PressedForDuration.ino ├── MultipleSequence │ └── MultipleSequence.ino ├── Interrupts │ └── Interrupts.ino ├── MultipleButtons │ └── MultipleButtons.ino ├── InterruptsOnPressedFor │ └── InterruptsOnPressedFor.ino └── VirtualButton │ └── VirtualButton.ino ├── LICENSE ├── keywords.txt ├── .gitignore └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: evert-arias 2 | custom: ["https://www.buymeacoffee.com/earias"] 3 | -------------------------------------------------------------------------------- /assets/social-media/social-media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evert-arias/EasyButton/HEAD/assets/social-media/social-media.png -------------------------------------------------------------------------------- /assets/social-media/social-media.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evert-arias/EasyButton/HEAD/assets/social-media/social-media.afdesign -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=EasyButton 2 | version=2.0.3 3 | author=Evert Arias 4 | maintainer=Evert Arias 5 | sentence=Arduino library for debouncing momentary contact switches, detect press, release, long press and sequences with event definitions and callbacks. 6 | paragraph=EasyButton is an small Arduino library for debouncing momentary contact switches like tactile buttons. It uses events and callbacks to trigger actions when a button is pressed once or held for a given duration. It also provides a sequence counter to be able to rise an event when a given pattern of presses has been matched. 7 | category=Signal Input/Output 8 | url=https://easybtn.earias.me 9 | architectures=* 10 | depends=MegunoLink 11 | -------------------------------------------------------------------------------- /src/EasyButtonVirtual.h: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonVirtual.h 3 | * @author Evert Arias, Jose Gabriel Companioni Benitez 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #ifndef _EasyButtonVirtual_h 9 | #define _EasyButtonVirtual_h 10 | 11 | #include 12 | #include "EasyButtonBase.h" 13 | 14 | class EasyButtonVirtual : public EasyButtonBase 15 | { 16 | private: 17 | bool &_button_abstraction; 18 | 19 | public: 20 | EasyButtonVirtual(bool &button_abstraction, bool active_low = true) : EasyButtonBase(active_low), _button_abstraction(button_abstraction) {} 21 | 22 | // PUBLIC FUNCTIONS 23 | void begin(); // Initialize a button object and the pin it's connected to. 24 | bool read(); // Returns the current debounced button state, true for pressed, false for released. 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /src/EasyButtonTouch.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonTouch.cpp 3 | * @author Evert Arias, Gutierrez PS, Felix A. Epp 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #if defined(ESP32) 9 | #include "EasyButtonTouch.h" 10 | #if defined(SOC_TOUCH_SENSOR_SUPPORTED) || (defined(SOC_TOUCH_SENSOR_NUM) && SOC_TOUCH_SENSOR_NUM > 1) 11 | 12 | void EasyButtonTouch::setThreshold(int threshold) 13 | { 14 | _touch_threshold = threshold; 15 | } 16 | 17 | void EasyButtonTouch::begin(int threshold) 18 | { 19 | _touch_threshold = threshold; 20 | begin(); 21 | } 22 | 23 | void EasyButtonTouch::begin() 24 | { 25 | _current_state = _readPin(); 26 | _time = millis(); 27 | _last_state = _current_state; 28 | _changed = false; 29 | _last_change = _time; 30 | } 31 | 32 | bool EasyButtonTouch::_readPin() 33 | { 34 | ADCFilter.Filter(touchRead(_pin)); 35 | return ADCFilter.Current() < _touch_threshold; 36 | } 37 | #endif 38 | #endif -------------------------------------------------------------------------------- /src/Sequence.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Sequence.h 3 | * @author Evert Arias, Jose Gabriel Companioni Benitez 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #include "Sequence.h" 9 | 10 | bool Sequence::newPress(uint32_t read_started_ms) 11 | { 12 | if (_is_enabled) 13 | { 14 | if (_short_press_count == 0) 15 | { 16 | _first_press_time = read_started_ms; 17 | } 18 | 19 | _short_press_count++; 20 | 21 | if (_short_press_count == _press_sequences && _press_sequence_duration >= (read_started_ms - _first_press_time)) 22 | { 23 | // Pressed sequence 24 | reset(); 25 | return true; 26 | } 27 | else if (_press_sequence_duration <= (read_started_ms - _first_press_time)) 28 | { 29 | // Sequence timeout 30 | _short_press_count = 1; 31 | _first_press_time = read_started_ms; 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | void Sequence::reset() 38 | { 39 | _short_press_count = 0; 40 | _first_press_time = 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/EasyButtonTouch.h: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonTouch.h 3 | * @author Evert Arias, Gutierrez PS, Felix A. Epp 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #if !defined(_EasyButtonTouch_h) and defined(ESP32) 9 | #define _EasyButtonTouch_h 10 | #include 11 | #if defined(SOC_TOUCH_SENSOR_SUPPORTED) || (defined(SOC_TOUCH_SENSOR_NUM) && SOC_TOUCH_SENSOR_NUM > 1) 12 | 13 | #include 14 | #include 15 | #include "EasyButton.h" 16 | 17 | class EasyButtonTouch : public EasyButton 18 | { 19 | public: 20 | EasyButtonTouch(uint8_t pin, uint32_t debounce_time = 35, uint16_t threshold = 50) : EasyButton(pin, debounce_time, false, false), _touch_threshold(threshold), ADCFilter(5, threshold) {} 21 | void begin(); 22 | void begin(int threshold); 23 | void setThreshold(int threshold); 24 | 25 | private: 26 | uint16_t _touch_threshold; // If touchRead() is below the threshold, the button is considered pressed. 27 | ExponentialFilter ADCFilter; 28 | 29 | bool _readPin(); 30 | }; 31 | #endif 32 | #endif -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EasyButton", 3 | "keywords": "IO, button, sensor, arduino", 4 | "description": "EasyButton is an small Arduino library for debouncing momentary contact switches like tactile buttons. It uses events and callbacks to trigger actions when a button is pressed once or held for a given duration. It also provides a sequence counter to be able to rise an event when a given pattern of presses has been matched.", 5 | "version": "2.0.3", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/evert-arias/EasyButton" 9 | }, 10 | "url": "https://easybtn.earias.me", 11 | "frameworks": "arduino", 12 | "platforms": "espressif8266, espressif32", 13 | "dependencies": [ 14 | { 15 | "owner": "megunolink", 16 | "name": "MegunoLink", 17 | "version": "^1.33" 18 | } 19 | ], 20 | "authors": [ 21 | { 22 | "name": "Evert Arias", 23 | "email": "evert.arias@hotmail.com" 24 | }, 25 | { 26 | "name": "Felix A. Epp", 27 | "url": "https://github.com/eppfel" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /examples/Pressed/Pressed.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: Pressed.ino 3 | Created: 9/5/2018 10:49:52 AM 4 | Author: Evert Arias 5 | Description: Example to demostrate how to use the library to detect a single pressed on a button. 6 | */ 7 | 8 | #include 9 | 10 | // Arduino pin where the button is connected to. 11 | #define BUTTON_PIN 2 12 | 13 | #define BAUDRATE 115200 14 | 15 | // Instance of the button. 16 | EasyButton button(BUTTON_PIN); 17 | 18 | // Callback function to be called when the button is pressed. 19 | void onPressed() 20 | { 21 | Serial.println("Button pressed"); 22 | } 23 | 24 | void setup() 25 | { 26 | // Initialize Serial for debuging purposes. 27 | Serial.begin(BAUDRATE); 28 | 29 | Serial.println(); 30 | Serial.println(">>> EasyButton pressed example <<<"); 31 | 32 | // Initialize the button. 33 | button.begin(); 34 | // Add the callback function to be called when the button is pressed. 35 | button.onPressed(onPressed); 36 | } 37 | 38 | void loop() 39 | { 40 | // Continuously read the status of the button. 41 | button.read(); 42 | } 43 | -------------------------------------------------------------------------------- /examples/TouchButton/TouchButton.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: TouchButton.ino 3 | Created: 6/25/2019 9:25:52 AM 4 | Author: Evert Arias 5 | Description: Example to demostrate how to use the library to detect a single touch. 6 | */ 7 | 8 | #include 9 | 10 | // Arduino pin where the button is connected to. 11 | #define BUTTON_PIN 27 12 | 13 | #define BAUDRATE 115200 14 | 15 | // Instance of the button. 16 | EasyButtonTouch button(BUTTON_PIN); 17 | 18 | // Callback function to be called when the button is pressed. 19 | void onPressed() 20 | { 21 | Serial.println("Button has been pressed"); 22 | } 23 | 24 | void setup() 25 | { 26 | // Initialize Serial for debuging purposes. 27 | Serial.begin(BAUDRATE); 28 | 29 | Serial.println(); 30 | Serial.println(">>> EasyButton touch button example <<<"); 31 | 32 | // Initialize the button. 33 | button.begin(); 34 | // Add the callback function to be called when the button is pressed. 35 | button.onPressed(onPressed); 36 | } 37 | 38 | void loop() 39 | { 40 | // Continuously read the status of the button. 41 | button.read(); 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Evert Arias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/Sequence/Sequence.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: Sequence.ino 3 | Created: 9/5/2018 10:49:52 AM 4 | Author: Evert Arias 5 | Description: Example to demostrate how to use the library to detect a sequence of presses on a button. 6 | */ 7 | 8 | #include 9 | 10 | // Arduino pin where the button is connected to. 11 | #define BUTTON_PIN 2 12 | 13 | #define BAUDRATE 115200 14 | 15 | // Instance of the button. 16 | EasyButton button(BUTTON_PIN); 17 | 18 | // Callback function to be called when the button is pressed. 19 | void onSequenceMatched() 20 | { 21 | Serial.println("Button pressed"); 22 | } 23 | 24 | void setup() 25 | { 26 | // Initialize Serial for debuging purposes. 27 | Serial.begin(BAUDRATE); 28 | 29 | Serial.println(); 30 | Serial.println(">>> EasyButton sequence example <<<"); 31 | 32 | // Initialize the button. 33 | button.begin(); 34 | // Add the callback function to be called when the given sequence of presses is matched. 35 | button.onSequence(5 /* number of presses */, 2000 /* timeout */, onSequenceMatched /* callback */); 36 | } 37 | 38 | void loop() 39 | { 40 | // Continuously read the status of the button. 41 | button.read(); 42 | } 43 | -------------------------------------------------------------------------------- /examples/PressedForDuration/PressedForDuration.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: PressedForDuration.ino 3 | Created: 9/5/2018 10:49:52 AM 4 | Author: Evert Arias 5 | Description: Example to demostrate how to use the library to detect a pressed for a given duration on a button. 6 | */ 7 | 8 | #include 9 | 10 | // Arduino pin where the button is connected to. 11 | #define BUTTON_PIN 2 12 | 13 | #define BAUDRATE 115200 14 | 15 | // Instance of the button. 16 | EasyButton button(BUTTON_PIN); 17 | 18 | // Callback function to be called when the button is pressed. 19 | void onPressedForDuration() 20 | { 21 | Serial.println("Button pressed"); 22 | } 23 | 24 | void setup() 25 | { 26 | // Initialize Serial for debuging purposes. 27 | Serial.begin(BAUDRATE); 28 | 29 | Serial.println(); 30 | Serial.println(">>> EasyButton pressedFor example <<<"); 31 | 32 | // Initialize the button. 33 | button.begin(); 34 | // Add the callback function to be called when the button is pressed for at least the given time. 35 | button.onPressedFor(2000, onPressedForDuration); 36 | } 37 | 38 | void loop() 39 | { 40 | // Continuously read the status of the button. 41 | button.read(); 42 | } 43 | -------------------------------------------------------------------------------- /examples/MultipleSequence/MultipleSequence.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: MultipleSequence.ino 3 | Created: 03/23/2020 12:45:23 AM 4 | Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa) 5 | Description: Example to demostrate how to work with multiple sequences 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | // Arduino pin where the button is connected to. 12 | #define BUTTON_PIN 2 13 | 14 | #define BAUDRATE 115200 15 | 16 | void sequenceEllapsed() 17 | { 18 | Serial.println("Double click"); 19 | } 20 | 21 | void otherSequence() 22 | { 23 | Serial.println("Other sequence"); 24 | } 25 | 26 | // Instance of the button. 27 | EasyButton button(BUTTON_PIN); 28 | 29 | void setup() 30 | { 31 | // Initialize Serial for debuging purposes. 32 | Serial.begin(BAUDRATE); 33 | 34 | Serial.println(); 35 | Serial.println(">>> EasyButton multiple onSequence example <<<"); 36 | 37 | // Initialize the button. 38 | button.begin(); 39 | 40 | button.onSequence(2, 1500, sequenceEllapsed); 41 | 42 | button.onSequence(3, 2500, otherSequence); 43 | } 44 | 45 | void loop() 46 | { 47 | // Continuously read the status of the button. 48 | button.read(); 49 | } 50 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For EasyButton 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | EasyButton KEYWORD1 10 | EasyButtonTouch KEYWORD1 11 | EasyButtonVirtual KEYWORD1 12 | EasyButtonBase KEYWORD1 13 | Sequence KEYWORD1 14 | 15 | ####################################### 16 | # Methods and Functions (KEYWORD2) 17 | ####################################### 18 | 19 | begin KEYWORD2 20 | read KEYWORD2 21 | onPressed KEYWORD2 22 | onPressedFor KEYWORD2 23 | onSequence KEYWORD2 24 | isPressed KEYWORD2 25 | isReleased KEYWORD2 26 | wasPressed KEYWORD2 27 | wasReleased KEYWORD2 28 | pressedFor KEYWORD2 29 | releasedFor KEYWORD2 30 | enableInterrupt KEYWORD2 31 | disableInterrupt KEYWORD2 32 | supportsInterrupt KEYWORD2 33 | newPress KEYWORD2 34 | reset KEYWORD2 35 | enable KEYWORD2 36 | disable KEYWORD2 37 | 38 | ####################################### 39 | # Instances (KEYWORD2) 40 | ####################################### 41 | 42 | ####################################### 43 | # Constants (LITERAL1) 44 | ####################################### -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.gitignore.io/api/visualstudiocode,windows,platformio 4 | # Edit at https://www.gitignore.io/?templates=visualstudiocode,windows,platformio 5 | 6 | ### PlatformIO ### 7 | .pioenvs 8 | .piolibdeps 9 | .clang_complete 10 | .gcc-flags.json 11 | .pio 12 | 13 | ### VisualStudioCode ### 14 | .vscode 15 | .vscode/* 16 | !.vscode/settings.json 17 | !.vscode/tasks.json 18 | !.vscode/launch.json 19 | !.vscode/extensions.json 20 | 21 | ### VisualStudioCode Patch ### 22 | # Ignore all local history of files 23 | .history 24 | 25 | ### Windows ### 26 | # Windows thumbnail cache files 27 | Thumbs.db 28 | ehthumbs.db 29 | ehthumbs_vista.db 30 | 31 | # Dump file 32 | *.stackdump 33 | 34 | # Folder config file 35 | [Dd]esktop.ini 36 | 37 | # Recycle Bin used on file shares 38 | $RECYCLE.BIN/ 39 | 40 | # Windows Installer files 41 | *.cab 42 | *.msi 43 | *.msix 44 | *.msm 45 | *.msp 46 | 47 | # Windows shortcuts 48 | *.lnk 49 | 50 | # End of https://www.gitignore.io/api/visualstudiocode,windows,platformio 51 | 52 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 53 | 54 | -------------------------------------------------------------------------------- /src/Sequence.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Sequence.h 3 | * @author Evert Arias, Jose Gabriel Companioni Benitez 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #ifndef _EasyButtonSequence_h 9 | #define _EasyButtonSequence_h 10 | 11 | #include 12 | 13 | class Sequence 14 | { 15 | private: 16 | bool _is_enabled; 17 | uint8_t _press_sequences; // The number of sequences to count. 18 | uint32_t _press_sequence_duration; // Time limit of the sequence. 19 | uint32_t _first_press_time; // Time when button was pressed for first time. 20 | uint32_t _short_press_count; // Short press counter. 21 | 22 | public: 23 | Sequence(uint8_t sequences, uint32_t duration) : _is_enabled(false), 24 | _press_sequences(sequences), 25 | _press_sequence_duration(duration), 26 | _first_press_time(0), 27 | _short_press_count(0) 28 | { 29 | } 30 | 31 | Sequence() : Sequence(0, 0) {} 32 | 33 | bool newPress(uint32_t read_started_ms); 34 | 35 | void reset(); 36 | 37 | void enable() { _is_enabled = true; } 38 | 39 | void disable() { _is_enabled = false; } 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /examples/Interrupts/Interrupts.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: Interrupts.ino 3 | Created: 8/11/2019 11:45:52 AM 4 | Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa) 5 | Description: Example to demostrate how to use interrupts in order to improve performance 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | // Arduino pin where the buttons are connected to. 12 | #define BUTTON_PIN 2 13 | 14 | #define BAUDRATE 115200 15 | 16 | // Instance of the button. 17 | EasyButton button(BUTTON_PIN); 18 | 19 | void buttonPressed() 20 | { 21 | Serial.println("Button pressed"); 22 | } 23 | 24 | void sequenceEllapsed() 25 | { 26 | Serial.println("Double click"); 27 | } 28 | 29 | void buttonISR() 30 | { 31 | button.read(); 32 | } 33 | 34 | void setup() 35 | { 36 | 37 | // Initialize Serial for debuging purposes. 38 | Serial.begin(BAUDRATE); 39 | 40 | Serial.println(); 41 | Serial.println(">>> EasyButton interrupts example <<<"); 42 | 43 | // Initialize the button. 44 | button.begin(); 45 | 46 | button.onPressed(buttonPressed); 47 | 48 | button.onSequence(2, 1500, sequenceEllapsed); 49 | 50 | if (button.supportsInterrupt()) 51 | { 52 | button.enableInterrupt(buttonISR); 53 | Serial.println("Button will be used through interrupts"); 54 | } 55 | } 56 | 57 | void loop() 58 | { 59 | // put your main code here, to run repeatedly: 60 | } 61 | -------------------------------------------------------------------------------- /examples/MultipleButtons/MultipleButtons.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: MultipleButtons.ino 3 | Created: 3/25/2019 11:45:52 AM 4 | Author: Evert Arias 5 | Description: Example to demostrate how to use the library with more than one button 6 | */ 7 | 8 | #include 9 | 10 | // Arduino pin where the buttons are connected to 11 | #define BUTTON_ONE_PIN 2 12 | #define BUTTON_TWO_PIN 4 13 | 14 | #define BAUDRATE 115200 15 | 16 | // Button1 17 | EasyButton button1(BUTTON_ONE_PIN); 18 | // Button2 19 | EasyButton button2(BUTTON_TWO_PIN); 20 | 21 | // Callback function to be called when button1 is pressed 22 | void onButton1Pressed() 23 | { 24 | Serial.println("Button1 pressed"); 25 | } 26 | 27 | // Callback function to be called when button2 is pressed 28 | void onButton2Pressed() 29 | { 30 | Serial.println("Button2 pressed"); 31 | } 32 | 33 | void setup() 34 | { 35 | // Initialize Serial for debuging purposes 36 | Serial.begin(BAUDRATE); 37 | 38 | Serial.println(); 39 | Serial.println(">>> EasyButton multiple buttons example <<<"); 40 | 41 | // Initialize the button1 42 | button1.begin(); 43 | // Initialize the button2 44 | button2.begin(); 45 | // Add the callback function to be called when the button1 is pressed. 46 | button1.onPressed(onButton1Pressed); 47 | // Add the callback function to be called when the button2 is pressed. 48 | button2.onPressed(onButton2Pressed); 49 | } 50 | 51 | void loop() 52 | { 53 | // Continuously read the status of the buttons 54 | button1.read(); 55 | button2.read(); 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyButton 2 | 3 | > 🔥 **EasyButton 3.0 Poll**: We're considering a major update with bug fixes and improved documentation! [VOTE NOW](https://github.com/evert-arias/EasyButton/discussions/100) to help shape the future of EasyButton! 🔥 4 | 5 | [![License](https://img.shields.io/badge/license-MIT%20License-blue.svg)](http://doge.mit-license.org) 6 | 7 | Arduino library for debouncing momentary contact switches, detect press, release, long press and sequences with event definitions and callbacks. 8 | 9 | Full documentation available at: 10 | 11 | ## Description 12 | 13 | **EasyButton** is an small Arduino library for debouncing momentary contact switches like tactile buttons. It uses events and callbacks to trigger actions when a button is pressed once or held for a given duration. It also provides a sequence counter to be able to rise an event when a given pattern of presses has been matched. 14 | 15 | ## Installation 16 | 17 | 18 | 19 | ## How to use 20 | 21 | 22 | 23 | ## Examples 24 | 25 | [Single Press](https://evert-arias.github.io/easybtn-docs/docs/on-single-press-example) 26 | 27 | [Pressed For Duration](https://evert-arias.github.io/easybtn-docs/docs/on-pressed-for-duration-example) 28 | 29 | [Detecting Sequence](https://evert-arias.github.io/easybtn-docs/docs/on-sequence-example) 30 | 31 | ## Copyright 32 | 33 | [MIT](../LICENSE.md) © [Evert Arias](https://me.treve.dev/) 34 | -------------------------------------------------------------------------------- /src/EasyButton.h: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButton.h 3 | * @author Evert Arias 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #ifndef _EasyButton_h 9 | #define _EasyButton_h 10 | 11 | #include 12 | #include "EasyButtonBase.h" 13 | 14 | #define EASYBUTTON_READ_TYPE_INTERRUPT 0 15 | #define EASYBUTTON_READ_TYPE_POLL 1 16 | 17 | class EasyButton : public EasyButtonBase 18 | { 19 | friend class EasyButtonTouch; 20 | 21 | public: 22 | EasyButton(uint8_t pin, uint32_t debounce_time = 35, bool pullup_enable = true, bool active_low = true) : EasyButtonBase(active_low), _pin(pin), _db_time(debounce_time), _pu_enabled(pullup_enable), _read_type(EASYBUTTON_READ_TYPE_POLL) 23 | { 24 | } 25 | ~EasyButton() {} 26 | 27 | // PUBLIC FUNCTIONS 28 | virtual void begin(); // Initialize a button object and the pin it's connected to. 29 | bool read(); // Returns the current debounced button state, true for pressed, false for released. 30 | void update(); // Update button pressed time, only needed when using interrupts. 31 | void enableInterrupt(callback_t callback); // Call a callback function when the button is pressed or released. 32 | void disableInterrupt(); 33 | bool supportsInterrupt(); // Returns true if the button pin is an external interrupt pin. 34 | 35 | private: 36 | // PRIVATE VARIABLES 37 | uint8_t _pin; // Arduino pin number where the Button is connected to. 38 | uint32_t _db_time; // Debounce time (ms). 39 | bool _pu_enabled; // Internal pullup resistor enabled. 40 | uint8_t _read_type; // Read type. Poll or Interrupt. 41 | 42 | virtual bool _readPin(); // Abstracts the pin value reading. 43 | }; 44 | 45 | #endif -------------------------------------------------------------------------------- /examples/InterruptsOnPressedFor/InterruptsOnPressedFor.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: InterruptsOnPressedFor.ino 3 | Created: 8/17/2019 10:16:52 AM 4 | Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa) 5 | Description: Example to demostrate how to use onPressedFor functionality when using interrupts 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | Arduino pin where the buttons are connected to. 13 | Should be a pin that supports external interrupts. 14 | */ 15 | #define BUTTON_PIN 2 16 | 17 | #define BAUDRATE 115200 18 | 19 | // Instance of the button. 20 | EasyButton button(BUTTON_PIN); 21 | 22 | void buttonPressedTwoSeconds() 23 | { 24 | Serial.println("Button pressed for two seconds"); 25 | } 26 | 27 | void buttonISR() 28 | { 29 | // When button is being used through external interrupts, parameter INTERRUPT must be passed to read() function. 30 | button.read(); 31 | } 32 | 33 | void setup() 34 | { 35 | // Initialize Serial for debuging purposes. 36 | Serial.begin(BAUDRATE); 37 | 38 | Serial.println(); 39 | Serial.println(">>> EasyButton onPressedFor interrupt example <<<"); 40 | 41 | // Initialize the button. 42 | button.begin(); 43 | 44 | button.onPressedFor(2000, buttonPressedTwoSeconds); 45 | 46 | if (button.supportsInterrupt()) 47 | { 48 | button.enableInterrupt(buttonISR); 49 | Serial.println("Button will be used through interrupts"); 50 | } 51 | } 52 | 53 | void loop() 54 | { 55 | /* 56 | update() function must be called repeatedly only if onPressedFor 57 | functionality is being used and interrupt is enabled. 58 | */ 59 | button.update(); 60 | } 61 | -------------------------------------------------------------------------------- /src/EasyButtonVirtual.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonVirtual.h 3 | * @author Evert Arias, Jose Gabriel Companioni Benitez 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #include "EasyButtonVirtual.h" 9 | 10 | void EasyButtonVirtual::begin() 11 | { 12 | _current_state = _button_abstraction; 13 | if (_active_low) 14 | { 15 | _current_state = !_current_state; 16 | } 17 | _time = millis(); 18 | _last_state = _current_state; 19 | _changed = false; 20 | _last_change = _time; 21 | } 22 | 23 | bool EasyButtonVirtual::read() 24 | { 25 | uint32_t read_started_ms = millis(); 26 | 27 | // Save last state. 28 | _last_state = _current_state; 29 | _current_state = _button_abstraction; 30 | 31 | if (_active_low) 32 | { 33 | _current_state = !_current_state; 34 | } 35 | 36 | // Report state change if current state vary from last state. 37 | _changed = (_current_state != _last_state); 38 | 39 | // If state has changed since last read. 40 | if (_changed) 41 | { 42 | // State change. 43 | // Save current millis as last change time. 44 | _last_change = read_started_ms; 45 | } 46 | 47 | if (wasReleased()) 48 | { 49 | if (!_was_btn_held) 50 | { 51 | if (_pressed_callback) 52 | { 53 | _pressed_callback(); 54 | } 55 | 56 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 57 | for (size_t i = 0; i < MAX_SEQUENCES; i++) 58 | { 59 | if (_sequences[i].newPress(read_started_ms)) 60 | { 61 | callback_t function = _pressed_sequence_callbacks[i]; 62 | function(); 63 | } 64 | } 65 | #endif 66 | } 67 | // Button was not held. 68 | else 69 | { 70 | _was_btn_held = false; 71 | } 72 | // Since button released, reset _pressed_for_callbackCalled value. 73 | _held_callback_called = false; 74 | } 75 | else if (isPressed()) 76 | { 77 | _checkPressedTime(); 78 | } 79 | 80 | _time = read_started_ms; 81 | 82 | return _current_state; 83 | } -------------------------------------------------------------------------------- /examples/VirtualButton/VirtualButton.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Name: EasyButtonVirtual.ino 3 | Created: 4/11/2020 1:22:52 AM 4 | Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa) 5 | Description: Example to demostrate how to use the virtual button feature. This allows the user to use a variable as if it were a button. Really useful when 6 | the buttons are connected through port expanders like PCF8574. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* 13 | The following is just to simulate changes in the button state, 14 | it is not useful when using the library in a real case. 15 | */ 16 | unsigned long previous_millis = 0; 17 | unsigned int interval = 1000; 18 | 19 | #define BAUDRATE 115200 20 | 21 | // Global variable that simulates the button's value. 22 | bool button = true; 23 | 24 | // Instance of the button. 25 | EasyButtonVirtual vButton(button); 26 | 27 | // Callback function to be called when the button is pressed. 28 | void buttonPressed() 29 | { 30 | Serial.println("Button pressed"); 31 | interval = 2500; 32 | } 33 | 34 | // Callback function to be called when the button is pressed. 35 | void buttonPressedForTwoSeconds() 36 | { 37 | Serial.println("Button pressed for two seconds"); 38 | } 39 | 40 | void setup() 41 | { 42 | // Initialize Serial for debuging purposes. 43 | Serial.begin(BAUDRATE); 44 | 45 | Serial.println(); 46 | Serial.println(">>> EasyButton virtual button example <<<"); 47 | 48 | // Initialize the button. 49 | vButton.begin(); 50 | 51 | // Callback function to be called when the button is pressed. 52 | vButton.onPressed(buttonPressed); 53 | 54 | // Add the callback function to be called when the button is pressed for at least the given time. 55 | vButton.onPressedFor(2000, buttonPressedForTwoSeconds); 56 | } 57 | 58 | void loop() 59 | { 60 | // Continuously read the status of the button. 61 | vButton.read(); 62 | 63 | /* 64 | The following is just to simulate changes in the button state, 65 | it is not useful when using the library in a real case. 66 | */ 67 | unsigned long current_millis = millis(); 68 | if (current_millis - previous_millis >= interval) 69 | { 70 | previous_millis = current_millis; 71 | button = !button; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/EasyButtonBase.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonBase.h 3 | * @author Evert Arias 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #include "EasyButtonBase.h" 9 | 10 | void EasyButtonBase::onPressed(EasyButtonBase::callback_t callback) 11 | { 12 | _pressed_callback = callback; 13 | } 14 | 15 | void EasyButtonBase::onPressedFor(uint32_t duration, EasyButtonBase::callback_t callback) 16 | { 17 | _held_threshold = duration; 18 | _pressed_for_callback = callback; 19 | } 20 | 21 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 22 | void EasyButtonBase::onSequence(uint8_t sequences, uint32_t duration, EasyButtonBase::callback_t callback) 23 | { 24 | if (_sequences_count < 5) 25 | { 26 | Sequence sequence(sequences, duration); 27 | sequence.enable(); 28 | _sequences[_sequences_count] = sequence; 29 | _pressed_sequence_callbacks[_sequences_count++] = callback; 30 | } 31 | } 32 | #endif 33 | 34 | bool EasyButtonBase::isPressed() 35 | { 36 | return _current_state; 37 | } 38 | 39 | bool EasyButtonBase::isReleased() 40 | { 41 | return !_current_state; 42 | } 43 | 44 | bool EasyButtonBase::wasPressed() 45 | { 46 | return _current_state && _changed; 47 | } 48 | 49 | bool EasyButtonBase::wasReleased() 50 | { 51 | return !_current_state && _changed; 52 | } 53 | 54 | bool EasyButtonBase::pressedFor(uint32_t duration) 55 | { 56 | return _current_state && _time - _last_change >= duration; 57 | } 58 | 59 | bool EasyButtonBase::releasedFor(uint32_t duration) 60 | { 61 | return !_current_state && _time - _last_change >= duration; 62 | } 63 | 64 | void EasyButtonBase::_checkPressedTime() 65 | { 66 | uint32_t read_started_ms = millis(); 67 | if (_current_state && read_started_ms - _last_change >= _held_threshold && _pressed_for_callback) 68 | { 69 | // Button has been pressed for at least the given time. 70 | _was_btn_held = true; 71 | 72 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 73 | // Reset short presses counters. 74 | for (Sequence seq : _sequences) 75 | { 76 | seq.reset(); 77 | } 78 | #endif 79 | 80 | // Call the callback function for a long press event if it exist and if it has not been called yet. 81 | if (_pressed_for_callback && !_held_callback_called) 82 | { 83 | // Set as called. 84 | _held_callback_called = true; 85 | _pressed_for_callback(); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/EasyButton.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButton.cpp 3 | * @author Evert Arias 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #include "EasyButton.h" 9 | 10 | void EasyButton::begin() 11 | { 12 | pinMode(_pin, _pu_enabled ? INPUT_PULLUP : INPUT); 13 | _current_state = _readPin(); 14 | if (_active_low) 15 | { 16 | _current_state = !_current_state; 17 | } 18 | _time = millis(); 19 | _last_state = _current_state; 20 | _changed = false; 21 | _last_change = _time; 22 | } 23 | 24 | bool EasyButton::read() 25 | { 26 | uint32_t read_started_ms = millis(); 27 | 28 | bool pinVal = _readPin(); 29 | 30 | if (_active_low) 31 | { 32 | pinVal = !pinVal; 33 | } 34 | 35 | if (read_started_ms - _last_change < _db_time) 36 | { 37 | // Debounce time has not ellapsed. 38 | _changed = false; 39 | } 40 | else 41 | { 42 | // Debounce time ellapsed. 43 | _last_state = _current_state; // Save last state. 44 | _current_state = pinVal; // Assign new state as current state from pin's value. 45 | _changed = (_current_state != _last_state); // Report state change if current state vary from last state. 46 | // If state has changed since last read. 47 | if (_changed) 48 | { 49 | // State changed. 50 | // Save current millis as last change time. 51 | _last_change = read_started_ms; 52 | } 53 | } 54 | 55 | if (wasReleased()) 56 | { 57 | if (!_was_btn_held) 58 | { 59 | if (_pressed_callback) 60 | { 61 | _pressed_callback(); 62 | } 63 | 64 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 65 | for (size_t i = 0; i < MAX_SEQUENCES; i++) 66 | { 67 | if (_sequences[i].newPress(read_started_ms)) 68 | { 69 | callback_t function = _pressed_sequence_callbacks[i]; 70 | function(); 71 | } 72 | } 73 | #endif 74 | } 75 | // Button was not held. 76 | else 77 | { 78 | _was_btn_held = false; 79 | } 80 | 81 | // Since button released, reset _pressed_for_callbackCalled value. 82 | _held_callback_called = false; 83 | } 84 | else if (isPressed() && _read_type == EASYBUTTON_READ_TYPE_POLL) 85 | { 86 | _checkPressedTime(); 87 | } 88 | 89 | _time = read_started_ms; 90 | 91 | return _current_state; 92 | } 93 | 94 | bool EasyButton::_readPin() 95 | { 96 | return digitalRead(_pin); 97 | } 98 | 99 | bool EasyButton::supportsInterrupt() 100 | { 101 | return (digitalPinToInterrupt(_pin) != NOT_AN_INTERRUPT); 102 | } 103 | 104 | void EasyButton::enableInterrupt(EasyButton::callback_t callback) 105 | { 106 | attachInterrupt(digitalPinToInterrupt(_pin), callback, CHANGE); 107 | _read_type = EASYBUTTON_READ_TYPE_INTERRUPT; 108 | } 109 | 110 | void EasyButton::disableInterrupt() 111 | { 112 | detachInterrupt(digitalPinToInterrupt(_pin)); 113 | _read_type = EASYBUTTON_READ_TYPE_POLL; 114 | } 115 | 116 | void EasyButton::update() 117 | { 118 | if (!_was_btn_held) 119 | { 120 | _checkPressedTime(); 121 | } 122 | } -------------------------------------------------------------------------------- /src/EasyButtonBase.h: -------------------------------------------------------------------------------- 1 | /** 2 | * EasyButtonBase.h 3 | * @author Evert Arias 4 | * @version 2.0.3 5 | * @license MIT 6 | */ 7 | 8 | #ifndef _EasyButtonBase_h 9 | #define _EasyButtonBase_h 10 | 11 | #include 12 | #include "Sequence.h" 13 | 14 | #if defined(ESP8266) || defined(ESP32) 15 | #define EASYBUTTON_FUNCTIONAL_SUPPORT 1 16 | #endif 17 | 18 | #ifdef EASYBUTTON_FUNCTIONAL_SUPPORT 19 | #include 20 | #include "FunctionalInterrupt.h" 21 | #endif 22 | 23 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 24 | #define MAX_SEQUENCES 5 25 | #endif 26 | 27 | class EasyButtonBase 28 | { 29 | public: 30 | // Common functions. 31 | #ifdef EASYBUTTON_FUNCTIONAL_SUPPORT 32 | typedef std::function callback_t; 33 | #else 34 | typedef void (*callback_t)(); 35 | #endif 36 | EasyButtonBase(bool active_low) : _active_low(active_low) 37 | { 38 | } 39 | virtual void begin() = 0; // Initialize a button object and the pin it's connected to. 40 | virtual bool read() = 0; // Returns the current debounced button state, true for pressed, false for released. 41 | void onPressed(callback_t callback); // Call a callback function when the button has been pressed and released. 42 | void onPressedFor(uint32_t duration, callback_t callback); // Call a callback function when the button has been held for at least the given number of milliseconds. 43 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 44 | void onSequence(uint8_t sequences, uint32_t duration, callback_t callback); // Call a callback function when the given sequence has matched. 45 | #endif 46 | 47 | bool isPressed(); // Returns true if the button state was pressed at the last read. 48 | bool isReleased(); // Returns true if the button state was released at the last read. 49 | bool wasPressed(); // Returns true if the button state at the last read was pressed. 50 | bool wasReleased(); // Returns true if the button state at the last read was released. 51 | bool pressedFor(uint32_t duration); // Returns true if the button state at the last read was pressed, and has been in that state for at least the given number of milliseconds. 52 | bool releasedFor(uint32_t duration); // Returns true if the button state at the last read was released, and has been in that state for at least the given number of milliseconds. 53 | 54 | protected: 55 | // Common variables. 56 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 57 | Sequence _sequences[MAX_SEQUENCES]; 58 | uint16_t _sequences_count; 59 | #endif 60 | uint32_t _held_threshold; // Held threshold. 61 | 62 | #ifndef EASYBUTTON_DO_NOT_USE_SEQUENCES 63 | callback_t _pressed_sequence_callbacks[MAX_SEQUENCES]; 64 | #endif 65 | callback_t _pressed_callback; // Callback function for pressed events. 66 | callback_t _pressed_for_callback; // Callback function for pressedFor events. 67 | bool _held_callback_called; // Indicate if button long press has been notified. 68 | bool _active_low; // Inverts button logic. If true, low = pressed else high = pressed. 69 | bool _current_state; // Current button state, true = pressed. 70 | bool _last_state; // Previous button state, true = pressed. 71 | bool _changed; // Has the state change since last read. 72 | uint32_t _time; // Time of current state. 73 | uint32_t _last_change; // Time of last state change. 74 | bool _was_btn_held; // Indicate if button was held. 75 | 76 | // Common functions 77 | void _checkPressedTime(); // Verify if pressed_for_callback should be called. 78 | }; 79 | 80 | #endif 81 | --------------------------------------------------------------------------------