diff --git a/examples/LongPress/LongPress.ino b/examples/LongPress/LongPress.ino index 45114d1..4f998ba 100644 --- a/examples/LongPress/LongPress.ino +++ b/examples/LongPress/LongPress.ino @@ -1,59 +1,53 @@ -/*----------------------------------------------------------------------* - * Example sketch for Arduino Button Library by Jack Christensen * - * * - * An example that uses both short and long button presses. * - * * - * A simple state machine where a short press of the button turns the * - * Arduino pin 13 LED on or off, and a long press causes the LED to * - * blink rapidly. Once in rapid blink mode, another long press goes * - * back to on/off mode. * - * * - * This work is licensed under the Creative Commons Attribution- * - * ShareAlike 3.0 Unported License. To view a copy of this license, * - * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * - * letter to Creative Commons, 171 Second Street, Suite 300, * - * San Francisco, California, 94105, USA. * - *----------------------------------------------------------------------*/ +// Arduino Button Library +// https://github.com/JChristensen/JC_Button +// Copyright (C) 2018 by Jack Christensen and licensed under +// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html +// +// Example sketch demonstrating short and long button presses. +// +// A simple state machine where a short press of the button turns the +// Arduino pin 13 LED on or off, and a long press causes the LED to +// blink rapidly. Once in rapid blink mode, another long press goes +// back to on/off mode. -#include //https://github.com/JChristensen/JC_Button +#include // https://github.com/JChristensen/JC_Button -#define BUTTON_PIN 7 //Connect a tactile button switch (or something similar) from this pin to ground. -#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor. -#define 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 DEBOUNCE_MS 25 //A debounce time of 20 milliseconds usually works well for tactile button switches. +// pin assignments +const byte + BUTTON_PIN(7), // connect a button switch from this pin to ground + LED_PIN(13); // the standard Arduino "pin 13" LED -#define LED_PIN 13 //The standard Arduino "Pin 13" LED. -#define LONG_PRESS 1000 //We define a "long press" to be 1000 milliseconds. -#define BLINK_INTERVAL 100 //In the BLINK state, switch the LED every 100 milliseconds. - -Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Define the button - -//The list of possible states for the state machine. This state machine has a fixed -//sequence of states, i.e. ONOFF --> TO_BLINK --> BLINK --> TO_ONOFF --> ONOFF -//Note that while the user perceives two "modes", i.e. ON/OFF mode and rapid blink mode, -//two extra states are needed in the state machine to transition between these modes. -enum {ONOFF, TO_BLINK, BLINK, TO_ONOFF}; -uint8_t STATE; //The current state machine state -boolean ledState; //The current LED status -unsigned long ms; //The current time from millis() -unsigned long msLast; //The last time the LED was switched +Button myBtn(BUTTON_PIN); // define the button +const unsigned long + LONG_PRESS(1000), // we define a "long press" to be 1000 milliseconds. + BLINK_INTERVAL(100); // in the BLINK state, switch the LED every 100 milliseconds. void setup() { - pinMode(LED_PIN, OUTPUT); //Set the LED pin as an output + myBtn.begin(); // initialize the button object + pinMode(LED_PIN, OUTPUT); // set the LED pin as an output } +// the list of possible states for the state machine. This state machine has a fixed +// sequence of states, i.e. ONOFF --> TO_BLINK --> BLINK --> TO_ONOFF --> ONOFF +// note that while the user perceives two "modes", i.e. ON/OFF mode and rapid blink mode, +// two extra states are needed in the state machine to transition between these modes. +enum states_t {ONOFF, TO_BLINK, BLINK, TO_ONOFF}; + +bool ledState; // current LED status +unsigned long ms; // current time from millis() +unsigned long msLast; // last time the LED was switched + void loop() { - ms = millis(); //record the current time - myBtn.read(); //Read the button + static states_t STATE; // current state machine state + ms = millis(); // record the current time + myBtn.read(); // read the button - switch (STATE) { - - //This state watches for short and long presses, switches the LED for - //short presses, and moves to the TO_BLINK state for long presses. + switch (STATE) + { + // this state watches for short and long presses, switches the LED for + // short presses, and moves to the TO_BLINK state for long presses. case ONOFF: if (myBtn.wasReleased()) switchLED(); @@ -61,9 +55,9 @@ void loop() STATE = TO_BLINK; break; - //This is a transition state where we start the fast blink as feedback to the user, - //but we also need to wait for the user to release the button, i.e. end the - //long press, before moving to the BLINK state. + // this is a transition state where we start the fast blink as feedback to the user, + // but we also need to wait for the user to release the button, i.e. end the + // long press, before moving to the BLINK state. case TO_BLINK: if (myBtn.wasReleased()) STATE = BLINK; @@ -71,10 +65,11 @@ void loop() fastBlink(); break; - //The fast-blink state. Watch for another long press which will cause us to - //turn the LED off (as feedback to the user) and move to the TO_ONOFF state. + // the fast-blink state. Watch for another long press which will cause us to + // turn the LED off (as feedback to the user) and move to the TO_ONOFF state. case BLINK: - if (myBtn.pressedFor(LONG_PRESS)) { + if (myBtn.pressedFor(LONG_PRESS)) + { STATE = TO_ONOFF; digitalWrite(LED_PIN, LOW); ledState = false; @@ -83,8 +78,8 @@ void loop() fastBlink(); break; - //This is a transition state where we just wait for the user to release the button - //before moving back to the ONOFF state. + // this is a transition state where we just wait for the user to release the button + // before moving back to the ONOFF state. case TO_ONOFF: if (myBtn.wasReleased()) STATE = ONOFF; @@ -92,15 +87,15 @@ void loop() } } -//Reverse the current LED state. If it's on, turn it off. If it's off, turn it on. +// reverse the current LED state. if it's on, turn it off. If it's off, turn it on. void switchLED() { - msLast = ms; //record the last switch time + msLast = ms; // record the last switch time ledState = !ledState; digitalWrite(LED_PIN, ledState); } -//Switch the LED on and off every BLINK_INETERVAL milliseconds. +// switch the LED on and off every BLINK_INETERVAL milliseconds. void fastBlink() { if (ms - msLast >= BLINK_INTERVAL) diff --git a/examples/SimpleOnOff/SimpleOnOff.ino b/examples/SimpleOnOff/SimpleOnOff.ino index c99bfd2..834991c 100644 --- a/examples/SimpleOnOff/SimpleOnOff.ino +++ b/examples/SimpleOnOff/SimpleOnOff.ino @@ -1,43 +1,35 @@ -/*----------------------------------------------------------------------* - * Example sketch for Arduino Button Library by Jack Christensen * - * * - * The simplest example. Using a tactile button switch to turn * - * the Arduino's pin 13 LED on and off. Wire a switch from Arduino * - * pin 2 to ground. * - * * - * This work is licensed under the Creative Commons Attribution- * - * ShareAlike 3.0 Unported License. To view a copy of this license, * - * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * - * letter to Creative Commons, 171 Second Street, Suite 300, * - * San Francisco, California, 94105, USA. * - *----------------------------------------------------------------------*/ +// Arduino Button Library +// https://github.com/JChristensen/JC_Button +// Copyright (C) 2018 by Jack Christensen and licensed under +// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html +// +// Example sketch to turn an LED on and off with a tactile button switch. +// Wire the switch from the Arduino pin to ground. -#include //https://github.com/JChristensen/JC_Button +#include // https://github.com/JChristensen/JC_Button -#define BUTTON_PIN 7 //Connect a tactile button switch (or something similar) from this pin to ground. -#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor. -#define 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 DEBOUNCE_MS 25 //A debounce time of 25 milliseconds usually works well for tactile button switches. -#define LED_PIN 13 //The standard Arduino "Pin 13" LED +// pin assignments +const byte + BUTTON_PIN(7), // connect a button switch from this pin to ground + LED_PIN(13); // the standard Arduino "pin 13" LED -Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Define the button -boolean ledState; //A variable that keeps the current LED status +Button myBtn(BUTTON_PIN); // define the button void setup() { - pinMode(LED_PIN, OUTPUT); //Set the LED pin as an output + myBtn.begin(); // initialize the button object + pinMode(LED_PIN, OUTPUT); // set the LED pin as an output } void loop() { - myBtn.read(); //Read the button + static bool ledState; // a variable that keeps the current LED status + myBtn.read(); // read the button - if (myBtn.wasReleased()) { //If the button was released, change the LED state + if (myBtn.wasReleased()) // if the button was released, change the LED state + { ledState = !ledState; digitalWrite(LED_PIN, ledState); } } - diff --git a/examples/UpDown/UpDown.ino b/examples/UpDown/UpDown.ino index 4565bfd..7299e8e 100644 --- a/examples/UpDown/UpDown.ino +++ b/examples/UpDown/UpDown.ino @@ -1,85 +1,85 @@ -/*----------------------------------------------------------------------* - * Example sketch for Arduino Button Library by Jack Christensen * - * * - * An example that uses both short and long button presses to adjust * - * a number up and down, between two limits. Short presses increment * - * or decrement by one, long presses repeat at a specified rate. * - * Every time the number changes, it is written to the serial monitor. * - * * - * This work is licensed under the Creative Commons Attribution- * - * ShareAlike 3.0 Unported License. To view a copy of this license, * - * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * - * letter to Creative Commons, 171 Second Street, Suite 300, * - * San Francisco, California, 94105, USA. * - *----------------------------------------------------------------------*/ +// Arduino Button Library +// https://github.com/JChristensen/JC_Button +// Copyright (C) 2018 by Jack Christensen and licensed under +// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html +// +// Example skletch that uses both short and long button presses to adjust +// a number up and down, between two limits. Short presses increment +// or decrement by one, long presses repeat at a specified rate. +// Every time the number changes, it is written to the serial monitor. -#include //https://github.com/JChristensen/JC_Button +#include // https://github.com/JChristensen/JC_Button -#define DN_PIN 7 //Connect two tactile button switches (or something similar) -#define UP_PIN 8 //from Arduino pin 7 to ground and from pin 8 to ground. -#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor. -#define 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 DEBOUNCE_MS 25 //A debounce time of 20 milliseconds usually works well for tactile button switches. +// pin assignments +const byte + DN_PIN(7), // connect a button switch from this pin to ground + UP_PIN(8); // ditto -#define REPEAT_FIRST 500 //ms required before repeating on long press -#define REPEAT_INCR 100 //repeat interval for long press -#define MIN_COUNT 0 -#define MAX_COUNT 59 +Button btnUP(UP_PIN), btnDN(DN_PIN); // define the buttons -Button btnUP(UP_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Define the buttons -Button btnDN(DN_PIN, PULLUP, INVERT, DEBOUNCE_MS); - -enum {WAIT, INCR, DECR}; //The possible states for the state machine -uint8_t STATE; //The current state machine state -int count; //The number that is adjusted -int lastCount = -1; //Previous value of count (initialized to ensure it's different when the sketch starts) -unsigned long rpt = REPEAT_FIRST; //A variable time that is used to drive the repeats for long presses +const unsigned long + REPEAT_FIRST(500), // ms required before repeating on long press + REPEAT_INCR(100); // repeat interval for long press +const int + MIN_COUNT(0), + MAX_COUNT(59); void setup() { + btnUP.begin(); + btnDN.begin(); Serial.begin(115200); } void loop() { - btnUP.read(); //read the buttons + static int + count, // the number that is adjusted + lastCount(-1); // previous value of count (initialized to ensure it's different when the sketch starts) + static unsigned long + rpt(REPEAT_FIRST); // a variable time that is used to drive the repeats for long presses + enum states_t {WAIT, INCR, DECR}; // states for the state machine + static states_t STATE; // current state machine state + + btnUP.read(); // read the buttons btnDN.read(); - if (count != lastCount) { //print the count if it has changed + if (count != lastCount) // print the count if it has changed + { lastCount = count; Serial.println(count, DEC); } - switch (STATE) { - - case WAIT: //wait for a button event + switch (STATE) + { + case WAIT: // wait for a button event if (btnUP.wasPressed()) STATE = INCR; else if (btnDN.wasPressed()) STATE = DECR; - else if (btnUP.wasReleased()) //reset the long press interval + else if (btnUP.wasReleased()) // reset the long press interval rpt = REPEAT_FIRST; else if (btnDN.wasReleased()) rpt = REPEAT_FIRST; - else if (btnUP.pressedFor(rpt)) { //check for long press - rpt += REPEAT_INCR; //increment the long press interval + else if (btnUP.pressedFor(rpt)) // check for long press + { + rpt += REPEAT_INCR; // increment the long press interval STATE = INCR; } - else if (btnDN.pressedFor(rpt)) { + else if (btnDN.pressedFor(rpt)) + { rpt += REPEAT_INCR; STATE = DECR; } break; - case INCR: //increment the counter - count = min(count++, MAX_COUNT); //but not more than the specified maximum + 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 + case DECR: // decrement the counter + count = max(count--, MIN_COUNT); // but not less than the specified minimum STATE = WAIT; break; } diff --git a/src/JC_Button.cpp b/src/JC_Button.cpp index 3c3666f..a025a65 100644 --- a/src/JC_Button.cpp +++ b/src/JC_Button.cpp @@ -1,18 +1,12 @@ -/*----------------------------------------------------------------------* - * Arduino Button Library v1.0 * - * Jack Christensen May 2011, published Mar 2012 * - * * - * Library for reading momentary contact switches like tactile button * - * switches. Intended for use in state machine constructs. * - * Use the read() function to read all buttons in the main loop, * - * which should execute as fast as possible. * - * * - * This work is licensed under the Creative Commons Attribution- * - * ShareAlike 3.0 Unported License. To view a copy of this license, * - * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * - * letter to Creative Commons, 171 Second Street, Suite 300, * - * San Francisco, California, 94105, USA. * - *----------------------------------------------------------------------*/ +// Arduino Button Library +// https://github.com/JChristensen/JC_Button +// Copyright (C) 2018 by Jack Christensen and licensed under +// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html +// +// Library for reading momentary contact switches like tactile button +// switches. Intended for use in state machine constructs. +// Use the read() function to read each button in the main loop, +// which should execute as fast as possible. #include "JC_Button.h" @@ -29,53 +23,41 @@ * (Note that invert cannot be implied from puEnable since an external * * pullup could be used.) * *----------------------------------------------------------------------*/ -Button::Button(uint8_t pin, uint8_t puEnable, uint8_t invert, uint32_t dbTime) + +void Button::begin() { - _pin = pin; - _puEnable = puEnable; - _invert = invert; - _dbTime = dbTime; - if (_puEnable != 0) - pinMode(_pin, INPUT_PULLUP); //enable pullup resistor - else - pinMode(_pin, INPUT); - _state = digitalRead(_pin); - if (_invert != 0) _state = !_state; - _time = millis(); - _lastState = _state; - _changed = 0; - _lastChange = _time; + pinMode(m_pin, m_puEnable ? INPUT_PULLUP : INPUT); + m_state = digitalRead(m_pin); + if (m_invert) m_state = !m_state; + m_time = millis(); + m_lastState = m_state; + m_changed = false; + m_lastChange = m_time; } /*----------------------------------------------------------------------* - * read() returns the state of the button, 1==pressed, 0==released, * - * does debouncing, captures and maintains times, previous states, etc. * - *----------------------------------------------------------------------*/ -uint8_t Button::read(void) +/ returns the state of the button, true==pressed, false==released, * +/ does debouncing, captures and maintains times, previous states, etc. * +/-----------------------------------------------------------------------*/ +bool Button::read() { - static uint32_t ms; - static uint8_t pinVal; - - ms = millis(); - pinVal = digitalRead(_pin); - if (_invert != 0) pinVal = !pinVal; - if (ms - _lastChange < _dbTime) { - _time = ms; - _changed = 0; - return _state; + uint32_t ms = millis(); + uint8_t pinVal = digitalRead(m_pin); + if (m_invert) pinVal = !pinVal; + if (ms - m_lastChange < m_dbTime) + { + m_time = ms; + m_changed = false; + return m_state; } - else { - _lastState = _state; - _state = pinVal; - _time = ms; - if (_state != _lastState) { - _lastChange = ms; - _changed = 1; - } - else { - _changed = 0; - } - return _state; + else + { + m_lastState = m_state; + m_state = pinVal; + m_time = ms; + m_changed = (m_state != m_lastState); + if (m_changed) m_lastChange = ms; + return m_state; } } @@ -84,14 +66,14 @@ uint8_t Button::read(void) * read, and return false (0) or true (!=0) accordingly. * * These functions do not cause the button to be read. * *----------------------------------------------------------------------*/ -uint8_t Button::isPressed(void) +bool Button::isPressed() { - return _state == 0 ? 0 : 1; + return m_state; } -uint8_t Button::isReleased(void) +bool Button::isReleased() { - return _state == 0 ? 1 : 0; + return m_state; } /*----------------------------------------------------------------------* @@ -100,37 +82,37 @@ uint8_t Button::isReleased(void) * true (!=0) accordingly. * * These functions do not cause the button to be read. * *----------------------------------------------------------------------*/ -uint8_t Button::wasPressed(void) +bool Button::wasPressed() { - return _state && _changed; + return m_state && m_changed; } -uint8_t Button::wasReleased(void) +bool Button::wasReleased() { - return !_state && _changed; + return !m_state && m_changed; } /*----------------------------------------------------------------------* * pressedFor(ms) and releasedFor(ms) check to see if the button is * * pressed (or released), and has been in that state for the specified * - * time in milliseconds. Returns false (0) or true (1) accordingly. * + * time in milliseconds. Returns false (0) or true (!=0) accordingly. * * These functions do not cause the button to be read. * *----------------------------------------------------------------------*/ -uint8_t Button::pressedFor(uint32_t ms) +bool Button::pressedFor(uint32_t ms) { - return (_state == 1 && _time - _lastChange >= ms) ? 1 : 0; + return m_state && m_time - m_lastChange >= ms; } -uint8_t Button::releasedFor(uint32_t ms) +bool Button::releasedFor(uint32_t ms) { - return (_state == 0 && _time - _lastChange >= ms) ? 1 : 0; + return !m_state && m_time - m_lastChange >= ms; } /*----------------------------------------------------------------------* * lastChange() returns the time the button last changed state, * * in milliseconds. * *----------------------------------------------------------------------*/ -uint32_t Button::lastChange(void) +uint32_t Button::lastChange() { - return _lastChange; + return m_lastChange; } diff --git a/src/JC_Button.h b/src/JC_Button.h index b6ce55e..e050870 100644 --- a/src/JC_Button.h +++ b/src/JC_Button.h @@ -1,42 +1,37 @@ -/*----------------------------------------------------------------------* - * Arduino Button Library v1.0 * - * Jack Christensen Mar 2012 * - * * - * This work is licensed under the Creative Commons Attribution- * - * ShareAlike 3.0 Unported License. To view a copy of this license, * - * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * - * letter to Creative Commons, 171 Second Street, Suite 300, * - * San Francisco, California, 94105, USA. * - *----------------------------------------------------------------------*/ -#ifndef Button_h -#define Button_h -#if ARDUINO >= 100 +// Arduino Button Library +// https://github.com/JChristensen/JC_Button +// Copyright (C) 2018 by Jack Christensen and licensed under +// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html + +#ifndef JC_BUTTON_H_INCLUDED +#define JC_BUTTON_H_INCLUDED + #include -#else -#include -#endif + class Button { public: - Button(uint8_t pin, uint8_t puEnable, uint8_t invert, uint32_t dbTime); - uint8_t read(); - uint8_t isPressed(); - uint8_t isReleased(); - uint8_t wasPressed(); - uint8_t wasReleased(); - uint8_t pressedFor(uint32_t ms); - uint8_t releasedFor(uint32_t ms); + Button::Button(uint8_t pin, uint32_t dbTime=25, uint8_t puEnable=true, uint8_t invert=true) + : m_pin(pin), m_dbTime(dbTime), m_puEnable(puEnable), m_invert(invert) {} + void begin(); + bool read(); + bool isPressed(); + bool isReleased(); + bool wasPressed(); + bool wasReleased(); + bool pressedFor(uint32_t ms); + bool releasedFor(uint32_t ms); uint32_t lastChange(); private: - uint8_t _pin; //arduino pin number - uint8_t _puEnable; //internal pullup resistor enabled - uint8_t _invert; //if 0, interpret high state as pressed, else interpret low state as pressed - uint8_t _state; //current button state - uint8_t _lastState; //previous button state - uint8_t _changed; //state changed since last read - uint32_t _time; //time of current state (all times are in ms) - uint32_t _lastChange; //time of last state change - uint32_t _dbTime; //debounce time + uint8_t m_pin; // arduino pin number connected to button + bool m_puEnable; // internal pullup resistor enabled + bool m_invert; // if true, interpret logic low as pressed, else interpret logic high as pressed + bool m_state; // current button state, true=pressed + bool m_lastState; // previous button state + bool m_changed; // state changed since last read + uint32_t m_time; // time of current state (ms from millis) + uint32_t m_lastChange; // time of last state change (ms) + uint32_t m_dbTime; // debounce time (ms) }; #endif