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

Dependents:   OneButton_Example ABBlind

Committer:
jaup
Date:
Thu Sep 01 09:21:00 2016 +0000
Revision:
1:fdf67f893a5c
Parent:
0:62d614796022
frist commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jaup 1:fdf67f893a5c 1 // Modifyed to support mbed environment, rewrite the state machine.
jaup 1:fdf67f893a5c 2 // by Zibin Zheng <znbin@qq.com>
jaup 1:fdf67f893a5c 3
jaup 0:62d614796022 4 // -----
jaup 0:62d614796022 5 // OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
jaup 0:62d614796022 6 // This class is implemented for use with the Arduino environment.
jaup 0:62d614796022 7 // Copyright (c) by Matthias Hertel, http://www.mathertel.de
jaup 0:62d614796022 8 // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
jaup 0:62d614796022 9 // More information on: http://www.mathertel.de/Arduino
jaup 0:62d614796022 10 // -----
jaup 1:fdf67f893a5c 11
jaup 0:62d614796022 12
jaup 0:62d614796022 13 #include "OneButton.h"
jaup 0:62d614796022 14
jaup 1:fdf67f893a5c 15
jaup 0:62d614796022 16 // ----- Initialization and Default Values -----
jaup 0:62d614796022 17
jaup 1:fdf67f893a5c 18 OneButton::OneButton(PinName pin, bool active_level)
jaup 0:62d614796022 19 {
jaup 0:62d614796022 20 btn_pin = new DigitalIn((PinName)pin); // sets the MenuPin as input
jaup 1:fdf67f893a5c 21
jaup 1:fdf67f893a5c 22 timer = new Timer;
jaup 1:fdf67f893a5c 23 timer->start();
jaup 0:62d614796022 24
jaup 1:fdf67f893a5c 25 _clickTicks = 400; // number of millisec that have to pass by before a click is detected.
jaup 0:62d614796022 26 _pressTicks = 800; // number of millisec that have to pass by before a long button press is detected.
jaup 1:fdf67f893a5c 27 _debounceTicks = 10;
jaup 0:62d614796022 28
jaup 0:62d614796022 29 _state = 0; // starting with state 0: waiting for button to be pressed
jaup 0:62d614796022 30 _isLongPressed = false; // Keep track of long press state
jaup 0:62d614796022 31
jaup 1:fdf67f893a5c 32 button_level = (bool)(btn_pin->read());
jaup 1:fdf67f893a5c 33 active = active_level;
jaup 1:fdf67f893a5c 34
jaup 1:fdf67f893a5c 35 if (active_level) {
jaup 1:fdf67f893a5c 36 // button connects VCC to the pin when pressed.
jaup 1:fdf67f893a5c 37 btn_pin->mode(PullDown);
jaup 0:62d614796022 38
jaup 0:62d614796022 39 } else {
jaup 1:fdf67f893a5c 40 // turn on pullUp resistor
jaup 1:fdf67f893a5c 41 btn_pin->mode(PullUp);
jaup 1:fdf67f893a5c 42 }
jaup 0:62d614796022 43
jaup 1:fdf67f893a5c 44 _clickFunc = NULL;
jaup 1:fdf67f893a5c 45 _pressFunc = NULL;
jaup 0:62d614796022 46 _doubleClickFunc = NULL;
jaup 0:62d614796022 47 _longPressStartFunc = NULL;
jaup 0:62d614796022 48 _longPressStopFunc = NULL;
jaup 0:62d614796022 49 _duringLongPressFunc = NULL;
jaup 0:62d614796022 50 } // OneButton
jaup 0:62d614796022 51
jaup 0:62d614796022 52
jaup 0:62d614796022 53 // explicitly set the number of millisec that have to pass by before a click is detected.
jaup 0:62d614796022 54 void OneButton::setClickTicks(int ticks)
jaup 0:62d614796022 55 {
jaup 0:62d614796022 56 _clickTicks = ticks;
jaup 0:62d614796022 57 } // setClickTicks
jaup 0:62d614796022 58
jaup 0:62d614796022 59
jaup 0:62d614796022 60 // explicitly set the number of millisec that have to pass by before a long button press is detected.
jaup 0:62d614796022 61 void OneButton::setPressTicks(int ticks)
jaup 0:62d614796022 62 {
jaup 0:62d614796022 63 _pressTicks = ticks;
jaup 0:62d614796022 64 } // setPressTicks
jaup 0:62d614796022 65
jaup 0:62d614796022 66
jaup 0:62d614796022 67 // save function for click event
jaup 0:62d614796022 68 void OneButton::attachClick(callbackFunction newFunction)
jaup 0:62d614796022 69 {
jaup 0:62d614796022 70 _clickFunc = newFunction;
jaup 0:62d614796022 71 } // attachClick
jaup 0:62d614796022 72
jaup 0:62d614796022 73
jaup 0:62d614796022 74 // save function for doubleClick event
jaup 0:62d614796022 75 void OneButton::attachDoubleClick(callbackFunction newFunction)
jaup 0:62d614796022 76 {
jaup 0:62d614796022 77 _doubleClickFunc = newFunction;
jaup 0:62d614796022 78 } // attachDoubleClick
jaup 0:62d614796022 79
jaup 0:62d614796022 80
jaup 0:62d614796022 81 // save function for press event
jaup 0:62d614796022 82 // DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress,
jaup 0:62d614796022 83 void OneButton::attachPress(callbackFunction newFunction)
jaup 0:62d614796022 84 {
jaup 0:62d614796022 85 _pressFunc = newFunction;
jaup 0:62d614796022 86 } // attachPress
jaup 0:62d614796022 87
jaup 0:62d614796022 88 // save function for longPressStart event
jaup 0:62d614796022 89 void OneButton::attachLongPressStart(callbackFunction newFunction)
jaup 0:62d614796022 90 {
jaup 0:62d614796022 91 _longPressStartFunc = newFunction;
jaup 0:62d614796022 92 } // attachLongPressStart
jaup 0:62d614796022 93
jaup 0:62d614796022 94 // save function for longPressStop event
jaup 0:62d614796022 95 void OneButton::attachLongPressStop(callbackFunction newFunction)
jaup 0:62d614796022 96 {
jaup 0:62d614796022 97 _longPressStopFunc = newFunction;
jaup 0:62d614796022 98 } // attachLongPressStop
jaup 0:62d614796022 99
jaup 0:62d614796022 100 // save function for during longPress event
jaup 0:62d614796022 101 void OneButton::attachDuringLongPress(callbackFunction newFunction)
jaup 0:62d614796022 102 {
jaup 0:62d614796022 103 _duringLongPressFunc = newFunction;
jaup 0:62d614796022 104 } // attachDuringLongPress
jaup 0:62d614796022 105
jaup 0:62d614796022 106 // function to get the current long pressed state
jaup 0:62d614796022 107 bool OneButton::isLongPressed()
jaup 0:62d614796022 108 {
jaup 0:62d614796022 109 return _isLongPressed;
jaup 0:62d614796022 110 }
jaup 0:62d614796022 111
jaup 1:fdf67f893a5c 112 /**
jaup 1:fdf67f893a5c 113 * @brief Button driver core function, driver state machine.
jaup 1:fdf67f893a5c 114 * @param handle: the button handle strcut.
jaup 1:fdf67f893a5c 115 * @retval None
jaup 1:fdf67f893a5c 116 */
jaup 0:62d614796022 117 void OneButton::tick(void)
jaup 0:62d614796022 118 {
jaup 1:fdf67f893a5c 119 int read_gpio_level = btn_pin->read(); // current button signal.
jaup 0:62d614796022 120
jaup 1:fdf67f893a5c 121 /*------------button debounce handle---------------*/
jaup 1:fdf67f893a5c 122 if(ticks != timer->read_ms()) { //1ms scan again.
jaup 1:fdf67f893a5c 123 if(read_gpio_level != button_level) {
jaup 1:fdf67f893a5c 124 //continue read 'debounce_cnt' times same new level change
jaup 1:fdf67f893a5c 125 if(++_debounce_cnt >= _debounceTicks) {
jaup 1:fdf67f893a5c 126 button_level = read_gpio_level;
jaup 1:fdf67f893a5c 127 _debounce_cnt = 0;
jaup 1:fdf67f893a5c 128 }
jaup 0:62d614796022 129
jaup 1:fdf67f893a5c 130 } else { //leved not change ,counter reset.
jaup 1:fdf67f893a5c 131 _debounce_cnt = 0;
jaup 1:fdf67f893a5c 132 }
jaup 1:fdf67f893a5c 133 }
jaup 0:62d614796022 134
jaup 1:fdf67f893a5c 135 //current (relative) time in msecs.
jaup 1:fdf67f893a5c 136 ticks = (uint16_t)(timer->read_ms());
jaup 0:62d614796022 137
jaup 1:fdf67f893a5c 138 /*-----------------State machine-------------------*/
jaup 1:fdf67f893a5c 139 switch (_state) {
jaup 1:fdf67f893a5c 140 case 0:
jaup 1:fdf67f893a5c 141 if(button_level == active) { //start press
jaup 1:fdf67f893a5c 142 if(_clickFunc) _clickFunc();
jaup 1:fdf67f893a5c 143 timer->reset();
jaup 1:fdf67f893a5c 144 _state = 1;
jaup 1:fdf67f893a5c 145 }
jaup 1:fdf67f893a5c 146 break;
jaup 0:62d614796022 147
jaup 1:fdf67f893a5c 148 case 1:
jaup 1:fdf67f893a5c 149 if(button_level != active) { //released
jaup 1:fdf67f893a5c 150 _state = 2;
jaup 0:62d614796022 151
jaup 1:fdf67f893a5c 152 } else if(ticks > _pressTicks) {
jaup 1:fdf67f893a5c 153 if(_longPressStartFunc) _longPressStartFunc();
jaup 1:fdf67f893a5c 154 _isLongPressed = 1;
jaup 1:fdf67f893a5c 155 _state = 5;
jaup 1:fdf67f893a5c 156 }
jaup 1:fdf67f893a5c 157 break;
jaup 0:62d614796022 158
jaup 1:fdf67f893a5c 159 case 2:
jaup 1:fdf67f893a5c 160 if(ticks > _clickTicks) { //released
jaup 1:fdf67f893a5c 161 //press event
jaup 1:fdf67f893a5c 162 if(_pressFunc) _pressFunc(); //press event
jaup 1:fdf67f893a5c 163 _state = 0; //reset
jaup 0:62d614796022 164
jaup 1:fdf67f893a5c 165 } else if(button_level == active) { //press again
jaup 1:fdf67f893a5c 166 if(_clickFunc) _clickFunc();
jaup 1:fdf67f893a5c 167 _state = 3;
jaup 1:fdf67f893a5c 168 }
jaup 1:fdf67f893a5c 169 break;
jaup 0:62d614796022 170
jaup 1:fdf67f893a5c 171 case 3: //repeat press pressing
jaup 1:fdf67f893a5c 172 if(button_level != active) { //double releasd
jaup 1:fdf67f893a5c 173 //double click event
jaup 1:fdf67f893a5c 174 if(_doubleClickFunc) _doubleClickFunc();
jaup 1:fdf67f893a5c 175 _state = 0;
jaup 1:fdf67f893a5c 176 }
jaup 1:fdf67f893a5c 177 break;
jaup 0:62d614796022 178
jaup 1:fdf67f893a5c 179 case 5:
jaup 1:fdf67f893a5c 180 if(button_level == active) {
jaup 1:fdf67f893a5c 181 //continue hold trigger
jaup 1:fdf67f893a5c 182 if(_duringLongPressFunc) _duringLongPressFunc();
jaup 1:fdf67f893a5c 183
jaup 1:fdf67f893a5c 184 } else { //releasd
jaup 0:62d614796022 185 if(_longPressStopFunc) _longPressStopFunc();
jaup 1:fdf67f893a5c 186 _isLongPressed = 0;
jaup 1:fdf67f893a5c 187 _state = 0; //reset
jaup 1:fdf67f893a5c 188 }
jaup 1:fdf67f893a5c 189 break;
jaup 1:fdf67f893a5c 190 }
jaup 1:fdf67f893a5c 191 }
jaup 0:62d614796022 192
jaup 0:62d614796022 193 // end.
jaup 0:62d614796022 194