【STM32】状态机(State Machine)
这篇博客介绍 状态机(State Machine),适合用于嵌入式开发、驱动开发、协议解析、按键识别等多种场景。
一、什么是状态机(State Machine)?
状态机(State Machine)是一种用于描述系统行为的抽象模型,它能够根据当前状态和输入条件,转换到下一个状态,并执行相应操作。
使用场景常见有:
- 按键消抖与识别
- 通信协议(如 UART、Modbus、CAN)
- 嵌入式流程控制(菜单系统、流程调度等)(我们此前的文章为贪吃蛇小游戏设计菜单系统 和 贪吃蛇的状态改变 便用到了状态机)
- Linux 驱动状态切换
- UI 界面状态设计
- …等
二、状态机的基本组成
元素 | 说明 |
---|---|
状态(State) | 系统可能处于的状态集合,例如:IDLE、WAIT、RUN |
事件/输入(Event) | 触发状态转移的条件,例如:按键按下、超时、数据接收 |
动作(Action) | 状态转移时执行的操作,例如:发送数据、点亮LED |
转移(Transition) | 状态 + 输入 → 新状态 + 动作 |
状态机分类
类型 | 说明 | 示例 |
---|---|---|
有限状态机(FSM) | 状态数量有限,事件驱动型 | 按键识别 |
Mealy 状态机 | 输出依赖于状态 + 输入 | 通信协议 |
Moore 状态机 | 输出只依赖当前状态 | 电梯状态控制 |
层级状态机 | 状态嵌套,适合复杂系统 | UI 菜单系统 |
三、状态机图示(例:按键识别)
+---------+ 按下 +---------+
| 空闲态 | -------------> | 按下态 |
+---------+ +---------+^ || | 松开| v
+---------+ <------------- +---------+
| 单击处理 | | 松开态 |
+---------+ 超时 +---------+
四、代码模版说明(结构体 + 函数指针实现)
✅ 1. 状态定义
typedef enum {STATE_IDLE,STATE_PRESS,STATE_RELEASE,STATE_CLICK,STATE_MAX
} State_t;
✅ 2. 事件定义
typedef enum {EVENT_NONE,EVENT_KEY_DOWN,EVENT_KEY_UP,EVENT_TIMEOUT
} Event_t;
✅ 3. 状态处理函数指针表
typedef void (*ActionFunc)(void);typedef struct {State_t current_state;Event_t event;State_t next_state;ActionFunc action;
} StateTable_t;
✅ 4. 状态转移表
void do_nothing(void) {}
void handle_click(void) { printf("Click!\n"); }StateTable_t state_table[] = {{STATE_IDLE, EVENT_KEY_DOWN, STATE_PRESS, do_nothing},{STATE_PRESS, EVENT_KEY_UP, STATE_CLICK, handle_click},{STATE_CLICK, EVENT_TIMEOUT, STATE_IDLE, do_nothing},{STATE_PRESS, EVENT_TIMEOUT, STATE_IDLE, do_nothing},
};
✅ 5. 状态机执行函数
State_t current_state = STATE_IDLE;void state_machine_run(Event_t evt) {for (int i = 0; i < sizeof(state_table)/sizeof(StateTable_t); ++i) {if (state_table[i].current_state == current_state &&state_table[i].event == evt) {if (state_table[i].action) {state_table[i].action();}current_state = state_table[i].next_state;break;}}
}
状态机的实际作用:
场景 状态说明
按键处理 IDLE → PRESS → RELEASE → CLICK
通信协议 WAIT_RX → RECEIVING → PARSE → REPLY
UI 界面 主界面 → 设置界面 → 子菜单 → 返回
电机控制 停止 → 加速 → 稳速 → 减速
使用状态机时需要注意:① 状态机逻辑清晰,避免 if/else
嵌套过深;② 使用结构体+函数指针提高可扩展性;③ 可配合定时器、事件队列使用;④ 状态机应保持单一职责,避免过度复杂。
状态机调试方法:
状态打印 每次状态切换打印当前状态
图示辅助 画状态图帮助理清逻辑
加日志 用 log 函数记录状态流转
使用断点 在 state_machine_run() 中下断点观察转移
状态机是嵌入式开发中最实用的控制逻辑模型之一,掌握它能帮助在程序逻辑中有效管理复杂流程、提高代码可读性与可维护性。
以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!