告别面条代码:有限状态机 (FSM) 设计模式

Evek Golden Lv4

“if 嵌套十层,flag 满天飞”,这是很多初学者代码的真实写照。当系统逻辑稍微复杂一点,这种线性思维的代码就变得难以维护。

有限状态机 (FSM, Finite State Machine) 是嵌入式软件的灵魂。它将系统的行为建模为一组状态及其转换。

1. 为什么需要状态机?

假设你要做一个按键消抖功能:

  • 未按下 -> 刚按下 -> 确认按下 (消抖后) -> 刚释放 -> 未按下。

如果不定义这些状态,你的代码里会有无数个 is_pressedlast_timedebounce_cnt 变量。而使用 FSM,你只需要关注当前处于哪个状态,以及收到什么事件(Timer, GPIO)后跳转到哪里。

2. 第一重境界:Switch-Case

这是最直观的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
typedef enum {
STATE_IDLE,
STATE_WAIT_ACK,
STATE_DATA_XFER,
STATE_ERROR
} State_t;

void FSM_Run(Event_t event) {
switch (currentState) {
case STATE_IDLE:
if (event == EVT_START) {
currentState = STATE_WAIT_ACK;
Timer_Start(100); // Action on transition
}
break;
case STATE_WAIT_ACK:
if (event == EVT_RX_ACK) {
currentState = STATE_DATA_XFER;
} else if (event == EVT_TIMEOUT) {
currentState = STATE_ERROR;
}
break;
// ...
}
}
  • 优点:简单,容易理解。
  • 缺点:当状态变多且每个状态逻辑复杂时,函数会变得巨大无比(几千行)。

3. 第二重境界:函数指针表 (Table Driven)

将每个状态的行为封装成一个函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef void (*StateFunc_t)(Event_t);

void State_Idle(Event_t evt);
void State_WaitAck(Event_t evt);

StateFunc_t FSM_Table[] = {
[STATE_IDLE] = State_Idle,
[STATE_WAIT_ACK] = State_WaitAck,
// ...
};

void FSM_Run(Event_t event) {
if (currentState < MAX_STATES) {
FSM_Table[currentState](event);
}
}
  • 优点:代码解耦,结构清晰。增加新状态只需增加新函数。

4. 第三重境界:分层状态机 (HSM)

对于复杂的设备(如微波炉:关门 -> 设定时间 -> 运行),“运行”状态下又有子状态(高火、低火、烧烤)。如果用平面 FSM,会产生状态爆炸。

HSM (Hierarchical State Machine) 允许状态嵌套。

  • 父状态处理通用事件(如“断电”事件,无论在哪个子状态,都统一由父状态处理)。
  • 子状态处理特定事件。
  • 框架推荐QP/C (Quantum Platform) 是最著名的嵌入式 HSM 框架,实现了 UML 状态图的所有特性。

总结

拥有状态机思维,你的代码将不再是不可预测的“面条”,而是精密运转的钟表。

  • Title: 告别面条代码:有限状态机 (FSM) 设计模式
  • Author: Evek Golden
  • Created at : 2024-09-03 11:00:00
  • Updated at : 2026-06-12 08:57:02
  • Link: https://blog.cocodemo.uno/posts/fsm4k8l/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments