一、安装第三方库--OneButton
今天分享一个超级有意思的库--OneButton。
首先,我们来安装下它。
方法一:
1、打开arduino,选择项目--加载库--管理库。
会弹出一个库管理器,在搜索栏输入OneButton。会自动搜到库,然后点击more info,选择合适的版本安装它。
方法二:
如果你的网络不是很好,可能下载不了,去github搜索它,如图。
1、github上下载库
下载压缩包。
放在arduino软件下面。
找到arduino的快捷方式,找到软件所在的位置。
打开如图,点击libraries文件夹,把我们从github下载的文件放到这里面。
然后重启arduino软件。
这种库安装方式优点:快,网络卡也可以这样安装;缺点:大家可以看下库安装位置是C盘,安装库较多可能电脑会卡。
二、使用OneButton库
直接代开示例demo进行修改,点开文件--示例--OneButton--SimpleOneButton。
点开这个例子,修改如下:
#include "OneButton.h"
//定义按键和灯引脚
#define PIN_INPUT 0
#define PIN_LED 2
OneButton button(PIN_INPUT, true);
//LED初始状态
int ledState = HIGH;
void setup()
{
Serial.begin(115200);
Serial.println("One Button Example with polling.");
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, ledState);
button.attachDoubleClick(doubleClick);
}
// main code here, to run repeatedly:
void loop()
{
// keep watching the push button:
button.tick();
// You can implement other code in here or just wait a while
delay(10);
} // loop
// 短时间内连按两下
void doubleClick()
{
Serial.println("x2");
ledState = !ledState; // reverse the LED
digitalWrite(PIN_LED, ledState);
}
注意:示例中的灯和按键的引脚是esp8266的,我们这里用到的是esp32,需要修改。
可以上传代码测试下。
OneButton库简单的地方是它把按键的状态已经封装好了,不需要自己去设置。
代码测试下按键状态--长按短按检测
#include "OneButton.h"
#define PIN_INPUT 0
#define PIN_LED 2
// Setup a new OneButton on pin PIN_INPUT
// The 2. parameter activeLOW is true, because external wiring sets the button to LOW when pressed.
OneButton button(PIN_INPUT, true);
// current LED state, staring with LOW (0)
int ledState = LOW;
// save the millis when a press has started.
unsigned long pressStartTime;
void checkTicks()
{
// include all buttons here to be checked
button.tick(); // just call tick() to check the state.
}
// this function will be called when the button was pressed 1 time only.
void singleClick()
{
Serial.println("singleClick() detected.");
} // singleClick
// this function will be called when the button was pressed 2 times in a short timeframe.
void doubleClick()
{
Serial.println("doubleClick() detected.");
ledState = !ledState; // reverse the LED
digitalWrite(PIN_LED, ledState);
} // doubleClick
// this function will be called when the button was pressed multiple times in a short timeframe.
void multiClick()
{
Serial.print("multiClick(");
Serial.print(button.getNumberClicks());
Serial.println(") detected.");
ledState = !ledState; // reverse the LED
digitalWrite(PIN_LED, ledState);
} // multiClick
// this function will be called when the button was held down for 1 second or more.
void pressStart()
{
Serial.println("pressStart()");
pressStartTime = millis() - 1000; // as set in setPressTicks()
} // pressStart()
// this function will be called when the button was released after a long hold.
void pressStop()
{
Serial.print("pressStop(");
Serial.print(millis() - pressStartTime);
Serial.println(") detected.");
} // pressStop()
// setup code here, to run once:
void setup()
{
Serial.begin(115200);
Serial.println("One Button Example with interrupts.");
// enable the led output.
pinMode(PIN_LED, OUTPUT); // sets the digital pin as output
digitalWrite(PIN_LED, ledState);
// setup interrupt routine
// when not registering to the interrupt the sketch also works when the tick is called frequently.
attachInterrupt(digitalPinToInterrupt(PIN_INPUT), checkTicks, CHANGE);
// link the xxxclick functions to be called on xxxclick event.
button.attachClick(singleClick);
button.attachDoubleClick(doubleClick);
button.attachMultiClick(multiClick);
button.setPressTicks(1000); // that is the time when LongPressStart is called
button.attachLongPressStart(pressStart);
button.attachLongPressStop(pressStop);
} // setup
// main code here, to run repeatedly:
void loop()
{
// keep watching the push button, even when no interrupt happens:
button.tick();
// You can implement other code in here or just wait a while
delay(10);
} // loop
有兴趣的小伙伴可以打开文件件看一下这些函数是怎么写的。
OneButton.cpp
/**
* @file OneButton.cpp
*
* @brief Library for detecting button clicks, doubleclicks and long press
* pattern on a single button.
*
* @author Matthias Hertel, https://www.mathertel.de
* @Copyright Copyright (c) by Matthias Hertel, https://www.mathertel.de.
*
* This work is licensed under a BSD style license. See
* http://www.mathertel.de/License.aspx
*
* More information on: https://www.mathertel.de/Arduino/OneButtonLibrary.aspx
*
* Changelog: see OneButton.h
*/
#include "OneButton.h"
// ----- Initialization and Default Values -----
/**
* @brief Construct a new OneButton object but not (yet) initialize the IO pin.
*/
OneButton::OneButton()
{
_pin = -1;
// further initialization has moved to OneButton.h
}
/**
* Initialize the OneButton library.
* @param pin The pin to be used for input from a momentary button.
* @param activeLow Set to true when the input level is LOW when the button is pressed, Default is true.
* @param pullupActive Activate the internal pullup when available. Default is true.
*/
OneButton::OneButton(const int pin, const boolean activeLow, const bool pullupActive)
{
// OneButton();
_pin = pin;
if (activeLow) {
// the button connects the input pin to GND when pressed.
_buttonPressed = LOW;
} else {
// the button connects the input pin to VCC when pressed.
_buttonPressed = HIGH;
} // if
if (pullupActive) {
// use the given pin as input and activate internal PULLUP resistor.
pinMode(pin, INPUT_PULLUP);
} else {
// use the given pin as input
pinMode(pin, INPUT);
} // if
} // OneButton
// explicitly set the number of millisec that have to pass by before a click is assumed stable.
void OneButton::setDebounceTicks(const int ticks)
{
_debounceTicks = ticks;
} // setDebounceTicks
// explicitly set the number of millisec that have to pass by before a click is detected.
void OneButton::setClickTicks(const 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(const int ticks)
{
_pressTicks = ticks;
} // setPressTicks
// save function for click event
void OneButton::attachClick(callbackFunction newFunction)
{
_clickFunc = newFunction;
} // attachClick
// save function for parameterized click event
void OneButton::attachClick(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramClickFunc = newFunction;
_clickFuncParam = parameter;
} // attachClick
// save function for doubleClick event
void OneButton::attachDoubleClick(callbackFunction newFunction)
{
_doubleClickFunc = newFunction;
_maxClicks = max(_maxClicks, 2);
} // attachDoubleClick
// save function for parameterized doubleClick event
void OneButton::attachDoubleClick(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramDoubleClickFunc = newFunction;
_doubleClickFuncParam = parameter;
_maxClicks = max(_maxClicks, 2);
} // attachDoubleClick
// save function for multiClick event
void OneButton::attachMultiClick(callbackFunction newFunction)
{
_multiClickFunc = newFunction;
_maxClicks = max(_maxClicks, 100);
} // attachMultiClick
// save function for parameterized MultiClick event
void OneButton::attachMultiClick(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramMultiClickFunc = newFunction;
_multiClickFuncParam = parameter;
_maxClicks = max(_maxClicks, 100);
} // attachMultiClick
// save function for longPressStart event
void OneButton::attachLongPressStart(callbackFunction newFunction)
{
_longPressStartFunc = newFunction;
} // attachLongPressStart
// save function for parameterized longPressStart event
void OneButton::attachLongPressStart(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramLongPressStartFunc = newFunction;
_longPressStartFuncParam = parameter;
} // attachLongPressStart
// save function for longPressStop event
void OneButton::attachLongPressStop(callbackFunction newFunction)
{
_longPressStopFunc = newFunction;
} // attachLongPressStop
// save function for parameterized longPressStop event
void OneButton::attachLongPressStop(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramLongPressStopFunc = newFunction;
_longPressStopFuncParam = parameter;
} // attachLongPressStop
// save function for during longPress event
void OneButton::attachDuringLongPress(callbackFunction newFunction)
{
_duringLongPressFunc = newFunction;
} // attachDuringLongPress
// save function for parameterized during longPress event
void OneButton::attachDuringLongPress(parameterizedCallbackFunction newFunction, void *parameter)
{
_paramDuringLongPressFunc = newFunction;
_duringLongPressFuncParam = parameter;
} // attachDuringLongPress
void OneButton::reset(void)
{
_state = OneButton::OCS_INIT;
_lastState = OneButton::OCS_INIT;
_nClicks = 0;
_startTime = 0;
}
// ShaggyDog ---- return number of clicks in any case: single or multiple clicks
int OneButton::getNumberClicks(void)
{
return _nClicks;
}
/**
* @brief Check input of the configured pin and then advance the finite state
* machine (FSM).
*/
void OneButton::tick(void)
{
if (_pin >= 0) {
tick(digitalRead(_pin) == _buttonPressed);
}
}
/**
* @brief Advance to a new state and save the last one to come back in cas of bouncing detection.
*/
void OneButton::_newState(stateMachine_t nextState)
{
_lastState = _state;
_state = nextState;
} // _newState()
/**
* @brief Run the finite state machine (FSM) using the given level.
*/
void OneButton::tick(bool activeLevel)
{
unsigned long now = millis(); // current (relative) time in msecs.
unsigned long waitTime = (now - _startTime);
// Implementation of the state machine
switch (_state) {
case OneButton::OCS_INIT:
// waiting for level to become active.
if (activeLevel) {
_newState(OneButton::OCS_DOWN);
_startTime = now; // remember starting time
_nClicks = 0;
} // if
break;
case OneButton::OCS_DOWN:
// waiting for level to become inactive.
if ((!activeLevel) && (waitTime < _debounceTicks)) {
// button was released to quickly so I assume some bouncing.
_newState(_lastState);
} else if (!activeLevel) {
_newState(OneButton::OCS_UP);
_startTime = now; // remember starting time
} else if ((activeLevel) && (waitTime > _pressTicks)) {
if (_longPressStartFunc) _longPressStartFunc();
if (_paramLongPressStartFunc) _paramLongPressStartFunc(_longPressStartFuncParam);
_newState(OneButton::OCS_PRESS);
} // if
break;
case OneButton::OCS_UP:
// level is inactive
if ((activeLevel) && (waitTime < _debounceTicks)) {
// button was pressed to quickly so I assume some bouncing.
_newState(_lastState); // go back
} else if (waitTime >= _debounceTicks) {
// count as a short button down
_nClicks++;
_newState(OneButton::OCS_COUNT);
} // if
break;
case OneButton::OCS_COUNT:
// dobounce time is over, count clicks
if (activeLevel) {
// button is down again
_newState(OneButton::OCS_DOWN);
_startTime = now; // remember starting time
} else if ((waitTime > _clickTicks) || (_nClicks == _maxClicks)) {
// now we know how many clicks have been made.
if (_nClicks == 1) {
// this was 1 click only.
if (_clickFunc) _clickFunc();
if (_paramClickFunc) _paramClickFunc(_clickFuncParam);
} else if (_nClicks == 2) {
// this was a 2 click sequence.
if (_doubleClickFunc) _doubleClickFunc();
if (_paramDoubleClickFunc) _paramDoubleClickFunc(_doubleClickFuncParam);
} else {
// this was a multi click sequence.
if (_multiClickFunc) _multiClickFunc();
if (_paramMultiClickFunc) _paramMultiClickFunc(_multiClickFuncParam);
} // if
reset();
} // if
break;
case OneButton::OCS_PRESS:
// waiting for menu pin being release after long press.
if (!activeLevel) {
_newState(OneButton::OCS_PRESSEND);
_startTime = now;
} else {
// still the button is pressed
if (_duringLongPressFunc) _duringLongPressFunc();
if (_paramDuringLongPressFunc) _paramDuringLongPressFunc(_duringLongPressFuncParam);
} // if
break;
case OneButton::OCS_PRESSEND:
// button was released.
if ((activeLevel) && (waitTime < _debounceTicks)) {
// button was released to quickly so I assume some bouncing.
_newState(_lastState); // go back
} else if (waitTime >= _debounceTicks) {
if (_longPressStopFunc) _longPressStopFunc();
if (_paramLongPressStopFunc) _paramLongPressStopFunc(_longPressStopFuncParam);
reset();
}
break;
default:
// unknown state detected -> reset state machine
_newState(OneButton::OCS_INIT);
break;
} // if
} // OneButton.tick()
// end.
OneButton.h
// -----
// 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. 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
// -----
// 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.
// 14.05.2017 Debouncing improvements.
// 25.06.2018 Optional third parameter for deactivating pullup.
// 26.09.2018 Anatoli Arkhipenko: Included solution to use library with other
// sources of input.
// 26.09.2018 Initialization moved into class declaration.
// 26.09.2018 Jay M Ericsson: compiler warnings removed.
// 29.01.2020 improvements from ShaggyDog18
// -----
#ifndef OneButton_h
#define OneButton_h
#include "Arduino.h"
// ----- Callback function types -----
extern "C" {
typedef void (*callbackFunction)(void);
typedef void (*parameterizedCallbackFunction)(void *);
}
class OneButton
{
public:
// ----- Constructor -----
OneButton();
/**
* Initialize the OneButton library.
* @param pin The pin to be used for input from a momentary button.
* @param activeLow Set to true when the input level is LOW when the button is pressed, Default is true.
* @param pullupActive Activate the internal pullup when available. Default is true.
*/
OneButton(const int pin, const boolean activeLow = true, const bool pullupActive = true);
// ----- Set runtime parameters -----
/**
* set # millisec after safe click is assumed.
*/
void setDebounceTicks(const int ticks);
/**
* set # millisec after single click is assumed.
*/
void setClickTicks(const int ticks);
/**
* set # millisec after press is assumed.
*/
void setPressTicks(const int ticks);
/**
* Attach an event to be called when a single click is detected.
* @param newFunction This function will be called when the event has been detected.
*/
void attachClick(callbackFunction newFunction);
void attachClick(parameterizedCallbackFunction newFunction, void *parameter);
/**
* Attach an event to be called after a double click is detected.
* @param newFunction This function will be called when the event has been detected.
*/
void attachDoubleClick(callbackFunction newFunction);
void attachDoubleClick(parameterizedCallbackFunction newFunction, void *parameter);
/**
* Attach an event to be called after a multi click is detected.
* @param newFunction This function will be called when the event has been detected.
*/
void attachMultiClick(callbackFunction newFunction);
void attachMultiClick(parameterizedCallbackFunction newFunction, void *parameter);
/**
* Attach an event to fire when the button is pressed and held down.
* @param newFunction
*/
void attachLongPressStart(callbackFunction newFunction);
void attachLongPressStart(parameterizedCallbackFunction newFunction, void *parameter);
/**
* Attach an event to fire as soon as the button is released after a long press.
* @param newFunction
*/
void attachLongPressStop(callbackFunction newFunction);
void attachLongPressStop(parameterizedCallbackFunction newFunction, void *parameter);
/**
* Attach an event to fire periodically while the button is held down.
* @param newFunction
*/
void attachDuringLongPress(callbackFunction newFunction);
void attachDuringLongPress(parameterizedCallbackFunction newFunction, void *parameter);
// ----- State machine functions -----
/**
* @brief Call this function every some milliseconds for checking the input
* level at the initialized digital pin.
*/
void tick(void);
/**
* @brief Call this function every time the input level has changed.
* Using this function no digital input pin is checked because the current
* level is given by the parameter.
*/
void tick(bool level);
/**
* Reset the button state machine.
*/
void reset(void);
/*
* return number of clicks in any case: single or multiple clicks
*/
int getNumberClicks(void);
/**
* @return true if we are currently handling button press flow
* (This allows power sensitive applications to know when it is safe to power down the main CPU)
*/
bool isIdle() const { return _state == OCS_INIT; }
/**
* @return true when a long press is detected
*/
bool isLongPressed() const { return _state == OCS_PRESS; };
private:
int _pin; // hardware pin number.
unsigned int _debounceTicks = 50; // number of ticks for debounce times.
unsigned int _clickTicks = 400; // number of msecs before a click is detected.
unsigned int _pressTicks = 800; // number of msecs before a long button press is detected
int _buttonPressed;
// These variables will hold functions acting as event source.
callbackFunction _clickFunc = NULL;
parameterizedCallbackFunction _paramClickFunc = NULL;
void *_clickFuncParam = NULL;
callbackFunction _doubleClickFunc = NULL;
parameterizedCallbackFunction _paramDoubleClickFunc = NULL;
void *_doubleClickFuncParam = NULL;
callbackFunction _multiClickFunc = NULL;
parameterizedCallbackFunction _paramMultiClickFunc = NULL;
void *_multiClickFuncParam = NULL;
callbackFunction _longPressStartFunc = NULL;
parameterizedCallbackFunction _paramLongPressStartFunc = NULL;
void *_longPressStartFuncParam = NULL;
callbackFunction _longPressStopFunc = NULL;
parameterizedCallbackFunction _paramLongPressStopFunc = NULL;
void *_longPressStopFuncParam;
callbackFunction _duringLongPressFunc = NULL;
parameterizedCallbackFunction _paramDuringLongPressFunc = NULL;
void *_duringLongPressFuncParam = NULL;
// 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.
// define FiniteStateMachine
enum stateMachine_t : int {
OCS_INIT = 0,
OCS_DOWN = 1,
OCS_UP = 2,
OCS_COUNT = 3,
OCS_PRESS = 6,
OCS_PRESSEND = 7,
UNKNOWN = 99
};
/**
* Advance to a new state and save the last one to come back in cas of bouncing detection.
*/
void _newState(stateMachine_t nextState);
stateMachine_t _state = OCS_INIT;
stateMachine_t _lastState = OCS_INIT; // used for debouncing
unsigned long _startTime; // start of current input change to checking debouncing
int _nClicks; // count the number of clicks with this variable
int _maxClicks = 1; // max number (1, 2, multi=3) of clicks of interest by registration of event functions.
};
#endif