先贴出安装状态枚举类型:
/* 定义按键的状态枚举类型 */
enum button_state {
BUTTON_STATE_IDLE = 0, /* 空闲状态 */
BUTTON_STATE_PRESS_DEBOUNCE, /* 按下消抖状态 */
BUTTON_STATE_PRESSED, /* 成功按下状态 */
BUTTON_STATE_LONG_PRESS_ONCE, /* 长按状态,单次触发 */
BUTTON_STATE_LONG_PRESS_CONTINUOUS, /* 长按状态,连续触发 */
BUTTON_STATE_RELEASE_DEBOUNCE /* 释放消抖状态 */
};
一、 状态切换流程图 (Mermaid 文本渲染)
如果你使用的 Markdown 编辑器(如 Notion、Obsidian、Typora 等)支持 Mermaid,可以直接复制以下代码生成图表;这里也直接为你呈现其逻辑拓扑:
graph TD START([系统初始化]) --> IDLE[BUTTON_STATE_IDLE] IDLE -- "1.a 检测到物理按下(引脚变低电平)" --> PRESS_DEB[BUTTON_STATE_PRESS_DEBOUNCE] PRESS_DEB -- "2a.抖动杂讯(电平恢复高电平)" --> IDLE PRESS_DEB -- "2b.消抖20ms到&&依旧低电平" --> PRESSED[BUTTON_STATE_PRESSED] PRESSED -- "3a.物理松开,触发【单击事件】" --> REL_DEB[BUTTON_STATE_RELEASE_DEBOUNCE] PRESSED -- "3b.按下时长>1s长按阈值" --> LONG1[BUTTON_STATE_LONG_PRESS_ONCE] LONG1 -- "4a.物理松开,触发【长按释放】" --> REL_DEB LONG1 -- "4b.按下>200ms连发间隔" --> LONG_CONT["BUTTON_STATE_LONG_PRESS_CONTINUOUS<br/>5a:每200ms触发连发事件"] %% 自环只写短标签 LONG_CONT -- "5a.保持按下" --> LONG_CONT LONG_CONT -- "5b.物理松开" --> REL_DEB REL_DEB -- "6a.松开消抖20ms到&&确定高电平" --> RELEASED[BUTTON_STATE_RELEASED] RELEASED -- "7.a自动复位(通知应用层后复位)" --> IDLE
下面是流程截图:

二、 核心跳转条件与动作详解
在你的 switch-case 轮询代码中,这 7 个状态的内在驱动逻辑如下:
1. 空闲 按下消抖 (IDLE PRESS_DEBOUNCE)
- 触发条件: 读取到硬件引脚电平为低(物理按下)。
- 执行动作: 启动/重置内部的消抖计数器(如
debounce_count = 0)。
2. 消抖判定 (PRESS_DEBOUNCE 的分叉)
- 分支 A (退回
IDLE): 如果在消抖时间内(例如没满 20ms),电平突然变回了高电平。判定为火花或电磁干扰(噪声抖动),直接打道回府。 - 分支 B (走向
PRESSED): 消抖时间顺利数满(如轮询了 2 次 10ms),且电平依然是低电平。判定为真正按下,记录当前的系统 tick 计数用于计算长按。
3. 确定按下 (PRESSED 的分叉)
- 分支 A (去松开消抖): 如果在长按时间阈值(如 1000ms)到来之前,用户松开了按键(电平变高)。此时判定为标准的“短按/单击”,向队列发送
CLICK事件,并去往RELEASE_DEBOUNCE。 - 分支 B (去长按单次): 用户死死按住不放,按下计时器累加达到了长按阈值(1000ms)。此时判定为“长按触发”,向队列发送
LONG_PRESS事件,状态转移至LONG_PRESS_ONCE。
4. 长按单次 长按连续 (LONG_PRESS_ONCE LONG_PRESS_CONTINUOUS)
- 分支 A (去松开消抖): 在触发了长按后,用户松手了。去往
RELEASE_DEBOUNCE。 - 分支 B (进阶连发): 用户继续按着不撒手。时间再次跨过设定的“连发间隔”(比如又过了 200ms),说明用户需要像调时钟一样“一直加数字”,状态转移至
LONG_PRESS_CONTINUOUS。
5. 持续连发循环 (LONG_PRESS_CONTINUOUS 自迭代)
- 自循环: 只要电平是低,每隔固定的连发间隔(如 200ms),就重复触发一次按键事件。状态依然保持为
LONG_PRESS_CONTINUOUS。 - 松开: 只要电平变高,随时打破循环,去往
RELEASE_DEBOUNCE。
6. 释放消抖 释放成功 (RELEASE_DEBOUNCE RELEASED)
- 意义: 物理按键在弹起时也会产生机械抖动(后沿抖动)。
- 逻辑: 确保电平稳定保持为高电平达到消抖时间后,状态走向
RELEASED。
7. 释放成功 空闲归位 (RELEASED IDLE)
- 清理现场: 到了这一步,标志着一个完整的按键生命周期(按下-判定-长/短按处理-松开-判定)彻底结束。代码中将按键的所有计时器清零,状态恢复为初始的
IDLE,静静等待下一次被按下。
