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

Dependents:   OneButton_Example ABBlind

Revision:
0:62d614796022
Child:
1:fdf67f893a5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OneButton.cpp	Wed Aug 31 10:09:43 2016 +0000
@@ -0,0 +1,178 @@
+// -----
+// 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.
+// Copyright (c) by Matthias Hertel, http://www.mathertel.de
+// 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)
+{
+	btn_pin = new DigitalIn((PinName)pin);      // sets the MenuPin as input
+	_pin = pin;
+
+	_clickTicks = 300;        // 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.
+
+	_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);
+
+	} else {
+		// button connects VCC to the pin when pressed.
+		_buttonReleased = LOW;
+		_buttonPressed = HIGH;
+	} // if
+
+
+	_doubleClickFunc = NULL;
+	_pressFunc = NULL;
+	_longPressStartFunc = NULL;
+	_longPressStopFunc = NULL;
+	_duringLongPressFunc = NULL;
+	
+	startMillis ();
+} // OneButton
+
+
+// explicitly set the number of millisec that have to pass by before a click is detected.
+void OneButton::setClickTicks(int ticks)
+{
+	_clickTicks = ticks;
+} // setClickTicks
+
+
+// explicitly set the number of millisec that have to pass by before a long button press is detected.
+void OneButton::setPressTicks(int ticks)
+{
+	_pressTicks = ticks;
+} // setPressTicks
+
+
+// save function for click event
+void OneButton::attachClick(callbackFunction newFunction)
+{
+	_clickFunc = newFunction;
+} // attachClick
+
+
+// save function for doubleClick event
+void OneButton::attachDoubleClick(callbackFunction newFunction)
+{
+	_doubleClickFunc = newFunction;
+} // attachDoubleClick
+
+
+// save function for press event
+// DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress,
+void OneButton::attachPress(callbackFunction newFunction)
+{
+	_pressFunc = newFunction;
+} // attachPress
+
+// save function for longPressStart event
+void OneButton::attachLongPressStart(callbackFunction newFunction)
+{
+	_longPressStartFunc = newFunction;
+} // attachLongPressStart
+
+// save function for longPressStop event
+void OneButton::attachLongPressStop(callbackFunction newFunction)
+{
+	_longPressStopFunc = newFunction;
+} // attachLongPressStop
+
+// save function for during longPress event
+void OneButton::attachDuringLongPress(callbackFunction newFunction)
+{
+	_duringLongPressFunc = newFunction;
+} // attachDuringLongPress
+
+// function to get the current long pressed state
+bool OneButton::isLongPressed()
+{
+	return _isLongPressed;
+}
+
+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.
+
+	// 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
+
+	} else if (_state == 1) { // waiting for menu pin being released.
+
+		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;
+
+		} else if (buttonLevel == _buttonReleased) {
+			_state = 2; // step to state 2
+
+		} 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
+
+		} else {
+			// wait. Stay in this state.
+		} // if
+
+	} 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.
+
+		} else if (buttonLevel == _buttonPressed) {
+			_state = 3; // step to state 3
+		} // if
+
+	} 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
+
+	} else if (_state == 6) { // waiting for menu pin being release after long press.
+		if (buttonLevel == _buttonReleased) {
+			_isLongPressed = false;  // Keep track of long press state
+			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()
+
+
+// end.
+
+