Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved onPressedFor functionality when using interrupts #20

Merged
merged 9 commits into from
Aug 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions examples/Interrupts/Interrupts.ino
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
Name: MultipleButtons.ino
Name: Interrupts.ino
Created: 8/11/2019 11:45:52 AM
Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa)
Description: Example to demostrate how to use the library with more than one button
Description: Example to demostrate how to use interrupts in order to improve performance
*/

#include <Arduino.h>
Expand All @@ -13,42 +13,37 @@

EasyButton button(BUTTON_PIN);


void buttonPressed()
{
Serial.println("Button is pressed");
Serial.println("Button Pressed");
}

void buttonPressedTwoSeconds()
void sequenceEllapsed()
{
Serial.println("Button pressed for two seconds");
Serial.println("Double click");
}

void buttonSequence()
void buttonISR()
{
Serial.println("Sequence");
//When button is being used through external interrupts, parameter INTERRUPT must be passed to read() function
button.read(INTERRUPT);
}

void buttonPressedReleased()
void setup()
{
button.read();
}

void setup() {
// put your setup code here, to run once:
Serial.begin(BAUDRATE);
button.begin();
button.onPressed(buttonPressed);
button.onSequence(2, 1500, sequenceEllapsed);
if (button.supportsInterrupt())
{
Serial.println("Button will be used through external interrupts");
button.enableInterrupt(buttonPressedReleased);
button.enableInterrupt(buttonISR);
Serial.println("Button will be used through interrupts");
}

button.onPressed(buttonPressed);
button.onPressedFor(2000, buttonPressedTwoSeconds);
button.onSequence(3, 5000, buttonSequence);
}

void loop() {
void loop()
{
// put your main code here, to run repeatedly:
}
43 changes: 43 additions & 0 deletions examples/InterruptsOnPressedFor/InterruptsOnPressedFor.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Name: InterruptsOnPressedFor.ino
Created: 8/17/2019 10:16:52 AM
Author: José Gabriel Companioni Benítez (https://github.com/elC0mpa)
Description: Example to demostrate how to use onPressedFor functionality when using interrupts
*/

#include <Arduino.h>
#include <EasyButton.h>

#define BUTTON_PIN 2 //Should be a pin that supports external interrupts
#define BAUDRATE 9600

EasyButton button(BUTTON_PIN);

void buttonPressedTwoSeconds()
{
Serial.println("Button Pressed for two seconds");
}

void buttonISR()
{
//When button is being used through external interrupts, parameter INTERRUPT must be passed to read() function
button.read(INTERRUPT);
}

void setup() {
// put your setup code here, to run once:
Serial.begin(BAUDRATE);
button.begin();
button.onPressedFor(2000, buttonPressedTwoSeconds);
if (button.supportsInterrupt())
{
button.enableInterrupt(buttonISR);
Serial.println("EasyButton onPressedFor Interrupt example");
}
}

void loop() {
// put your main code here, to run repeatedly:
// update() function must be called repeatedly only if onPressedFor functionality is being used and interrupt is enabled
button.update();
}
93 changes: 48 additions & 45 deletions src/EasyButton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,93 +66,71 @@ bool EasyButton::releasedFor(uint32_t duration)
return !_current_state && _time - _last_change >= duration;
}

bool EasyButton::read()
bool EasyButton::read(int read_type = POLL)
{

// get current millis.
uint32_t read_started_ms = millis();

// read pin value.
bool pinVal = _readPin();

// if invert = true, invert Button's pin value.
if (_invert) {
if (_invert)
pinVal = !pinVal;
}

// detect change on button's state.
if (read_started_ms - _last_change < _db_time)
{//true -> debounce time has not ellapsed
if (read_started_ms - _last_change < _db_time)
{ //true -> debounce time has not ellapsed
_changed = false;
}
else
{// debounce time ellapsed
else
{ //true -> debounce time ellapsed
_last_state = _current_state; // save last state.
_current_state = pinVal; // assign new state as current state from pin's value.
_changed = (_current_state != _last_state); // report state change if current state vary from last state.
// if state has changed since last read.
if (_changed)
{// state change
if (_changed)
{ // state change
// save current millis as last change time.
_last_change = read_started_ms;
}
}

// call the callback functions when conditions met.
// if (!_current_state && _changed) {
if (wasReleased()) {
// button was released.
if (!_was_btn_held)
if (wasReleased())
{
if (!_was_btn_held)
{
if (_short_press_count == 0)
{
_first_press_time = read_started_ms;
}
// increment presses counter.

_short_press_count++;
// button is not being held.
// call the callback function for a short press event if it exist.
if (_pressed_callback) {

if (_pressed_callback)
_pressed_callback();
}

if (_short_press_count == _press_sequences && _press_sequence_duration >= (read_started_ms - _first_press_time))
{//true-> pressed_sequence
if (_short_press_count == _press_sequences && _press_sequence_duration >= (read_started_ms - _first_press_time))
{ //true-> pressed_sequence
if (_pressed_sequence_callback)
{
_pressed_sequence_callback();
}
_short_press_count = 0;
_first_press_time = 0;//MOdificar
_first_press_time = 0; //MOdificar
}
// if sequence timeout, reset short presses counters.

else if (_press_sequence_duration <= (read_started_ms - _first_press_time))
{
{ // true-> sequence timeout
_short_press_count = 0;
_first_press_time = 0;
}
}
// button was not held.
else
else
{
_was_btn_held = false;
}
// since button released, reset _pressed_for_callbackCalled value.
_held_callback_called = false;
}
// button is not released.
else if (_current_state && read_started_ms - _last_change >= _held_threshold && _pressed_for_callback) {
// button has been pressed for at least the given time
_was_btn_held = true;
// reset short presses counters.
_short_press_count = 0;
_first_press_time = 0;
// call the callback function for a long press event if it exist and if it has not been called yet.
if (_pressed_for_callback && !_held_callback_called) {
_held_callback_called = true; // set as called.
_pressed_for_callback();
}
}
else if(isPressed() && read_type == POLL)
_checkPressedTime();


_time = read_started_ms;

Expand All @@ -177,4 +155,29 @@ void EasyButton::enableInterrupt(EasyButton::callback_t callback)
void EasyButton::disableInterrupt()
{
detachInterrupt(digitalPinToInterrupt(_pin));
}

void EasyButton::update()
{
if (!_was_btn_held)
_checkPressedTime();
}

void EasyButton::_checkPressedTime()
{
uint32_t read_started_ms = millis();
if (_current_state && read_started_ms - _last_change >= _held_threshold && _pressed_for_callback)
{
// button has been pressed for at least the given time
_was_btn_held = true;
// reset short presses counters.
_short_press_count = 0;
_first_press_time = 0;
// call the callback function for a long press event if it exist and if it has not been called yet.
if (_pressed_for_callback && !_held_callback_called)
{
_held_callback_called = true; // set as called.
_pressed_for_callback();
}
}
}
8 changes: 6 additions & 2 deletions src/EasyButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#include <functional>
#endif

#define INTERRUPT 0
#define POLL 1

class EasyButton
{
friend class EasyButtonTouch;
Expand All @@ -31,8 +34,8 @@ class EasyButton
~EasyButton() {}
// PUBLIC FUNCTIONS
virtual void begin(); // Initialize a button object and the pin it's connected to.
bool read(); // Returns the current debounced button state, true for pressed, false for released.

bool read(int read_type = POLL); // Returns the current debounced button state, true for pressed, false for released.
void update(); // Update button pressed time, only needed when using interrupts
void onPressed(callback_t callback); // Call a callback function when the button has been pressed and released.
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.
void onSequence(uint8_t sequences, uint32_t duration, callback_t callback); // Call a callback function when the given sequence has matched.
Expand Down Expand Up @@ -69,6 +72,7 @@ class EasyButton
callback_t _pressed_sequence_callback; // Callback function for pressedSequence events.

virtual bool _readPin(); // Abstracts the pin value reading.
void _checkPressedTime(); // Verify if pressed_for_callback should be called
};

#endif