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

Dependents:   OneButton_Example ABBlind

Files at this revision

API Documentation at this revision

Comitter:
jaup
Date:
Thu Sep 01 09:21:00 2016 +0000
Parent:
0:62d614796022
Commit message:
frist commit

Changed in this revision

OneButton.cpp Show annotated file Show diff for this revision Revisions of this file
OneButton.h Show annotated file Show diff for this revision Revisions of this file
millis.lib Show diff for this revision Revisions of this file
--- a/OneButton.cpp	Wed Aug 31 10:09:43 2016 +0000
+++ b/OneButton.cpp	Thu Sep 01 09:21:00 2016 +0000
@@ -1,3 +1,6 @@
+// Modifyed to support mbed environment, rewrite the state machine.
+// by Zibin Zheng <znbin@qq.com>
+
 // -----
 // OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
 // This class is implemented for use with the Arduino environment.
@@ -5,45 +8,45 @@
 // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
 // More information on: http://www.mathertel.de/Arduino
 // -----
-// Changelog: see OneButton.h
-// -----
+
 
 #include "OneButton.h"
 
+
 // ----- Initialization and Default Values -----
 
-OneButton::OneButton(PinName pin, int activeLow)
+OneButton::OneButton(PinName pin, bool active_level)
 {
 	btn_pin = new DigitalIn((PinName)pin);      // sets the MenuPin as input
-	_pin = pin;
+
+	timer = new Timer;
+	timer->start();
 
-	_clickTicks = 300;        // number of millisec that have to pass by before a click is detected.
+	_clickTicks = 400;        // number of millisec that have to pass by before a click is detected.
 	_pressTicks = 800;       // number of millisec that have to pass by before a long button press is detected.
+	_debounceTicks = 10;
 
 	_state = 0; // starting with state 0: waiting for button to be pressed
 	_isLongPressed = false;  // Keep track of long press state
 
-	if (activeLow) {
-		// button connects ground to the pin when pressed.
-		_buttonReleased = HIGH; // notPressed
-		_buttonPressed = LOW;
-//		digitalWrite(pin, HIGH);   // turn on pullUp resistor
-		btn_pin->mode(PullUp);
+	button_level = (bool)(btn_pin->read());
+	active = active_level;
+
+	if (active_level) {
+		// button connects VCC to the pin when pressed.
+		btn_pin->mode(PullDown);
 
 	} else {
-		// button connects VCC to the pin when pressed.
-		_buttonReleased = LOW;
-		_buttonPressed = HIGH;
-	} // if
+		// turn on pullUp resistor
+		btn_pin->mode(PullUp);
+	}
 
-
+	_clickFunc = NULL;
+	_pressFunc = NULL;
 	_doubleClickFunc = NULL;
-	_pressFunc = NULL;
 	_longPressStartFunc = NULL;
 	_longPressStopFunc = NULL;
 	_duringLongPressFunc = NULL;
-	
-	startMillis ();
 } // OneButton
 
 
@@ -106,73 +109,86 @@
 	return _isLongPressed;
 }
 
+/**
+  * @brief  Button driver core function, driver state machine.
+  * @param  handle: the button handle strcut.
+  * @retval None
+  */
 void OneButton::tick(void)
 {
-	// Detect the input information
-//	int buttonLevel = digitalRead(_pin); // current button signal.
-	int buttonLevel = btn_pin->read(); // current button signal.
-	unsigned long now = millis(); // current (relative) time in msecs.
+	int read_gpio_level = btn_pin->read(); // current button signal.
 
-	// Implementation of the state machine
-	if (_state == 0) { // waiting for menu pin being pressed.
-		if (buttonLevel == _buttonPressed) {
-			_state = 1; // step to state 1
-			_startTime = now; // remember starting time
-		} // if
+	/*------------button debounce handle---------------*/
+	if(ticks != timer->read_ms()) { //1ms scan again.
+		if(read_gpio_level != button_level) {
+			//continue read 'debounce_cnt' times same new level change
+			if(++_debounce_cnt >= _debounceTicks) {
+				button_level = read_gpio_level;
+				_debounce_cnt = 0;
+			}
 
-	} else if (_state == 1) { // waiting for menu pin being released.
+		} else { //leved not change ,counter reset.
+			_debounce_cnt = 0;
+		}
+	}
 
-		if ((buttonLevel == _buttonReleased) && ((unsigned long)(now - _startTime) < _debounceTicks)) {
-			// button was released to quickly so I assume some debouncing.
-			// go back to state 0 without calling a function.
-			_state = 0;
+	//current (relative) time in msecs.
+	ticks = (uint16_t)(timer->read_ms());
 
-		} else if (buttonLevel == _buttonReleased) {
-			_state = 2; // step to state 2
+	/*-----------------State machine-------------------*/
+	switch (_state) {
+	case 0:
+		if(button_level == active) {	//start press
+			if(_clickFunc) _clickFunc();
+			timer->reset();
+			_state = 1;
+		}
+		break;
 
-		} else if ((buttonLevel == _buttonPressed) && ((unsigned long)(now - _startTime) > _pressTicks)) {
-			_isLongPressed = true;  // Keep track of long press state
-			if (_pressFunc) _pressFunc();
-			if (_longPressStartFunc) _longPressStartFunc();
-			if (_duringLongPressFunc) _duringLongPressFunc();
-			_state = 6; // step to state 6
+	case 1:
+		if(button_level != active) { //released
+			_state = 2;
 
-		} else {
-			// wait. Stay in this state.
-		} // if
+		} else if(ticks > _pressTicks) {
+			if(_longPressStartFunc) _longPressStartFunc();
+			_isLongPressed = 1;
+			_state = 5;
+		}
+		break;
 
-	} else if (_state == 2) { // waiting for menu pin being pressed the second time or timeout.
-		if ((unsigned long)(now - _startTime) > _clickTicks) {
-			// this was only a single short click
-			if (_clickFunc) _clickFunc();
-			_state = 0; // restart.
+	case 2:
+		if(ticks > _clickTicks) {	//released
+			//press event
+			if(_pressFunc) _pressFunc();	//press event
+			_state = 0;	//reset
 
-		} else if (buttonLevel == _buttonPressed) {
-			_state = 3; // step to state 3
-		} // if
+		} else if(button_level == active) { //press again
+			if(_clickFunc) _clickFunc();
+			_state = 3;
+		}
+		break;
 
-	} else if (_state == 3) { // waiting for menu pin being released finally.
-		if (buttonLevel == _buttonReleased) {
-			// this was a 2 click sequence.
-			if (_doubleClickFunc) _doubleClickFunc();
-			_state = 0; // restart.
-		} // if
+	case 3:	//repeat press pressing
+		if(button_level != active) {	//double releasd
+			//double click event
+			if(_doubleClickFunc) _doubleClickFunc();
+			_state = 0;
+		}
+		break;
 
-	} else if (_state == 6) { // waiting for menu pin being release after long press.
-		if (buttonLevel == _buttonReleased) {
-			_isLongPressed = false;  // Keep track of long press state
+	case 5:
+		if(button_level == active) {
+			//continue hold trigger
+			if(_duringLongPressFunc) _duringLongPressFunc();
+
+		} else { //releasd
 			if(_longPressStopFunc) _longPressStopFunc();
-			_state = 0; // restart.
-		} else {
-			// button is being long pressed
-			_isLongPressed = true; // Keep track of long press state
-			if (_duringLongPressFunc) _duringLongPressFunc();
-		} // if
-
-	} // if
-} // OneButton.tick()
-
+			_isLongPressed = 0;
+			_state = 0; //reset
+		}
+		break;
+	}
+}
 
 // end.
 
-
--- a/OneButton.h	Wed Aug 31 10:09:43 2016 +0000
+++ b/OneButton.h	Thu Sep 01 09:21:00 2016 +0000
@@ -1,3 +1,6 @@
+// Modifyed to support mbed environment, rewrite the state machine.
+// by Zibin Zheng <znbin@qq.com>
+
 // -----
 // OneButton.h - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
 // This class is implemented for use with the Arduino environment.
@@ -5,21 +8,66 @@
 // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
 // More information on: http://www.mathertel.de/Arduino
 // -----
-// 02.10.2010 created by Matthias Hertel
-// 21.04.2011 transformed into a library
-// 01.12.2011 include file changed to work with the Arduino 1.0 environment
-// 23.03.2014 Enhanced long press functionalities by adding longPressStart and longPressStop callbacks
-// 21.09.2015 A simple way for debounce detection added.
-// -----
+
 
 #ifndef OneButton_h
 #define OneButton_h
 
 #include "mbed.h"
-#include "millis.h"
+
+
+/**
+ * Example:
+ * @code
+ 
+#include "mbed.h"
+#include "OneButton.h"
+
+Serial pc(SERIAL_TX, SERIAL_RX);
+
+OneButton btn1(PC_13);
+
+void pressed() {
+	pc.printf("pressed\r\n");
+}
+
+void click() {
+	pc.printf("click\r\n");
+}
+
+void double_click() {
+	pc.printf("double_click\r\n");
+}
 
-#define HIGH		1
-#define LOW         0
+void long_start() {
+	pc.printf("long_start\r\n");
+}
+
+void long_hold() {
+	pc.printf("long_hold\r\n");
+}
+
+void long_stop() {
+	pc.printf("long_stop\r\n");
+}
+
+int main() {
+
+	btn1.attachClick(&click);
+	btn1.attachPress(&pressed);
+	btn1.attachDoubleClick(&double_click);
+	btn1.attachLongPressStart(&long_start);
+	btn1.attachDuringLongPress(&long_hold);
+	btn1.attachLongPressStop(&long_stop);
+
+	while(1) {
+
+		btn1.tick(); //loop
+	}
+}
+
+*/
+
 
 // ----- Callback function types -----
 
@@ -31,8 +79,9 @@
 class OneButton
 {
 public:
+
 	// ----- Constructor -----
-	OneButton(PinName pin, int active = 1);
+	OneButton(PinName pin, bool active_level = 0);
 
 	// ----- Set runtime parameters -----
 
@@ -57,15 +106,11 @@
 	bool isLongPressed();
 
 private:
-	int _pin;        // hardware pin number.
 	int _clickTicks; // number of ticks that have to pass by before a click is detected
 	int _pressTicks; // number of ticks that have to pass by before a long button press is detected
-	static 
-	const int _debounceTicks = 10; // number of ticks for debounce times.
 
 	int _buttonReleased;
 	int _buttonPressed;
-
 	bool _isLongPressed;
 
 	// These variables will hold functions acting as event source.
@@ -78,13 +123,18 @@
 
 	// These variables that hold information across the upcoming tick calls.
 	// They are initialized once on program start and are updated every time the tick function is called.
-	int _state;
-	unsigned long _startTime; // will be set in state 1
+	
+	uint16_t ticks;
+	uint8_t _state;
+	uint8_t _debounce_cnt;
+	uint8_t _debounceTicks; // number of ticks for debounce times.
+	bool button_level;
+	bool active;
 	
 	DigitalIn* btn_pin;
+	Timer *timer;
 };
 
 #endif
 
 
-
--- a/millis.lib	Wed Aug 31 10:09:43 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/teams/DFRobot/code/millis/#736e6cc31bcd