/** * @file button_manager.h * @brief 三按钮管理器 - 双向去抖 + 长按/短按识别 + 超时自愈 * * 按钮1 (GPIO14): 长按1.5秒 → 配网 * 按钮2 (GPIO13): 短按 → 解除报警 * 按钮3 (GPIO46): 短按 → 翻页 * * 去抖策略: 状态变化需持续稳定 BTN_DEBOUNCE_MS 才确认 * 自愈策略: 按钮按下超过 10 秒强制复位,防止卡死 */ #ifndef BUTTON_MANAGER_H #define BUTTON_MANAGER_H #include #include "config.h" #define BTN_STUCK_TIMEOUT_MS 10000 // 按钮卡死超时 (10秒强制复位) typedef void (*ButtonCallback)(void); class ButtonManager { public: ButtonManager(); /** 初始化三个按钮引脚 */ void begin(); /** 主循环轮询 (每 10ms 调用) */ void loop(); /** 注册回调 */ void onProvisionLongPress(ButtonCallback cb) { _cbProvision = cb; } void onAlarmDismiss(ButtonCallback cb) { _cbDismiss = cb; } void onPageSwitch(ButtonCallback cb) { _cbPage = cb; } private: /** * 按钮状态机 (基于稳定读数而非边沿) * * 状态转换: * IDLE ──[raw稳定LOW×BTN_DEBOUNCE_MS]──→ PRESSED (记录pressTime) * PRESSED ──[hold≥BTN_LONG_PRESS_MS]──→ 触发长按回调 (仅限hasLong) * PRESSED ──[raw稳定HIGH×BTN_DEBOUNCE_MS]──→ 检查hold时长触发短按 → IDLE * PRESSED ──[hold≥BTN_STUCK_TIMEOUT_MS]──→ 强制复位 → IDLE (防卡死) */ struct ButtonState { uint8_t pin; bool stableState; // 当前确认的稳定状态 (true=按下) bool rawState; // 上一次 raw 读值 uint32_t changeTime; // raw 状态变化时刻 uint32_t pressTime; // 稳定按下时刻 (ms) bool longTriggered; // 长按已触发 bool shortPending; // 等待释放以判定短按 }; /** 处理单个按钮 (基于稳定状态而非瞬时边沿) */ void _processButton(ButtonState& btn, bool hasShort, bool hasLong); bool _readPin(uint8_t pin); /** 强制复位单个按钮 */ void _resetButton(ButtonState& btn); ButtonState _btnProvision; ButtonState _btnDismiss; ButtonState _btnPage; ButtonCallback _cbProvision; ButtonCallback _cbDismiss; ButtonCallback _cbPage; }; #endif // BUTTON_MANAGER_H