Library for detecting button clicks, doubleclicks and long press pattern on a single button.

Dependents:   OneButton_Example ABBlind

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?

UserRevisionLine numberNew 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