Library for detecting button clicks, doubleclicks and long press pattern on a single button.
Dependents: OneButton_Example ABBlind
OneButton.cpp@0:62d614796022, 2016-08-31 (annotated)
- Committer:
- jaup
- Date:
- Wed Aug 31 10:09:43 2016 +0000
- Revision:
- 0:62d614796022
- Child:
- 1:fdf67f893a5c
event-driven button driver
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jaup | 0:62d614796022 | 1 | // ----- |
jaup | 0:62d614796022 | 2 | // OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button. |
jaup | 0:62d614796022 | 3 | // This class is implemented for use with the Arduino environment. |
jaup | 0:62d614796022 | 4 | // Copyright (c) by Matthias Hertel, http://www.mathertel.de |
jaup | 0:62d614796022 | 5 | // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx |
jaup | 0:62d614796022 | 6 | // More information on: http://www.mathertel.de/Arduino |
jaup | 0:62d614796022 | 7 | // ----- |
jaup | 0:62d614796022 | 8 | // Changelog: see OneButton.h |
jaup | 0:62d614796022 | 9 | // ----- |
jaup | 0:62d614796022 | 10 | |
jaup | 0:62d614796022 | 11 | #include "OneButton.h" |
jaup | 0:62d614796022 | 12 | |
jaup | 0:62d614796022 | 13 | // ----- Initialization and Default Values ----- |
jaup | 0:62d614796022 | 14 | |
jaup | 0:62d614796022 | 15 | OneButton::OneButton(PinName pin, int activeLow) |
jaup | 0:62d614796022 | 16 | { |
jaup | 0:62d614796022 | 17 | btn_pin = new DigitalIn((PinName)pin); // sets the MenuPin as input |
jaup | 0:62d614796022 | 18 | _pin = pin; |
jaup | 0:62d614796022 | 19 | |
jaup | 0:62d614796022 | 20 | _clickTicks = 300; // number of millisec that have to pass by before a click is detected. |
jaup | 0:62d614796022 | 21 | _pressTicks = 800; // number of millisec that have to pass by before a long button press is detected. |
jaup | 0:62d614796022 | 22 | |
jaup | 0:62d614796022 | 23 | _state = 0; // starting with state 0: waiting for button to be pressed |
jaup | 0:62d614796022 | 24 | _isLongPressed = false; // Keep track of long press state |
jaup | 0:62d614796022 | 25 | |
jaup | 0:62d614796022 | 26 | if (activeLow) { |
jaup | 0:62d614796022 | 27 | // button connects ground to the pin when pressed. |
jaup | 0:62d614796022 | 28 | _buttonReleased = HIGH; // notPressed |
jaup | 0:62d614796022 | 29 | _buttonPressed = LOW; |
jaup | 0:62d614796022 | 30 | // digitalWrite(pin, HIGH); // turn on pullUp resistor |
jaup | 0:62d614796022 | 31 | btn_pin->mode(PullUp); |
jaup | 0:62d614796022 | 32 | |
jaup | 0:62d614796022 | 33 | } else { |
jaup | 0:62d614796022 | 34 | // button connects VCC to the pin when pressed. |
jaup | 0:62d614796022 | 35 | _buttonReleased = LOW; |
jaup | 0:62d614796022 | 36 | _buttonPressed = HIGH; |
jaup | 0:62d614796022 | 37 | } // if |
jaup | 0:62d614796022 | 38 | |
jaup | 0:62d614796022 | 39 | |
jaup | 0:62d614796022 | 40 | _doubleClickFunc = NULL; |
jaup | 0:62d614796022 | 41 | _pressFunc = NULL; |
jaup | 0:62d614796022 | 42 | _longPressStartFunc = NULL; |
jaup | 0:62d614796022 | 43 | _longPressStopFunc = NULL; |
jaup | 0:62d614796022 | 44 | _duringLongPressFunc = NULL; |
jaup | 0:62d614796022 | 45 | |
jaup | 0:62d614796022 | 46 | startMillis (); |
jaup | 0:62d614796022 | 47 | } // OneButton |
jaup | 0:62d614796022 | 48 | |
jaup | 0:62d614796022 | 49 | |
jaup | 0:62d614796022 | 50 | // explicitly set the number of millisec that have to pass by before a click is detected. |
jaup | 0:62d614796022 | 51 | void OneButton::setClickTicks(int ticks) |
jaup | 0:62d614796022 | 52 | { |
jaup | 0:62d614796022 | 53 | _clickTicks = ticks; |
jaup | 0:62d614796022 | 54 | } // setClickTicks |
jaup | 0:62d614796022 | 55 | |
jaup | 0:62d614796022 | 56 | |
jaup | 0:62d614796022 | 57 | // explicitly set the number of millisec that have to pass by before a long button press is detected. |
jaup | 0:62d614796022 | 58 | void OneButton::setPressTicks(int ticks) |
jaup | 0:62d614796022 | 59 | { |
jaup | 0:62d614796022 | 60 | _pressTicks = ticks; |
jaup | 0:62d614796022 | 61 | } // setPressTicks |
jaup | 0:62d614796022 | 62 | |
jaup | 0:62d614796022 | 63 | |
jaup | 0:62d614796022 | 64 | // save function for click event |
jaup | 0:62d614796022 | 65 | void OneButton::attachClick(callbackFunction newFunction) |
jaup | 0:62d614796022 | 66 | { |
jaup | 0:62d614796022 | 67 | _clickFunc = newFunction; |
jaup | 0:62d614796022 | 68 | } // attachClick |
jaup | 0:62d614796022 | 69 | |
jaup | 0:62d614796022 | 70 | |
jaup | 0:62d614796022 | 71 | // save function for doubleClick event |
jaup | 0:62d614796022 | 72 | void OneButton::attachDoubleClick(callbackFunction newFunction) |
jaup | 0:62d614796022 | 73 | { |
jaup | 0:62d614796022 | 74 | _doubleClickFunc = newFunction; |
jaup | 0:62d614796022 | 75 | } // attachDoubleClick |
jaup | 0:62d614796022 | 76 | |
jaup | 0:62d614796022 | 77 | |
jaup | 0:62d614796022 | 78 | // save function for press event |
jaup | 0:62d614796022 | 79 | // DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress, |
jaup | 0:62d614796022 | 80 | void OneButton::attachPress(callbackFunction newFunction) |
jaup | 0:62d614796022 | 81 | { |
jaup | 0:62d614796022 | 82 | _pressFunc = newFunction; |
jaup | 0:62d614796022 | 83 | } // attachPress |
jaup | 0:62d614796022 | 84 | |
jaup | 0:62d614796022 | 85 | // save function for longPressStart event |
jaup | 0:62d614796022 | 86 | void OneButton::attachLongPressStart(callbackFunction newFunction) |
jaup | 0:62d614796022 | 87 | { |
jaup | 0:62d614796022 | 88 | _longPressStartFunc = newFunction; |
jaup | 0:62d614796022 | 89 | } // attachLongPressStart |
jaup | 0:62d614796022 | 90 | |
jaup | 0:62d614796022 | 91 | // save function for longPressStop event |
jaup | 0:62d614796022 | 92 | void OneButton::attachLongPressStop(callbackFunction newFunction) |
jaup | 0:62d614796022 | 93 | { |
jaup | 0:62d614796022 | 94 | _longPressStopFunc = newFunction; |
jaup | 0:62d614796022 | 95 | } // attachLongPressStop |
jaup | 0:62d614796022 | 96 | |
jaup | 0:62d614796022 | 97 | // save function for during longPress event |
jaup | 0:62d614796022 | 98 | void OneButton::attachDuringLongPress(callbackFunction newFunction) |
jaup | 0:62d614796022 | 99 | { |
jaup | 0:62d614796022 | 100 | _duringLongPressFunc = newFunction; |
jaup | 0:62d614796022 | 101 | } // attachDuringLongPress |
jaup | 0:62d614796022 | 102 | |
jaup | 0:62d614796022 | 103 | // function to get the current long pressed state |
jaup | 0:62d614796022 | 104 | bool OneButton::isLongPressed() |
jaup | 0:62d614796022 | 105 | { |
jaup | 0:62d614796022 | 106 | return _isLongPressed; |
jaup | 0:62d614796022 | 107 | } |
jaup | 0:62d614796022 | 108 | |
jaup | 0:62d614796022 | 109 | void OneButton::tick(void) |
jaup | 0:62d614796022 | 110 | { |
jaup | 0:62d614796022 | 111 | // Detect the input information |
jaup | 0:62d614796022 | 112 | // int buttonLevel = digitalRead(_pin); // current button signal. |
jaup | 0:62d614796022 | 113 | int buttonLevel = btn_pin->read(); // current button signal. |
jaup | 0:62d614796022 | 114 | unsigned long now = millis(); // current (relative) time in msecs. |
jaup | 0:62d614796022 | 115 | |
jaup | 0:62d614796022 | 116 | // Implementation of the state machine |
jaup | 0:62d614796022 | 117 | if (_state == 0) { // waiting for menu pin being pressed. |
jaup | 0:62d614796022 | 118 | if (buttonLevel == _buttonPressed) { |
jaup | 0:62d614796022 | 119 | _state = 1; // step to state 1 |
jaup | 0:62d614796022 | 120 | _startTime = now; // remember starting time |
jaup | 0:62d614796022 | 121 | } // if |
jaup | 0:62d614796022 | 122 | |
jaup | 0:62d614796022 | 123 | } else if (_state == 1) { // waiting for menu pin being released. |
jaup | 0:62d614796022 | 124 | |
jaup | 0:62d614796022 | 125 | if ((buttonLevel == _buttonReleased) && ((unsigned long)(now - _startTime) < _debounceTicks)) { |
jaup | 0:62d614796022 | 126 | // button was released to quickly so I assume some debouncing. |
jaup | 0:62d614796022 | 127 | // go back to state 0 without calling a function. |
jaup | 0:62d614796022 | 128 | _state = 0; |
jaup | 0:62d614796022 | 129 | |
jaup | 0:62d614796022 | 130 | } else if (buttonLevel == _buttonReleased) { |
jaup | 0:62d614796022 | 131 | _state = 2; // step to state 2 |
jaup | 0:62d614796022 | 132 | |
jaup | 0:62d614796022 | 133 | } else if ((buttonLevel == _buttonPressed) && ((unsigned long)(now - _startTime) > _pressTicks)) { |
jaup | 0:62d614796022 | 134 | _isLongPressed = true; // Keep track of long press state |
jaup | 0:62d614796022 | 135 | if (_pressFunc) _pressFunc(); |
jaup | 0:62d614796022 | 136 | if (_longPressStartFunc) _longPressStartFunc(); |
jaup | 0:62d614796022 | 137 | if (_duringLongPressFunc) _duringLongPressFunc(); |
jaup | 0:62d614796022 | 138 | _state = 6; // step to state 6 |
jaup | 0:62d614796022 | 139 | |
jaup | 0:62d614796022 | 140 | } else { |
jaup | 0:62d614796022 | 141 | // wait. Stay in this state. |
jaup | 0:62d614796022 | 142 | } // if |
jaup | 0:62d614796022 | 143 | |
jaup | 0:62d614796022 | 144 | } else if (_state == 2) { // waiting for menu pin being pressed the second time or timeout. |
jaup | 0:62d614796022 | 145 | if ((unsigned long)(now - _startTime) > _clickTicks) { |
jaup | 0:62d614796022 | 146 | // this was only a single short click |
jaup | 0:62d614796022 | 147 | if (_clickFunc) _clickFunc(); |
jaup | 0:62d614796022 | 148 | _state = 0; // restart. |
jaup | 0:62d614796022 | 149 | |
jaup | 0:62d614796022 | 150 | } else if (buttonLevel == _buttonPressed) { |
jaup | 0:62d614796022 | 151 | _state = 3; // step to state 3 |
jaup | 0:62d614796022 | 152 | } // if |
jaup | 0:62d614796022 | 153 | |
jaup | 0:62d614796022 | 154 | } else if (_state == 3) { // waiting for menu pin being released finally. |
jaup | 0:62d614796022 | 155 | if (buttonLevel == _buttonReleased) { |
jaup | 0:62d614796022 | 156 | // this was a 2 click sequence. |
jaup | 0:62d614796022 | 157 | if (_doubleClickFunc) _doubleClickFunc(); |
jaup | 0:62d614796022 | 158 | _state = 0; // restart. |
jaup | 0:62d614796022 | 159 | } // if |
jaup | 0:62d614796022 | 160 | |
jaup | 0:62d614796022 | 161 | } else if (_state == 6) { // waiting for menu pin being release after long press. |
jaup | 0:62d614796022 | 162 | if (buttonLevel == _buttonReleased) { |
jaup | 0:62d614796022 | 163 | _isLongPressed = false; // Keep track of long press state |
jaup | 0:62d614796022 | 164 | if(_longPressStopFunc) _longPressStopFunc(); |
jaup | 0:62d614796022 | 165 | _state = 0; // restart. |
jaup | 0:62d614796022 | 166 | } else { |
jaup | 0:62d614796022 | 167 | // button is being long pressed |
jaup | 0:62d614796022 | 168 | _isLongPressed = true; // Keep track of long press state |
jaup | 0:62d614796022 | 169 | if (_duringLongPressFunc) _duringLongPressFunc(); |
jaup | 0:62d614796022 | 170 | } // if |
jaup | 0:62d614796022 | 171 | |
jaup | 0:62d614796022 | 172 | } // if |
jaup | 0:62d614796022 | 173 | } // OneButton.tick() |
jaup | 0:62d614796022 | 174 | |
jaup | 0:62d614796022 | 175 | |
jaup | 0:62d614796022 | 176 | // end. |
jaup | 0:62d614796022 | 177 | |
jaup | 0:62d614796022 | 178 |