Skip to content
Open
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
69 changes: 60 additions & 9 deletions Button.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Button - a small library for Arduino to handle button debouncing

MIT licensed.
*/

Expand All @@ -13,6 +13,9 @@ Button::Button(uint8_t pin, uint16_t debounce_ms)
, _state(HIGH)
, _ignore_until(0)
, _has_changed(false)
, _reported_repeats(0)
, _repeat_delay_ms(-1)
, _repeat_ms(-1)
{
}

Expand All @@ -21,9 +24,9 @@ void Button::begin()
pinMode(_pin, INPUT_PULLUP);
}

//
//
// public methods
//
//

bool Button::read()
{
Expand All @@ -32,15 +35,26 @@ bool Button::read()
{
// ignore any changes during this period
}
// pin has changed

// pin has changed
else if (digitalRead(_pin) != _state)
{
_ignore_until = millis() + _delay;
_state = !_state;

if (_state == RELEASED)
{
_reported_repeats = repeats_since_press();
}

else
{
_reported_repeats = 0;
}

_ignore_until = millis() + _delay;
_has_changed = true;
}

return _state;
}

Expand All @@ -62,14 +76,51 @@ bool Button::has_changed()
return false;
}

// has the button gone from off -> on
// how many repeated press events occured since the button was pressed
uint16_t Button::repeat_count()
{
return _state == PRESSED ? repeats_since_press() : _reported_repeats;
}

// has the button gone from off -> on or pressed repeatedly
bool Button::pressed()
{
return (read() == PRESSED && has_changed());
if (read() == PRESSED)
{
uint16_t old_repeats = _reported_repeats;
_reported_repeats = repeats_since_press();
return (has_changed() || old_repeats != _reported_repeats);
}
else
{
return false;
}
}

// has the button gone from on -> off
bool Button::released()
{
return (read() == RELEASED && has_changed());
}

void Button::set_repeat(int16_t delay_ms, int16_t repeat_ms)
{
_repeat_delay_ms = delay_ms > _delay ? delay_ms - _delay : 0;
_repeat_ms = repeat_ms;
}

uint16_t Button::repeats_since_press()
{
if (_repeat_delay_ms == -1 || millis() < _ignore_until + _repeat_delay_ms)
{
return 0;
}

if (_repeat_ms <= 0)
{
return 1;
}

uint32_t press_time = millis() - _ignore_until;
return 1 + (press_time - _repeat_delay_ms) / _repeat_ms;
}
13 changes: 10 additions & 3 deletions Button.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Button - a small library for Arduino to handle button debouncing

MIT licensed.
*/

Expand All @@ -18,16 +18,23 @@ class Button
bool pressed();
bool released();
bool has_changed();

uint16_t repeat_count();
void set_repeat(int16_t delay_ms, int16_t repeat_ms);

const static bool PRESSED = LOW;
const static bool RELEASED = HIGH;

private:
uint16_t repeats_since_press();

uint8_t _pin;
uint16_t _delay;
bool _state;
uint32_t _ignore_until;
bool _has_changed;
uint16_t _reported_repeats;
int16_t _repeat_delay_ms;
int16_t _repeat_ms;
};

#endif
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Features
** when a button is pressed
** when a button is released
** or when a button changes (i.e. pressing or releasing)
** repeated press (i.e. when the button is kept pressed for a long time, like on a computer keyboard)
** long press

Requirements
------------
Expand Down Expand Up @@ -93,6 +95,16 @@ Returns true whenever the button is pressed or released, i.e., its position is t
**bool read()**
Returns the current debounced state of the button, i.e. Button::PRESSED or Button::RELEASED.

**void set_repeat(int16_t delay_ms, int16_t repeat_ms)**
Set the repeated press timer: `delay_ms` specifies the time in milliseconds after before the first repeated press event, and `repeat_ms` specifies the time in milliseconds between subsequent events. You can set `delay_ms` to -1 to disable repeated press event (that's also the default), and similarly, set `repeat_ms`
to -1 to disable subsequent press event. This way you can detect a long press, but not repeated press events.

**uint16_t repeat_count()**
Returns the number of repeated press event since the button was last `pressed()`. When the button is first pressed, this method will return 0, and then the
number will increment by 1 for any repeated press event. You can also read the `repeat_count()` value after the button is `released()`, and then react
differently in case of a short press vs a long press. Note that you need to call `set_repeat()` first, otherwise repeated pressed will not be detected and
`repeat_count()` will always return `0`.

**bool has_changed()**
Returns whether the position/state of the button has changed after calling the previous read() function. Unlikely to be used except by Super Gurus.

Expand Down
2 changes: 2 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ toggled KEYWORD2
pressed KEYWORD2
released KEYWORD2
has_changed KEYWORD2
repeat_count KEYWORD2
set_repeat KEYWORD2

#######################################
# Constants (LITERAL1)
Expand Down