Giter Site home page Giter Site logo

jchristensen / jc_button Goto Github PK

View Code? Open in Web Editor NEW
423.0 36.0 101.0 50 KB

Arduino library to debounce button switches, detect presses, releases, and long presses

License: GNU General Public License v3.0

C++ 100.00%
arduino-library button debounce switch debounce-button arduino debounce-switch

jc_button's Introduction

Arduino Button Library

https://github.com/JChristensen/JC_Button
README file

License

Arduino Button Library Copyright (C) 2018-2019 Jack Christensen GNU GPL v3.0

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/gpl.html

Introduction

The Button library is for debouncing and reading momentary contact switches like tactile button switches. "Long presses" of arbitrary length can be detected. Works well in state machine constructs. Use the read() function to read each button in the main loop, which should execute as fast as possible.

The simplest way to use a button with an AVR microcontroller is to wire the button between a GPIO pin and ground, and turn on the AVR internal pullup resistor. The Button class constructor takes four arguments, but three have default values that work for a button wired in this manner.

A derived class, ToggleButton, implements button objects that need only "push-on, push-off" functionality.

Examples

The following example sketches are included with the Button library:

  • SimpleOnOff: Just turns the Arduino's pin 13 LED on and off.
  • LongPress: Demonstrates detecting long and short button presses.
  • UpDown: Counts up or down, one number at a time or rapidly by holding the button down.
  • Toggle: Demonstrates ToggleButton functionality.

Constructors

Button(pin, dbTime, puEnable, invert)

Description

The constructor defines a button object.

Syntax

Button(pin, dbTime, puEnable, invert);

Required parameter

pin: Arduino pin number that the button is connected to (byte)

Optional parameters

dbTime: Debounce time in milliseconds. Defaults to 25ms if not given. (unsigned long)
puEnable: true to enable the microcontroller's internal pull-up resistor, else false. Defaults to true if not given. (bool)
invert: false interprets a high logic level to mean the button is pressed, true interprets a low level as pressed. true should be used when a pull-up resistor is employed, false for a pull-down resistor. Defaults to true if not given. (bool)

Returns

None.

Example
// button connected from pin 2 to ground, 25ms debounce, pullup enabled, logic inverted
Button myButton(2);

// same as above but this button needs a longer debounce time (50ms)
Button myButton(3, 50);

// a button wired from the MCU pin to Vcc with an external pull-down resistor
Button myButton(4, 25, false, false);

ToggleButton(pin, initialState, dbTime, puEnable, invert)

Description

The constructor defines a toggle button object, which has "push-on, push-off" functionality. The initial state can be on or off. See the section, ToggleButton Library Functions for functions that apply specifically to the ToggleButton object. The ToggleButton class is derived from the Button class, so all Button functions are available, but because it is inherently a more limited concept, the special ToggleButton functions will be most useful, along with begin() and read().

Syntax

ToggleButton(pin, initialState, dbTime, puEnable, invert);

Required parameter

pin: Arduino pin number that the button is connected to (byte)

Optional parameters

initialState: Initial state for the button. Defaults to off (false) if not given. (bool)
dbTime: Debounce time in milliseconds. Defaults to 25ms if not given. (unsigned long)
puEnable: true to enable the microcontroller's internal pull-up resistor, else false. Defaults to true if not given. (bool)
invert: false interprets a high logic level to mean the button is pressed, true interprets a low level as pressed. true should be used when a pull-up resistor is employed, false for a pull-down resistor. Defaults to true if not given. (bool)

Returns

None.

Example
// button connected from pin 2 to ground, initial state off,
// 25ms debounce, pullup enabled, logic inverted
ToggleButton myToggle(2);

// same as above but this button is initially "on" and also
// needs a longer debounce time (50ms).
ToggleButton myToggle(3, true, 50);

// a button wired from the MCU pin to Vcc with an external pull-down resistor,
// initial state is off.
Button myButton(4, false, 25, false, false);

Button Library Functions

begin()

Description

Initializes the Button object and the pin it is connected to.

Syntax

myButton.begin();

Parameters

None.

Returns

None.

Example
myButton.begin();

read()

Description

Reads the button and returns a boolean value (true or false) to indicate whether the button is pressed. The read() function needs to execute very frequently in order for the sketch to be responsive. A good place for read() is at the top of loop(). Often, the return value from read() will not be needed if the other functions below are used.

Syntax

myButton.read();

Parameters

None.

Returns

true if the button is pressed, else false (bool)

Example
myButton.read();

isPressed()

isReleased()

Description

These functions check the button state from the last call to read() and return false or true accordingly. These functions do not cause the button to be read.

Syntax

myButton.isPressed();
myButton.isReleased();

Parameters

None.

Returns

true or false, depending on whether the button has been pressed (released) or not (bool)

Example
if ( myButton.isPressed() )
{
	//do something
}
else
{
	//do something else
}

wasPressed()

wasReleased()

Description

These functions check the button state to see if it changed between the last two calls to read() and return false or true accordingly. These functions do not cause the button to be read. Note that these functions may be more useful than isPressed() and isReleased() since they actually detect a change in the state of the button, which is usually what we want in order to cause some action.

Syntax

myButton.wasPressed();
myButton.wasReleased();

Parameters

None.

Returns

true or false, depending on whether the button was pressed (released) or not (boolean)

Example
if ( myButton.wasPressed() )
{
	//do something
}

pressedFor(ms)

releasedFor(ms)

Description

These functions check to see if the button is pressed (or released), and has been in that state for the specified time in milliseconds. Returns false or true accordingly. These functions are useful to detect "long presses". Note that these functions do not cause the button to be read.

Syntax

myButton.pressedFor(ms);
myButton.releasedFor(ms);

Parameters

ms: The number of milliseconds (unsigned long)

Returns

true or false, depending on whether the button was pressed (released) for the specified time (bool)

Example
if ( myButton.pressedFor(1000) )
{
    // button has been pressed for one second
}

lastChange()

Description

Under certain circumstances, it may be useful to know when a button last changed state. lastChange() returns the time the button last changed state, in milliseconds (the value is derived from the Arduino millis() function).

Syntax

myButton.lastChange();

Parameters

None.

Returns

The time in milliseconds when the button last changed state (unsigned long)

Example
unsigned long msLastChange = myButton.lastChange();

ToggleButton Library Functions

changed()

Description

Returns a boolean value (true or false) to indicate whether the toggle button changed state the last time read() was called.

Syntax

myToggle.changed();

Parameters

None.

Returns

true if the toggle state changed, else false (bool)

Example
if (myToggle.changed())
{
    // do something
}
else
{
    // do something different
}

toggleState()

Description

Returns a boolean value (true or false) to indicate the toggle button state as of the last time read() was called.

Syntax

myToggle.toggleState();

Parameters

None.

Returns

true if the toggle is "on", else false (bool)

Example
if (myToggle.toggleState())
{
    // do something
}
else
{
    // do something different
}

jc_button's People

Contributors

bitflippersanonymous avatar jchristensen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jc_button's Issues

Double-click

I've used this library for a few of my FastLED routines over the past couple of years and would love to see a double-click feature added, so that it would support:

  • click
  • double-click
  • long click

Anyways, thanks for the library.

Simulate physical button press?

Hello Mr. Christensen,
I have three physical buttons, but have a need to simulate a button press in my sketch. I guess I'm looking for something like myBtn.press();. Other than getting out a soldering iron and attaching a wire from an available GPIO to the switch itself to pull it low, not sure what else to do, how to get past this. Any ideas? Thanks in advance!

Compilation warning when working with Arduino Rev4

The specific warning is this one:
WARNING: library JC_Button claims to run on avr architecture(s) and may be incompatible with your current board which runs on renesas_uno architecture(s).

Are there any known problems? Can the warning be safely ignored?

If there are concerns, I would be happy to help out, if I can.

Thanks for any reply and your work so far with the library!

Feature request: Compatibility for Arduino Every

When compiling for arduino every --fbqn arduino:megaavr:nona4809 following warning is issued:

WARNING: library JC_Button claims to run on avr architecture(s) and may be incompatible with your current board which runs on megaavr architecture(s).

SDK update issue

after cloning to Arduino/libraries i've had to rename to Button-git as if left it get over written next time there is a libraries update - either a different lib call Button or a very early version of Button?

either way it breaks my code!

btn.pressedFor(ms) makes the code run repeatedly

I have something similar to this:

void loop() {
  if (btn.pressedFor(500)) {
    // Do stuff
    Serial.println("btn pressed for 500 ms");
  }
}

When I hold down the button for 500 ms, the serial monitor shows that it runs multiple times, and I see why in the library code. However, what I'm looking for is one of the following:

  1. When I hold it down, it should run once and do not run again until I release it and hold it down again.
  2. When I hold it down, it should run periodically with the 500 ms intervals until I release it. (Prefered)

Is there an easy way to implement one of these in my code without messing with the library itself?

Not working with Nano Every

I get this error while uploading on a brandnew Nano Every, and the Buttons are not working.
Maybe you can have look into this?
WARNUNG: Bibliothek JC_Button behauptet auf (avr) Architektur(en) ausgeführt werden zu können und ist möglicherweise inkompatibel mit Ihrem derzeitigen Board, welches auf (megaavr) Architektur(en) ausgeführt wird.

library.properties says architecture is AVR only

This is related to issues #4 and #17 in that the library properties says the library architecture is AVR only when it runs on other processors.
The reason I bring this up is that the IDE no longer shows examples for architectures/processors that are not in the library.properties architectures list.

The button code doesn't use anything outside of the standard Arduino core functions so it should work on any Arduino core.
Using a star "*" rather than "avr" would allow the examples to show up on all the cores and remove a warning that the IDE will issue when using a library on an architecture not specified in the library.properties
i.e. in the case of using it on a ESP8266 processor you will not see or be able to access any of the examples and you will get this warning when using it your sketches:

WARNING: library JC_Button claims to run on (avr) architecture(s) and may be incompatible with your current board which runs on (esp8266) architecture(s).

Can a button be toggle and long press at the same time?

For a midi controller I need this behaviour:

toggle press btn1: REC (command has to be sent once)
toggle press btn1: OVERDUB (command has to be sent once)
long press btn1: DELETE

for rec and overdub, no problem:

ToggleButton btn0(BUTTON10); 

void loop() {
    btn0.read();   
    if (btn0.changed()){   
      btn0action();
    }
}

void btn0action(){
      if(action0 == "overdub"){
        action0 = "rec";
        MIDI.sendControlChange(60, 127, 1);
      } else {
        action0 = "overdub";
        MIDI.sendControlChange(60, 0, 1);
      }
   }

How can I detect long press if btn 0 is already declared as a toggle button?

no syntax highlighting when library is included

Hello!
Unfortunately there is no syntax highlighting when the library is included. I think adding the line "JC_Button Keyword1"
to keywords.txt does the trick.

(As I read "Keyword1" should be used for classes. You named your class "Button", but the name of your libary is "JC_Button". Without adding "JC_Button Keyword1" to keywords.txt there is no syntax highlighting when library is included.)

Continuous integration / unit tests

Hello @JChristensen,

Ensuring that this library can still be compiled (using a continuous integration service such as Travis) could be a nice improvement.
Adding some unit tests to ensure that code works correctly could help to make this lib even better.
I have been using https://github.com/ianfixes/arduino_ci recently, (this is quite new in Arduino library development). It can help to achieve this.

Are you interested in a pull request to enable such a feature?
If so I can submit it.

Kind regards

UpDown.ino: Non-working usage of min()/max()...

Hi Jack,

thank you very much for your efforts programming this library.

Maybe you recognized, that i modified your lib for an ESP-32 and its capacitive touch buttons (see https://github.com/dl9sec/JC_CapButton).
While testing the lib I came across a problem with the UpDown example, which did not work neither with tactile buttons, nor with my capacitive touch buttons (the counter always shows 0). First I suspected the ESP-32 architecture, but it was much easier.

Inside the state machine you use the following code:

case INCR:                              // increment the counter
    count = min(count++, MAX_COUNT);    // but not more than the specified maximum
    STATE = WAIT;
    break;

case DECR:                              // decrement the counter
    count = max(count--, MIN_COUNT);    // but not less than the specified minimum
    STATE = WAIT;
    break;

The reason is the usage of min() and max() where you do the increment/decrement math inside the function call.
The Arduino reference explicitly warns about that usage (see https://www.arduino.cc/reference/en/language/functions/math/min/). And the Arduino guys are right... ;-D

Changing the code to

case INCR:                              // increment the counter
    count++;
    count = min(count, MAX_COUNT);    // but not more than the specified maximum
    STATE = WAIT;
    break;

case DECR:                              // decrement the counter
    count--;
    count = max(count, MIN_COUNT);    // but not less than the specified minimum
    STATE = WAIT;
    break;

makes the example work like a charm (also with my capacitive touch buttons).

The good news: I tested your library succesfully on an ESP-32, so you could extend the "architectures" in "library.properties" "with "esp32" (and i am sure on esp8266 too) :-)

Regards, Thorsten

Hello Jack Christensen

Many thancks , for your work and of course your help for beginner.
j m front of your job about your button programe
#include <Button.h> //https://github.com/JChristensen/Button

#define int BUTTON_PIN 2 //Connect a tactile button switch (or something similar)

                       //from Arduino pin 2 to ground.

#define int PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor.

#define int INVERT true //Since the pullup resistor will keep the pin high unless the

                       //switch is closed, this is negative logic, i.e. a high state

                       //means the button is NOT pressed. (Assuming a normally open switch.)

#define int DEBOUNCE_MS 20 //A debounce time of 20 milliseconds usually works well for tactile button switches.

#define LED_PIN 13 //The standard Arduino "Pin 13" LED

Button myBtn(2,true, true, 20); //Declare the button

boolean ledState; //A variable that keeps the current LED status

void setup(void)

{

pinMode(LED_PIN, OUTPUT);    //Set the LED pin as an output

}

void loop(void)

{

myBtn.read();                    //Read the button



if (myBtn.wasReleased()) {       //If the button was released, change the LED state

    ledState = !ledState;

    digitalWrite(LED_PIN, ledState);

}

}
it doesnt work , j get your button librairie in my blilio. please may you help me

double_click check

please can you make a function or simple example for checking if the button is pressed twice, three times, e.t.c

Explicit set to togglebutton

For my sonoff s-20 i extend the toogle-button, because via mqtt excplicit "switch-on" or "switch-off" request is received, and in this case the togglebutton is in the wrong state.

	bool toggleState(bool s) {return m_toggleState = s;}

The actual state is corrected and returned.
Now:
void switch_via_mqtt(int value) {
toggleState(value);
}

Detect Simultaneous Events

How can I detect when two buttons have been simultaneously released? I have tried this and it has never worked.

if (sw1.wasReleased() && sw2.wasReleased()) {

Setup Inputs breaks the code

I found that if I use in the setup area to set up my inputs also, not just my outputs, the code start to act weird, first it is put my led on, then sometimes its start blinking or just dont do anything.
Just modified one of the examples to visualize:


#include <JC_Button.h>          // https://github.com/JChristensen/JC_Button

// pin assignments
const byte
    BUTTON1_PIN(10),            // connect a button switch from this pin to ground
    LED1_PIN(12);                // connect an LED to ground, through an appropriate current limiting resistor

ToggleButton                    // define the buttons
    btn1(BUTTON1_PIN);         // this button's initial state is off


void setup()
{
    // initialize the button objects
    btn1.begin();

    // set the LED pins as outputs
    pinMode(LED1_PIN, OUTPUT);

    //This is breaking the code
    pinMode(BUTTON1_PIN, INPUT);

    // show the initial states
    digitalWrite(LED1_PIN, btn1.toggleState());
}

void loop()
{
    // read the buttons
    btn1.read();

    // if button state changed, update the LEDs
    if (btn1.changed()) digitalWrite(LED1_PIN, btn1.toggleState());

}

Usage notes for ESP8266

The current library code does work on esp8266 even though the architecture in the .properties says avr only.
That said, I spent a day pulling my hair out trying to figure out some issues that were due to some internal design limitations and external h/w used on the esp8266 parts. I was using a WeMos D1 mini.
So here are some usage notes from my clock project:

 * GPIO0, GPIO2, and GPIO15 are special inputs used at reset and power up.
 * GPIO2 is also used for LED control of the built in LED.
 * They control the boot mode:
 *  GPIO15    GPIO0    GPIO2    MODE       Description
 *    L         L        H      UART    Download Code from Uart
 *    L         H        H      FLASH   Boot from SPI flash (normal)
 *    H         x        x      SDIO    Boot from SD card
 *
 * Programing flash using uart0 requires a boot mode of "boot from uart0"
 * with boot_sel=b001, that is, it must make sure
 * GPIO15=0, GPIO0=0, and GPIO2=1 during reset 
 * Because of this, GPIO15 has an external pulldown.
 * This makes these GPIO pins unsuitable for simple grounding switches especially
 * when switches can be pressed at powerup to set modes.
 * GPIO15 and GPIO0 do appear to work correctly after boot and GPIO0 does
 * not appear to have a pull down on it.
 * more docs here:
 * http://esp8266.github.io/Arduino/versions/2.0.0/doc/reference.html
 * https://github.com/CHERTS/esp8266-devkit/tree/master/Espressif/docs/ESP8266

Then there is the difference between Arduino pin #s, which match GPIOn bit numbers on all esp8266 modules, but are different from the Dn symbols provided by the WeMos boards - which are only used on the WeMos boards. i.e. on WeMos boards pin 0 is not the same as pin D0

I think some form of this information, perhaps placed in the readme or the examples, could be very helpful for esp8266 users.

For the examples, GPIO2 is used for the LED so Arduino pin 2 should not be used.


If you don't have any ESP8266 boards to play with, I'd recommend getting a few they are really inexpensive.
My preference is the Wemos D1 mini, and the WeMos D1/Linknode D1 (for uno form factor), and don't get the Wemos D1 R2 as the pinout mapping is a total wreck on the board. I would encourage everyone to avoid that board.
On the uno formfactor boards you want to see D0, D1, etc.. in the normal uno positions starting with Rx on pin 0.
The R2 boards don't do this so the pin mapping is mess and makes the board a pain to use.

LICENSE file

Hello,

Maybe you should put a LICENSE file in this repository

Kind regards

ESP 8266

Is there a way to make this great Library to work together with ESP8266 (Wemos) - Im getting this error
WARNING: library JC_Button-master claims to run on (avr) architecture(s) and may be incompatible with your current board which runs on (esp8266) architecture(s).

Not immune to noise :(

Hello Jack

I've been using and recommending this library for years, but recently had a problem with buttons in a project using this library, and after investigating I found that the problem lies in your debounce code.

The problem is that button press/release changes are detected immediately, your code only prevents multiple changes during the debounce time. Therefore, it's not immune to noise!

To be clear, I always thought the button press/release was detected after the debounce time, not before, to wait for the button state to be stabilized.

Here is a Wokwi demo with the debounce time set to one second : https://wokwi.com/projects/353568497230783489

ESP Support? Pull-Ups not being enabled

Hi to All,
Internal ESP12E pull ups are not being enabled with writing HIGH the digital input pin. Checked with SimpleOnOff example. Same example works as expected with Mega2560.

Using "pinMode(_pin, INPUT_PULLUP);" for enabling the pull ups fixes the issue on ESP12E. Checked with Mega2560 and also Ok.


if (_puEnable != 0)
pinMode(_pin, INPUT_PULLUP); //enable pullup resistor
else (pinMode(_pin, INPUT));

Very minor - extra example req

Greets Jack!
Just found your great Button lib. Very sophisticated - but getting into it. Would be helpful to have one more example of 1 press, 2 presses, 3 presses etc. Might be a more common use case that would help people come up to speed with the lib a bit faster!

=Alan R.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.