当前位置: 首页 > news >正文

esp32墨水屏天气预测学习

onebutton.cpp,onebutton.h代码学习:代码文件如下 :

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
// 07.05.2023 Debouncing in one point. #118
// -----#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 -----/** Create a OneButton instance.* use setup(...) to specify the hardware configuration. */OneButton();/*** Create a OneButton instance and setup.* @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.*/explicit OneButton(const int pin, const bool activeLow = true, const bool pullupActive = true);// ----- Set runtime parameters -----/*** Initialize or re-initialize the input pin. * @param pin The pin to be used for input from a momentary button.* @param mode Any of the modes also used in pinMode like INPUT or INPUT_PULLUP (default).* @param activeLow Set to true when the input level is LOW when the button is pressed, Default is true.*/void setup(const uint8_t pin, const uint8_t mode = INPUT_PULLUP, const bool activeLow = true);/*** set # millisec after safe click is assumed.*/[[deprecated("Use setDebounceMs() instead.")]]void setDebounceTicks(const unsigned int ms) {setDebounceMs(ms);};  // deprecatedvoid setDebounceMs(const int ms);/*** set # millisec after single click is assumed.*/[[deprecated("Use setClickMs() instead.")]]void setClickTicks(const unsigned int ms) {setClickMs(ms);};  // deprecatedvoid setClickMs(const unsigned int ms);/*** set # millisec after press is assumed.*/[[deprecated("Use setPressMs() instead.")]]void setPressTicks(const unsigned int ms) {setPressMs(ms);};  // deprecatedvoid setPressMs(const unsigned int ms);/*** set interval in msecs between calls of the DuringLongPress event.* 0 ms is the fastest events calls.*/void setLongPressIntervalMs(const unsigned int ms) {_long_press_interval_ms = ms;};/*** set # millisec after idle is assumed.*/void setIdleMs(const unsigned int ms);// ----- Attach events functions -----/*** Attach an event to be called immediately when a depress is detected.* @param newFunction This function will be called when the event has been detected.*/void attachPress(callbackFunction newFunction);void attachPress(parameterizedCallbackFunction newFunction, void *parameter);/*** 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.* The period of calls is set by setLongPressIntervalMs(ms).* @param newFunction*/void attachDuringLongPress(callbackFunction newFunction);void attachDuringLongPress(parameterizedCallbackFunction newFunction, void *parameter);/*** Attach an event when the button is in idle position.* @param newFunction*/void attachIdle(callbackFunction newFunction);// ----- 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.* Run the finite state machine (FSM) using the given level.*/void tick(bool activeLevel);/*** 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 = -1;                 // hardware pin number.int _debounce_ms = 50;         // number of msecs for debounce times.unsigned int _click_ms = 400;  // number of msecs before a click is detected.unsigned int _press_ms = 800;  // number of msecs before a long button press is detectedunsigned int _idle_ms = 1000;  // number of msecs before idle is detectedint _buttonPressed = 0;  // this is the level of the input pin when the button is pressed.// LOW if the button connects the input pin to GND when pressed.// HIGH if the button connects the input pin to VCC when pressed.// These variables will hold functions acting as event source.callbackFunction _pressFunc = NULL;parameterizedCallbackFunction _paramPressFunc = NULL;void *_pressFuncParam = NULL;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 = NULL;callbackFunction _duringLongPressFunc = NULL;parameterizedCallbackFunction _paramDuringLongPressFunc = NULL;void *_duringLongPressFuncParam = NULL;callbackFunction _idleFunc = 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 FiniteStateMachineenum stateMachine_t : int {OCS_INIT = 0,OCS_DOWN = 1,   // button is downOCS_UP = 2,     // button is upOCS_COUNT = 3,  // in multi press-mode, countingOCS_PRESS = 6,  // button is hold downOCS_PRESSEND = 7,};/*** Run the finite state machine (FSM) using the given level.*/void _fsm(bool activeLevel);/***  Advance to a new state.*/void _newState(stateMachine_t nextState);stateMachine_t _state = OCS_INIT;bool _idleState = false;bool debouncedLevel = false;bool _lastDebounceLevel = false;      // used for pin debouncingunsigned long _lastDebounceTime = 0;  // millis()unsigned long now = 0;                // millis()unsigned long _startTime = 0;  // start time of current activeLevel changeint _nClicks = 0;              // count the number of clicks with this variableint _maxClicks = 1;            // max number (1, 2, multi=3) of clicks of interest by registration of event functions.unsigned int _long_press_interval_ms = 0;    // interval in msecs between calls of the DuringLongPress eventunsigned long _lastDuringLongPressTime = 0;  // used to produce the DuringLongPress intervalpublic:int pin() const {return _pin;};stateMachine_t state() const {return _state;};bool debounce(const bool value);int debouncedValue() const {return debouncedLevel;};/*** @brief Use this function in the DuringLongPress and LongPressStop events to get the time since the button was pressed.* @return milliseconds from the start of the button press.*/unsigned long getPressedMs() {return (millis() - _startTime);};
};#endif

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.*                          Ihor Nehrutsa, Ihor.Nehrutsa@gmail.com** 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.
OneButton::OneButton(const int pin, const bool activeLow, const bool pullupActive) {setup(pin, pullupActive ? INPUT_PULLUP : INPUT, activeLow);
}  // OneButton// initialize or re-initialize the input pin
void OneButton::setup(const uint8_t pin, const uint8_t mode, const bool activeLow) {_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;}pinMode(pin, mode);
}// explicitly set the number of millisec that have to pass by before a click is assumed stable.
void OneButton::setDebounceMs(const int ms) {_debounce_ms = ms;
}  // setDebounceMs// explicitly set the number of millisec that have to pass by before a click is detected.
void OneButton::setClickMs(const unsigned int ms) {_click_ms = ms;
}  // setClickMs// explicitly set the number of millisec that have to pass by before a long button press is detected.
void OneButton::setPressMs(const unsigned int ms) {_press_ms = ms;
}  // setPressMs// explicitly set the number of millisec that have to pass by before button idle is detected.
void OneButton::setIdleMs(const unsigned int ms) {_idle_ms = ms;
}  // setIdleMs// save function for click event
void OneButton::attachPress(callbackFunction newFunction) {_pressFunc = newFunction;
}  // attachPress// save function for parameterized click event
void OneButton::attachPress(parameterizedCallbackFunction newFunction, void *parameter) {_paramPressFunc = newFunction;_pressFuncParam = parameter;
}  // attachPress// 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// save function for idle button event
void OneButton::attachIdle(callbackFunction newFunction) {_idleFunc = newFunction;
}  // attachIdlevoid OneButton::reset(void) {_state = OneButton::OCS_INIT;_nClicks = 0;_startTime = millis();_idleState = false;
}// ShaggyDog ---- return number of clicks in any case: single or multiple clicks
int OneButton::getNumberClicks(void) {return _nClicks;
}/*** @brief Debounce input pin level for use in SpesialInput.*/
bool OneButton::debounce(const bool value) {now = millis();  // current (relative) time in msecs.// Don't debounce going into active state, if _debounce_ms is negativeif (value && _debounce_ms < 0)debouncedLevel = value;if (_lastDebounceLevel == value) {if (now - _lastDebounceTime >= abs(_debounce_ms))debouncedLevel = value;} else {_lastDebounceTime = now;_lastDebounceLevel = value;}return debouncedLevel;
};/*** @brief Check input of the configured pin,* debounce button state and then* advance the finite state machine (FSM).*/
void OneButton::tick(void) {if (_pin >= 0) {_fsm(debounce(digitalRead(_pin) == _buttonPressed));}
}  // tick()void OneButton::tick(bool activeLevel) {_fsm(debounce(activeLevel));
}/***  @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) {_state = nextState;
}  // _newState()/*** @brief Run the finite state machine (FSM) using the given level.*/
void OneButton::_fsm(bool activeLevel) {unsigned long waitTime = (now - _startTime);// Implementation of the state machineswitch (_state) {case OneButton::OCS_INIT:// on idle for idle_ms call idle functionif (!_idleState and (waitTime > _idle_ms))if (_idleFunc) {_idleState = true;_idleFunc();}// waiting for level to become active.if (activeLevel) {_newState(OneButton::OCS_DOWN);_startTime = now;  // remember starting time_nClicks = 0;if (_pressFunc) _pressFunc();if (_paramPressFunc) _paramPressFunc(_pressFuncParam);}  // ifbreak;case OneButton::OCS_DOWN:// waiting for level to become inactive.if (!activeLevel) {_newState(OneButton::OCS_UP);_startTime = now;  // remember starting time} else if (waitTime > _press_ms) {if (_longPressStartFunc) _longPressStartFunc();if (_paramLongPressStartFunc) _paramLongPressStartFunc(_longPressStartFuncParam);_newState(OneButton::OCS_PRESS);}  // ifbreak;case OneButton::OCS_UP:// level is inactive// count as a short button down_nClicks++;_newState(OneButton::OCS_COUNT);break;case OneButton::OCS_COUNT:// dobounce time is over, count clicksif (activeLevel) {// button is down again_newState(OneButton::OCS_DOWN);_startTime = now;  // remember starting time} else if ((waitTime >= _click_ms) || (_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);}  // ifreset();}  // ifbreak;case OneButton::OCS_PRESS:// waiting for pin being release after long press.if (!activeLevel) {_newState(OneButton::OCS_PRESSEND);} else {// still the button is pressedif ((now - _lastDuringLongPressTime) >= _long_press_interval_ms) {if (_duringLongPressFunc) _duringLongPressFunc();if (_paramDuringLongPressFunc) _paramDuringLongPressFunc(_duringLongPressFuncParam);_lastDuringLongPressTime = now;}}  // ifbreak;case OneButton::OCS_PRESSEND:// button was released.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 库的实现,用于检测单个按钮的多种交互事件(如单击、双击、长按、多击等),适用于 Arduino 等嵌入式平台。其核心通过有限状态机(FSM) 和时间阈值判断,实现对按钮状态的精准跟踪和事件识别。以下是详细解释:

1. 核心功能与设计目标

该库的主要作用是简化按钮交互逻辑,无需手动处理防抖、事件区分(如单击 vs 双击)等复杂细节。支持的事件包括:

  • 单击(Click)
  • 双击(Double Click)
  • 多击(Multi Click,如 3 次点击)
  • 长按开始(Long Press Start)
  • 长按结束(Long Press Stop)
  • 长按过程中(During Long Press)
  • 按钮空闲(Idle,长时间未操作)

2. 类结构与核心成员变量

关键成员变量
  • 状态相关_state(当前状态机状态)、_nClicks(点击计数)、_startTime(事件起始时间戳)。
  • 时间阈值_debounce_ms(防抖时间)、_click_ms(点击间隔阈值)、_press_ms(长按判定时间)、_idle_ms(空闲判定时间)。
  • 回调函数:如 _clickFunc(单击回调)、_doubleClickFunc(双击回调)等,用于事件触发时执行用户自定义逻辑。
  • 引脚配置_pin(按钮连接的引脚)、_buttonPressed(按钮按下时的电平,LOW 或 HIGH)。

3. 初始化与配置方法

构造函数与 setup 方法
  • 构造函数支持两种初始化方式:默认构造(后续需调用 setup)或直接指定引脚、电平模式(activeLow)和上拉配置(pullupActive)。
  • setup 方法是核心初始化函数:
    • 配置引脚模式(INPUT 或 INPUT_PULLUP)。
    • 根据 activeLow 设定按钮按下时的电平(LOW 表示低电平有效,HIGH 表示高电平有效)。


LOW 表示低电平有效,HIGH 表示高电平有效)。这什么意思?

src/led.cpp在电子电路和嵌入式编程中,“LOW 表示低电平有效,HIGH 表示高电平有效” 是描述电路信号与功能逻辑对应关系的常用说法,具体含义如下:

1. 高低电平的物理含义

  • HIGH(高电平):通常指接近电源电压的电平(例如在 3.3V 系统中约为 3.3V,5V 系统中约为 5V)。
  • LOW(低电平):通常指接近 0V 的电平(例如 0~0.8V)。

2. “有效” 的含义

“有效” 在这里表示 “触发目标功能的状态”。例如:

  • 若某设备(如 LED、继电器)是 “低电平有效”,则当控制信号为LOW时,设备执行预期功能(如 LED 点亮、继电器吸合);
  • 若为 “高电平有效”,则当控制信号为HIGH时,设备执行预期功能。

3. 结合你的代码理解

在你提供的 src/led.cpp 中,LED 的控制逻辑就是 “低电平有效” 的典型例子:

cpp

运行

// 例如:
case 1:digitalWrite(PIN_LED, LOW); // On(低电平点亮LED)vTaskDelay(pdMS_TO_TICKS(1000));
break;
case 0:digitalWrite(PIN_LED, HIGH); // Off(高电平关闭LED)vTaskDelay(pdMS_TO_TICKS(1000));
break;
  • 当向 LED 引脚写入 LOW 时,LED 点亮(此时 LOW 是 “有效电平”,触发 “点亮” 功能);
  • 当写入 HIGH 时,LED 熄灭(此时 HIGH 是 “无效电平”,不触发点亮功能)。

这种逻辑由硬件电路设计决定(例如 LED 的驱动方式是 “灌电流” 还是 “拉电流”),代码中需根据硬件设计匹配对应的电平控制逻辑。在电子电路和嵌入式编程中,“LOW 表示低电平有效,HIGH 表示高电平有效” 是描述电路信号与功能逻辑对应关系的常用说法,具体含义如下:

1. 高低电平的物理含义

  • HIGH(高电平):通常指接近电源电压的电平(例如在 3.3V 系统中约为 3.3V,5V 系统中约为 5V)。
  • LOW(低电平):通常指接近 0V 的电平(例如 0~0.8V)。

2. “有效” 的含义

“有效” 在这里表示 “触发目标功能的状态”。例如:

  • 若某设备(如 LED、继电器)是 “低电平有效”,则当控制信号为LOW时,设备执行预期功能(如 LED 点亮、继电器吸合);
  • 若为 “高电平有效”,则当控制信号为HIGH时,设备执行预期功能。

3. 结合你的代码理解

在你提供的 src/led.cpp 中,LED 的控制逻辑就是 “低电平有效” 的典型例子:

cpp

运行

// 例如:
case 1:digitalWrite(PIN_LED, LOW); // On(低电平点亮LED)vTaskDelay(pdMS_TO_TICKS(1000));
break;
case 0:digitalWrite(PIN_LED, HIGH); // Off(高电平关闭LED)vTaskDelay(pdMS_TO_TICKS(1000));
break;
  • 当向 LED 引脚写入 LOW 时,LED 点亮(此时 LOW 是 “有效电平”,触发 “点亮” 功能);
  • 当写入 HIGH 时,LED 熄灭(此时 HIGH 是 “无效电平”,不触发点亮功能)。

这种逻辑由硬件电路设计决定(例如 LED 的驱动方式是 “灌电流” 还是 “拉电流”),代码中需根据硬件设计匹配对应的电平控制逻辑。



时间参数配置
  • setDebounceMs(ms):设置防抖时间(默认通常为 20ms),用于过滤机械抖动导致的电平波动。
  • setClickMs(ms):设置点击间隔阈值(默认约 200ms),用于区分单击和双击(两次点击间隔小于该值视为双击)。
  • setPressMs(ms):设置长按判定时间(默认约 500ms),按下持续时间超过该值视为长按。
  • setIdleMs(ms):设置空闲判定时间,按钮长时间未操作时触发空闲事件。

4. 事件回调注册

通过一系列 attachXXX 方法注册事件回调函数,支持两种回调类型:

  • 无参数回调(callbackFunction):如 attachClick(func),触发时直接调用 func()
  • 带参数回调(parameterizedCallbackFunction):如 attachClick(func, param),触发时调用 func(param),方便传递自定义参数。

支持的事件回调包括:

  • attachClick:单击事件。
  • attachDoubleClick:双击事件。
  • attachMultiClick:多击事件(3 次及以上点击)。
  • attachLongPressStart:长按开始事件(按下时间超过 _press_ms 时触发)。
  • attachLongPressStop:长按结束事件(长按后释放时触发)。
  • attachDuringLongPress:长按过程中持续触发的事件(默认每 100ms 一次)。
  • attachIdle:按钮空闲事件(超过 _idle_ms 未操作时触发)。

5. 核心逻辑:有限状态机(FSM)

状态机是该库的核心,通过 _fsm 方法实现,用于跟踪按钮状态并触发相应事件。主要状态包括:

状态说明
OCS_INIT初始状态(空闲),等待按钮被按下。
OCS_DOWN按钮已按下,等待释放或判定为长按。
OCS_UP按钮已释放,开始计数点击次数。
OCS_COUNT计数状态,判断点击次数(单击 / 双击 / 多击),等待下一次点击或超时。
OCS_PRESS长按状态,按钮持续按下,触发 “长按过程中” 事件。
OCS_PRESSEND长按结束状态,按钮释放,触发 “长按结束” 事件。


有限状态机是什么意思

有限状态机(Finite State Machine,简称 FSM)是一种数学模型,用于描述一个系统在有限个 “状态” 之间,根据输入(或事件)进行规则化转移的行为。它的核心思想是:系统在某一时刻只能处于一种 “状态”,当接收到特定输入(或事件)时,会按照预设规则切换到另一种状态,并可能执行相应的动作

核心组成部分

  1. 状态(State):系统可能处于的有限个离散状态(例如 “开启”“关闭”“待机”“错误” 等)。
  2. 事件(Event/Input):触发状态转移的外部或内部信号(例如 “按钮按下”“超时”“数据接收完成” 等)。
  3. 转移(Transition):定义在特定状态下,收到某事件后切换到新状态的规则(例如 “在‘关闭’状态下,收到‘开机信号’则转移到‘开启’状态”)。
  4. 动作(Action):状态转移时或处于某状态时执行的操作(例如 “进入‘开启’状态时启动电机”“在‘错误’状态时报警”)。

特点

  • 有限性:状态数量是有限的(区别于无限状态机)。
  • 确定性:在某一状态下,给定相同的事件,转移到的下一个状态是确定的(也有非确定性 FSM,但实际应用中多为确定性)。

应用场景

有限状态机在编程、电子电路、控制系统等领域广泛应用,例如:

  • 交通信号灯:状态为 “红灯”“黄灯”“绿灯”,事件为 “定时结束”,转移规则为 “红灯→绿灯→黄灯→红灯” 循环。
  • 电梯控制:状态包括 “上升中”“下降中”“停止”,事件为 “楼层按钮按下”,转移规则根据当前位置和目标楼层确定。
  • 通信协议:例如 TCP 协议的 “建立连接”“数据传输”“断开连接” 等状态切换。
  • 嵌入式设备逻辑:如按钮长按 / 短按的判断(状态:“未按下”“短按中”“长按中”,事件:“按键按下”“超时”)。

优势

  • 简化复杂逻辑:将系统行为分解为清晰的状态和转移规则,避免嵌套条件判断(如多层if-elseswitch-case)。
  • 提高可读性:状态和规则直观,便于理解和维护。
  • 可验证性:有限状态可穷举,便于测试和调试。

例如,在代码中可以用enum定义状态,用switch-case或状态转移表实现状态逻辑,如下简单示例(伪代码):

// 定义状态
enum State {OFF,   // 关闭ON,    // 开启ERROR  // 错误
};// 当前状态
State currentState = OFF;// 处理事件并转移状态
void handleEvent(Event event) {switch (currentState) {case OFF:if (event == POWER_ON) {currentState = ON;  // 转移到开启状态startDevice();      // 执行动作}break;case ON:if (event == POWER_OFF) {currentState = OFF;  // 转移到关闭状态stopDevice();        // 执行动作} else if (event == OVERHEAT) {currentState = ERROR; // 转移到错误状态triggerAlarm();       // 执行动作}break;// ... 其他状态处理}
}


状态转换流程(简化):
  1. 初始状态(OCS_INIT

    • 若按钮被按下(电平符合 _buttonPressed),进入 OCS_DOWN 状态,记录开始时间,重置点击计数。
    • 若长时间未操作(超过 _idle_ms),触发 idle 事件。
  2. 按下状态(OCS_DOWN

    • 若按钮释放,进入 OCS_UP 状态,记录释放时间。
    • 若按下时间超过 _press_ms,触发 “长按开始” 事件,进入 OCS_PRESS 状态。
  3. 释放状态(OCS_UP

    • 点击计数 _nClicks 加 1,进入 OCS_COUNT 状态。
  4. 计数状态(OCS_COUNT

    • 若在 _click_ms 内再次按下按钮,回到 OCS_DOWN 状态(继续计数)。
    • 若超时(超过 _click_ms)或达到最大点击数:
      • 1 次点击 → 触发 click 事件。
      • 2 次点击 → 触发 doubleClick 事件。
      • 3 次及以上 → 触发 multiClick 事件。
      • 重置状态机至 OCS_INIT
  5. 长按状态(OCS_PRESS

    • 若按钮释放,进入 OCS_PRESSEND 状态,触发 “长按结束” 事件。
    • 持续按下时,每隔 _long_press_interval_ms(默认 100ms)触发 “长按过程中” 事件。
  6. 长按结束状态(OCS_PRESSEND

    • 触发 “长按结束” 事件后,重置状态机至 OCS_INIT

6. 防抖处理(debounce 方法)

按钮机械结构会导致电平在按下 / 释放时产生抖动(短时间内多次跳变),debounce 方法通过以下逻辑过滤抖动:

  • 记录上次电平变化时间(_lastDebounceTime)。
  • 若当前电平与上次一致,且持续时间超过 _debounce_ms,则认为电平稳定,更新有效电平(debouncedLevel)。
  • 若电平变化,则重置计时,等待稳定。

7. 核心驱动方法(tick 方法)

tick 是状态机的 “心脏”,需要在主循环(loop)中频繁调用(如每 10ms 一次),功能包括:

  • 读取按钮当前电平(或接受外部传入的电平)。
  • 调用 debounce 方法获取稳定电平。
  • 调用 _fsm 方法驱动状态机更新,实现事件检测。

总结

OneButton 库通过有限状态机时间阈值,优雅地解决了按钮交互中的防抖、事件区分(单击 / 双击 / 长按等)问题。用户只需注册回调函数并在主循环中调用 tick 方法,即可轻松处理复杂的按钮交互,无需关心底层状态逻辑。

该库广泛应用于需要按钮输入的嵌入式项目(如智能家居控制面板、手持设备等),简化了代码复杂度,提高了交互可靠性。

下面是详细分析:

1.OneButton::OneButton() {
_pin = -1;
// further initialization has moved to OneButton.h
}

src/main.cppsrc/main.cpp这段代码是OneButton类的默认构造函数,用于初始化OneButton类的对象,具体解析如下:

1. 语法解析

  • OneButton::OneButton():表示这是OneButton类的默认构造函数(无参数构造函数)。::是作用域解析符,用于指明该函数属于OneButton类。
  • 函数体内部:_pin = -1; 表示将类的成员变量_pin初始化为-1
  • 注释 // further initialization has moved to OneButton.h 说明:原本可能在构造函数中进行的其他初始化操作,现在已转移到OneButton.h头文件中(可能使用 C++ 的类内成员初始化语法)。

2. 成员变量_pin的含义

结合代码库上下文(如src/main.cpp中使用OneButton处理按键),_pinOneButton类中用于存储按键连接的 GPIO 引脚编号的成员变量。

  • 初始化值-1通常表示 “未指定引脚” 或 “未初始化状态”(因为 GPIO 引脚编号一般为非负整数,如GPIO_NUM_14)。
  • 后续会通过其他方法(如src/main.cpp中的button.setup(PIN_BUTTON, INPUT_PULLUP, true);)为_pin设置实际的引脚值。

3. 初始化逻辑的迁移

注释表明 “进一步的初始化已移至OneButton.h”,这通常是因为在 C++11 及以上标准中,支持类内成员初始化(在类定义中直接初始化成员变量),例如在OneButton.h中可能有类似代码:

class OneButton {
private:int _pin = -1; // 类内初始化,替代构造函数中的部分初始化逻辑// 其他成员变量及声明...
public:OneButton(); // 构造函数声明// 其他方法...
};

这种方式可以简化构造函数的实现,将基础初始化逻辑集中在类定义中。

总结

该构造函数的核心作用是初始化OneButton对象的引脚状态为 “未指定”(_pin = -1),并通过注释说明其他初始化逻辑的位置,为后续的按键引脚配置(如setup方法)提供基础状态。


2.

// Initialize the OneButton library.

OneButton::OneButton(const int pin, const bool activeLow, const bool pullupActive) {

  setup(pin, pullupActive ? INPUT_PULLUP : INPUT, activeLow);

}  // OneButton

这段代码是OneButton类的带参数构造函数,用于初始化按键的硬件配置(引脚、输入模式、有效电平),具体解析如下:

1. 函数声明解析

  • OneButton::OneButton(...):表示这是OneButton类的构造函数,用于创建OneButton对象时初始化。
  • 参数列表:
    • const int pin:按键连接的 GPIO 引脚编号(例如之前代码中的PIN_BUTTON = GPIO_NUM_14)。
    • const bool activeLow:指定按键的有效电平(true表示低电平有效,false表示高电平有效)。
    • const bool pullupActive:是否启用引脚的内部上拉电阻(true启用,false不启用)。

2. 函数体逻辑

  • 核心操作:调用setup方法完成初始化,传递三个参数:
    1. pin:直接传入按键引脚号。
    2. pullupActive ? INPUT_PULLUP : INPUT:根据pullupActive决定引脚的输入模式:
      • pullupActive = true:引脚模式设为INPUT_PULLUP(启用内部上拉电阻,此时按键未按下时引脚为高电平)。
      • pullupActive = false:引脚模式设为INPUT(普通输入模式,需外部接上下拉电阻)。
    3. activeLow:传入有效电平参数,用于后续判断按键状态(按下时的电平是否为有效信号)。

3. 作用与意义

  • 该构造函数的核心是将按键的硬件配置参数传递给setup方法,由setup方法完成具体的引脚初始化(如pinMode配置)和状态变量设置。
  • 结合OneButton库的功能(检测单击、双击、长按等事件),这里的初始化是后续按键事件检测的基础 —— 只有正确配置引脚模式和有效电平,才能准确判断按键的按下 / 松开状态。

示例场景

例如在src/main.cpp中初始化按键时:

button.setup(PIN_BUTTON, INPUT_PULLUP, true);

若使用该带参构造函数,可直接在创建对象时完成配置:

OneButton button(PIN_BUTTON, true, true); // 等价于上面的setup调用

其中:

  • PIN_BUTTON指定引脚,
  • true表示低电平有效(按键按下时引脚为低电平),
  • true表示启用内部上拉电阻。

综上,该构造函数是OneButton类初始化的入口之一,通过封装硬件配置参数,简化了按键的初始化流程。

http://www.dtcms.com/a/393986.html

相关文章:

  • LabelImg 操作指南:提高标注速度
  • redhat7.2迁移ssh免密到麒麟v10
  • Linux基操
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘protobuf’ 问题
  • EXCEL中公式和文字混合和数字自动变成大写金额
  • Linux软件安装与项目部署
  • Config-配置中心2.0
  • Meta 开源 MobileLLM-R1 系列小参数高效模型,颠覆大模型竞赛
  • 【论文阅读】One-Minute Video Generation with Test-Time Training
  • 玄鸟12600M矿机ETC/ETHW挖矿性能解析与技术参数分析
  • Rust_2025:阶段1:day7.1 类型转换
  • Composer在PHP项目中的手动类自动加载策略
  • kubeasz二进制部署k8s生产环境集群
  • 浏览器缓存
  • 【PyTorch】梯度检查点 checkpoint 实现源码剖析
  • 学习嵌入式的第三十九天——ARM——汇编
  • 解决AI摘要不显示的三种方案 -AIsummary插件
  • 企业网盘,基于 .NET 技术开发,用于构建安全高效的文件云存储和云管理平台。
  • AFNetWorking
  • vscode连接ubuntu18报Gilbc2.28错
  • 华为超节点 384 集群: AI 算力的架构革新与实践
  • mescroll-uni 完全指南——Vue3 setup格式
  • 动态规划算法的欢乐密码(六):子数组系列(下)
  • StringBuilder与StringBuffer区别详解
  • 深入浅出 Scikit-learn:从入门到实战的机器学习工具包指南
  • 乡村社区服务管理系统的设计与实现-(源码+LW+可部署)
  • Spring Framework
  • 01 定位器项目笔记——知识复习回顾
  • 《Python实现图像剪辑:从基础裁剪到高级滤镜处理》
  • 【图像处理基石】工业检测中使用的图像处理算法有哪些?