在嵌入式开发中,状态机(State Machine, FSM)是一种非常常见且实用的设计模式。
无论是 业务逻辑实现、通信交互还是任务调度,几乎都离不开状态机。传统写法通常是 if/else 或 switch/case,但当状态和事件多起来时,代码会变得 臃肿难维护。本文将介绍一种 表驱动状态机 的实现方式,清晰、优雅、易扩展。
1.表驱动状态机原理
1.1. 传统实现方式
switch (state) {
case STATE_OFF:
if (event == EVT_PRESS) state = STATE_ON;
break;
case STATE_ON:
if (event == EVT_PRESS) state = STATE_BLINK;
break;
case STATE_BLINK:
if (event == EVT_PRESS) state = STATE_OFF;
break;
}
这种实现方式,状态较多时不易于维护,耦合度比较高。
1.2 表驱动思想
表驱动状态机用一张表集中描述逻辑:
| 当前状态 | 事件 | 下一个状态 | 动作函数 |
|---|---|---|---|
| STATE_OFF | EVT_PRESS | STATE_ON | entry_on() |
| STATE_ON | EVT_PRESS | STATE_BLINK | entry_blink() |
| STATE_BLINK | EVT_PRESS | STATE_OFF | entry_off() |
| STATE_ANY | EVT_ON | STATE_ON | entry_on() |
| STATE_ANY | EVT_OFF | STATE_OFF | entry_off() |
再写一个 通用执行器,遍历表格,找到匹配规则,完成状态迁移。这样逻辑和代码解耦,简洁可扩展。
2. 核心代码框架
2.1. 迁移表结构
typedef struct {
uint8_t curState; // 当前状态
uint32_t evtMask; // 事件掩码
uint8_t nextState; // 下一个状态
void (*action)(void); // 动作函数
} Transition;
2.2. 执行器
void state_machine_step(uint8_t* pState, const Transition* tbl, uint8_t tn, uint32_t evt) {
for (uint8_t i = 0; i < tn; i++) {
const Transiton* t = &tbl[i];
if ((*pState == t->curState || t->curState == STATE_ANY) && (evt & t->evtMask)) {
*pState = t->nextState;
if (t->action) t->action();
break;
}
}
}
3. 简单示例
3.1 源码
#include "state_machine.h"
// 事件定义
typedef enum {
EVT_PRESS = (1u << 0),
EVT_OFF = (1u << 1),
EVT_ON = (1u << 2),
} EvtBitMask;
// 状态定义
typedef enum {
STATE_OFF = 1,
STATE_ON,
STATE_BLINK,
} LedState;
static void entry_off(void) {
printf("LED OFF\n");
}
static void entry_on(void) {
printf("LED ON\n");
}
static void entry_blink(void) {
printf("LED BLINKING\n");
}
// 迁移表
static const Transition LED_TRANS[] = {
{STATE_OFF, EVT_PRESS, STATE_ON, entry_on},
{STATE_ON, EVT_PRESS, STATE_BLINK, entry_blink},
{STATE_BLINK, EVT_PRESS, STATE_OFF, entry_off},
{STATE_ANY, EVT_ON, STATE_ON, entry_on},
{STATE_ANY, EVT_OFF, STATE_OFF, entry_off},
};
int main(void) {
uint8_t ledState = STATE_ON;
Evt evtSeq[] = {EVT_PRESS, EVT_PRESS, EVT_PRESS, EVT_OFF, EVT_ON, EVT_OFF};
size_t n = sizeof(evtSeq) / sizeof(evtSeq[0]);
for (size_t i = 0; i < n; i++) {
state_machine_step(&ledState, LED_TRANS, sizeof(LED_TRANS) / sizeof(LED_TRANS[0]), evtSeq[i]);
}
return 0;
}
3.2 运行结果
LED BLINKING
LED OFF
LED ON
LED OFF
LED ON
LED OFF
4. 状态迁移图

5. 总结
-
表驱动状态机把复杂的逻辑集中到 迁移表,直观且易扩展
150

被折叠的 条评论
为什么被折叠?



