状态机设计模式实战:嵌入式系统的核心设计方法¶
概述¶
状态机(State Machine)是嵌入式系统中最重要的设计模式之一。它提供了一种清晰、结构化的方法来管理复杂的控制逻辑和系统行为。完成本教程后,你将能够:
- 理解状态机的基本概念和工作原理
- 掌握有限状态机(FSM)的设计方法
- 学会使用不同的状态机实现技术
- 理解事件驱动编程模型
- 能够设计和实现实际的状态机应用
- 掌握状态机的调试和优化技巧
背景知识¶
什么是状态机?¶
状态机(State Machine)是一种数学模型,用于描述系统在不同状态之间的转换。在嵌入式系统中,状态机是管理复杂行为的强大工具。
核心概念: - 状态(State):系统在某一时刻的工作模式或条件 - 事件(Event):触发状态转换的条件或输入 - 转换(Transition):从一个状态到另一个状态的变化 - 动作(Action):状态转换时执行的操作
状态机的基本要素:
为什么需要状态机?¶
在嵌入式系统中,我们经常遇到这样的问题:
问题场景:
// 没有状态机的代码:难以维护
void ProcessButton(void) {
if(button_pressed) {
if(system_on) {
if(mode == 1) {
if(timer_expired) {
// 做某事
} else {
// 做另一件事
}
} else if(mode == 2) {
// 更多嵌套...
}
} else {
// 更多条件...
}
}
}
这种代码的问题: - 逻辑复杂,难以理解 - 嵌套层次深,难以维护 - 容易出错,难以调试 - 扩展困难
使用状态机后:
// 使用状态机:清晰明了
void StateMachine(Event_t event) {
switch(current_state) {
case STATE_OFF:
if(event == EVENT_BUTTON_PRESS) {
current_state = STATE_ON;
TurnSystemOn();
}
break;
case STATE_ON:
if(event == EVENT_BUTTON_PRESS) {
current_state = STATE_OFF;
TurnSystemOff();
}
break;
}
}
状态机的类型¶
1. 有限状态机(FSM - Finite State Machine) - 状态数量有限 - 最常用的类型 - 适合大多数嵌入式应用
2. 分层状态机(HSM - Hierarchical State Machine) - 状态可以嵌套 - 支持状态继承 - 适合复杂系统
3. 并发状态机 - 多个状态机同时运行 - 状态机之间可以通信 - 适合多任务系统
本教程主要关注有限状态机(FSM),这是最基础也是最实用的类型。
核心内容¶
状态机的基本原理¶
状态图表示¶
状态机通常用状态图来表示:
[开始]
↓
┌───────┐
│ 空闲 │←──────────┐
└───────┘ │
│ │
按键按下 按键按下
│ │
↓ │
┌───────┐ │
│ 运行 │───────────┘
└───────┘
状态图的组成: - 圆角矩形:表示状态 - 箭头:表示状态转换 - 箭头上的文字:表示触发转换的事件 - 状态内的文字:表示状态名称
状态转换表¶
状态机也可以用表格表示:
| 当前状态 | 事件 | 动作 | 下一状态 |
|---|---|---|---|
| 空闲 | 按键按下 | 启动系统 | 运行 |
| 运行 | 按键按下 | 停止系统 | 空闲 |
| 运行 | 超时 | 报警 | 错误 |
| 错误 | 复位 | 清除错误 | 空闲 |
状态机的实现方法¶
方法1:Switch-Case实现¶
这是最简单、最直观的实现方法:
#include <stdint.h>
#include <stdbool.h>
// 定义状态
typedef enum {
STATE_IDLE, // 空闲状态
STATE_RUNNING, // 运行状态
STATE_PAUSED, // 暂停状态
STATE_ERROR // 错误状态
} State_t;
// 定义事件
typedef enum {
EVENT_NONE, // 无事件
EVENT_START, // 启动事件
EVENT_STOP, // 停止事件
EVENT_PAUSE, // 暂停事件
EVENT_RESUME, // 恢复事件
EVENT_ERROR_OCCUR, // 错误发生
EVENT_ERROR_CLEAR // 错误清除
} Event_t;
// 全局变量
State_t current_state = STATE_IDLE;
Event_t current_event = EVENT_NONE;
// 状态机处理函数
void StateMachine_Process(Event_t event) {
switch(current_state) {
case STATE_IDLE:
// 空闲状态的处理
if(event == EVENT_START) {
// 执行启动动作
SystemStart();
// 转换到运行状态
current_state = STATE_RUNNING;
}
break;
case STATE_RUNNING:
// 运行状态的处理
if(event == EVENT_STOP) {
SystemStop();
current_state = STATE_IDLE;
}
else if(event == EVENT_PAUSE) {
SystemPause();
current_state = STATE_PAUSED;
}
else if(event == EVENT_ERROR_OCCUR) {
HandleError();
current_state = STATE_ERROR;
}
break;
case STATE_PAUSED:
// 暂停状态的处理
if(event == EVENT_RESUME) {
SystemResume();
current_state = STATE_RUNNING;
}
else if(event == EVENT_STOP) {
SystemStop();
current_state = STATE_IDLE;
}
break;
case STATE_ERROR:
// 错误状态的处理
if(event == EVENT_ERROR_CLEAR) {
ClearError();
current_state = STATE_IDLE;
}
break;
default:
// 未知状态,重置到空闲
current_state = STATE_IDLE;
break;
}
}
// 主循环
int main(void) {
SystemInit();
while(1) {
// 获取事件(从按键、传感器等)
current_event = GetEvent();
// 处理状态机
if(current_event != EVENT_NONE) {
StateMachine_Process(current_event);
}
// 其他任务...
}
return 0;
}
优点: - 代码简单直观 - 易于理解和调试 - 适合小型状态机
缺点: - 状态多时代码冗长 - 难以扩展 - 状态转换逻辑分散
方法2:状态表驱动¶
使用表格驱动的方法,将状态转换逻辑集中管理:
#include <stdint.h>
#include <stdbool.h>
// 状态和事件定义(同上)
typedef enum {
STATE_IDLE,
STATE_RUNNING,
STATE_PAUSED,
STATE_ERROR,
STATE_MAX
} State_t;
typedef enum {
EVENT_START,
EVENT_STOP,
EVENT_PAUSE,
EVENT_RESUME,
EVENT_ERROR_OCCUR,
EVENT_ERROR_CLEAR,
EVENT_MAX
} Event_t;
// 动作函数类型
typedef void (*Action_t)(void);
// 状态转换表项
typedef struct {
State_t current_state; // 当前状态
Event_t event; // 触发事件
Action_t action; // 执行的动作
State_t next_state; // 下一状态
} StateTransition_t;
// 动作函数声明
void Action_SystemStart(void);
void Action_SystemStop(void);
void Action_SystemPause(void);
void Action_SystemResume(void);
void Action_HandleError(void);
void Action_ClearError(void);
void Action_None(void);
// 状态转换表
const StateTransition_t state_table[] = {
// 当前状态 事件 动作 下一状态
{STATE_IDLE, EVENT_START, Action_SystemStart, STATE_RUNNING},
{STATE_RUNNING, EVENT_STOP, Action_SystemStop, STATE_IDLE},
{STATE_RUNNING, EVENT_PAUSE, Action_SystemPause, STATE_PAUSED},
{STATE_RUNNING, EVENT_ERROR_OCCUR, Action_HandleError, STATE_ERROR},
{STATE_PAUSED, EVENT_RESUME, Action_SystemResume, STATE_RUNNING},
{STATE_PAUSED, EVENT_STOP, Action_SystemStop, STATE_IDLE},
{STATE_ERROR, EVENT_ERROR_CLEAR, Action_ClearError, STATE_IDLE},
};
#define STATE_TABLE_SIZE (sizeof(state_table) / sizeof(StateTransition_t))
// 当前状态
State_t current_state = STATE_IDLE;
// 状态机处理函数
void StateMachine_Process(Event_t event) {
// 遍历状态转换表
for(uint8_t i = 0; i < STATE_TABLE_SIZE; i++) {
// 查找匹配的转换
if(state_table[i].current_state == current_state &&
state_table[i].event == event) {
// 执行动作
if(state_table[i].action != NULL) {
state_table[i].action();
}
// 转换状态
current_state = state_table[i].next_state;
// 找到匹配项,退出循环
break;
}
}
}
// 动作函数实现
void Action_SystemStart(void) {
printf("System starting...\n");
// 启动系统的具体操作
}
void Action_SystemStop(void) {
printf("System stopping...\n");
// 停止系统的具体操作
}
void Action_SystemPause(void) {
printf("System paused\n");
// 暂停系统的具体操作
}
void Action_SystemResume(void) {
printf("System resumed\n");
// 恢复系统的具体操作
}
void Action_HandleError(void) {
printf("Error occurred!\n");
// 错误处理
}
void Action_ClearError(void) {
printf("Error cleared\n");
// 清除错误
}
void Action_None(void) {
// 空操作
}
优点: - 状态转换逻辑集中 - 易于维护和扩展 - 可以动态修改转换表 - 代码结构清晰
缺点: - 需要更多内存存储表格 - 查找转换需要遍历表格
方法3:函数指针实现¶
使用函数指针数组,每个状态对应一个处理函数:
#include <stdint.h>
#include <stdbool.h>
// 事件定义
typedef enum {
EVENT_START,
EVENT_STOP,
EVENT_PAUSE,
EVENT_RESUME,
EVENT_ERROR,
EVENT_CLEAR
} Event_t;
// 状态定义
typedef enum {
STATE_IDLE,
STATE_RUNNING,
STATE_PAUSED,
STATE_ERROR
} State_t;
// 状态处理函数类型
typedef State_t (*StateHandler_t)(Event_t event);
// 前向声明
State_t State_Idle_Handler(Event_t event);
State_t State_Running_Handler(Event_t event);
State_t State_Paused_Handler(Event_t event);
State_t State_Error_Handler(Event_t event);
// 状态处理函数数组
StateHandler_t state_handlers[] = {
State_Idle_Handler, // STATE_IDLE
State_Running_Handler, // STATE_RUNNING
State_Paused_Handler, // STATE_PAUSED
State_Error_Handler // STATE_ERROR
};
// 当前状态
State_t current_state = STATE_IDLE;
// 空闲状态处理函数
State_t State_Idle_Handler(Event_t event) {
switch(event) {
case EVENT_START:
printf("Starting system...\n");
InitializeSystem();
return STATE_RUNNING;
default:
return STATE_IDLE; // 保持当前状态
}
}
// 运行状态处理函数
State_t State_Running_Handler(Event_t event) {
switch(event) {
case EVENT_STOP:
printf("Stopping system...\n");
StopSystem();
return STATE_IDLE;
case EVENT_PAUSE:
printf("Pausing system...\n");
PauseSystem();
return STATE_PAUSED;
case EVENT_ERROR:
printf("Error detected!\n");
HandleError();
return STATE_ERROR;
default:
// 运行状态的正常处理
ProcessRunning();
return STATE_RUNNING;
}
}
// 暂停状态处理函数
State_t State_Paused_Handler(Event_t event) {
switch(event) {
case EVENT_RESUME:
printf("Resuming system...\n");
ResumeSystem();
return STATE_RUNNING;
case EVENT_STOP:
printf("Stopping from pause...\n");
StopSystem();
return STATE_IDLE;
default:
return STATE_PAUSED;
}
}
// 错误状态处理函数
State_t State_Error_Handler(Event_t event) {
switch(event) {
case EVENT_CLEAR:
printf("Clearing error...\n");
ClearError();
return STATE_IDLE;
default:
// 在错误状态下显示错误信息
DisplayError();
return STATE_ERROR;
}
}
// 状态机处理函数
void StateMachine_Process(Event_t event) {
// 调用当前状态的处理函数
State_t next_state = state_handlers[current_state](event);
// 更新状态
if(next_state != current_state) {
printf("State transition: %d -> %d\n", current_state, next_state);
current_state = next_state;
}
}
// 主循环
int main(void) {
SystemInit();
while(1) {
Event_t event = GetEvent();
StateMachine_Process(event);
}
return 0;
}
优点: - 每个状态的逻辑独立 - 易于添加新状态 - 代码模块化好 - 执行效率高
缺点: - 需要更多函数 - 状态转换逻辑分散
事件驱动机制¶
状态机通常与事件驱动编程结合使用。
事件队列实现¶
#include <stdint.h>
#include <stdbool.h>
#define EVENT_QUEUE_SIZE 16
// 事件定义
typedef enum {
EVENT_NONE,
EVENT_BUTTON_PRESS,
EVENT_BUTTON_RELEASE,
EVENT_TIMER_EXPIRE,
EVENT_DATA_RECEIVED,
EVENT_ERROR
} Event_t;
// 事件队列
typedef struct {
Event_t buffer[EVENT_QUEUE_SIZE];
uint8_t head;
uint8_t tail;
uint8_t count;
} EventQueue_t;
EventQueue_t event_queue = {0};
// 初始化事件队列
void EventQueue_Init(void) {
event_queue.head = 0;
event_queue.tail = 0;
event_queue.count = 0;
}
// 添加事件到队列
bool EventQueue_Push(Event_t event) {
if(event_queue.count >= EVENT_QUEUE_SIZE) {
return false; // 队列满
}
event_queue.buffer[event_queue.tail] = event;
event_queue.tail = (event_queue.tail + 1) % EVENT_QUEUE_SIZE;
event_queue.count++;
return true;
}
// 从队列获取事件
bool EventQueue_Pop(Event_t *event) {
if(event_queue.count == 0) {
return false; // 队列空
}
*event = event_queue.buffer[event_queue.head];
event_queue.head = (event_queue.head + 1) % EVENT_QUEUE_SIZE;
event_queue.count--;
return true;
}
// 检查队列是否为空
bool EventQueue_IsEmpty(void) {
return (event_queue.count == 0);
}
// 中断服务程序示例:按键中断
void Button_IRQHandler(void) {
if(ButtonIsPressed()) {
EventQueue_Push(EVENT_BUTTON_PRESS);
} else {
EventQueue_Push(EVENT_BUTTON_RELEASE);
}
}
// 定时器中断
void Timer_IRQHandler(void) {
EventQueue_Push(EVENT_TIMER_EXPIRE);
}
// 主循环
int main(void) {
SystemInit();
EventQueue_Init();
while(1) {
Event_t event;
// 处理队列中的所有事件
while(EventQueue_Pop(&event)) {
StateMachine_Process(event);
}
// 其他任务或进入低功耗模式
__WFI();
}
return 0;
}
事件队列的优点: - 解耦事件产生和处理 - 中断中只需添加事件,处理在主循环 - 可以缓冲多个事件 - 避免事件丢失
实践示例¶
示例1:LED控制状态机¶
实现一个简单的LED控制系统,支持多种闪烁模式:
#include <stdint.h>
#include <stdbool.h>
// LED状态定义
typedef enum {
LED_STATE_OFF, // 关闭
LED_STATE_ON, // 常亮
LED_STATE_BLINK_SLOW, // 慢速闪烁
LED_STATE_BLINK_FAST, // 快速闪烁
LED_STATE_BREATH // 呼吸灯
} LED_State_t;
// LED事件定义
typedef enum {
LED_EVENT_BUTTON_SHORT, // 短按
LED_EVENT_BUTTON_LONG, // 长按
LED_EVENT_TIMER_TICK // 定时器滴答
} LED_Event_t;
// 全局变量
LED_State_t led_state = LED_STATE_OFF;
uint32_t led_timer = 0;
uint8_t led_brightness = 0;
bool led_on = false;
// LED硬件控制
void LED_SetBrightness(uint8_t brightness) {
// 使用PWM控制LED亮度
PWM_SetDutyCycle(brightness);
}
void LED_TurnOn(void) {
LED_SetBrightness(255);
led_on = true;
}
void LED_TurnOff(void) {
LED_SetBrightness(0);
led_on = false;
}
// LED状态机处理
void LED_StateMachine(LED_Event_t event) {
switch(led_state) {
case LED_STATE_OFF:
if(event == LED_EVENT_BUTTON_SHORT) {
// 短按:开灯
LED_TurnOn();
led_state = LED_STATE_ON;
}
break;
case LED_STATE_ON:
if(event == LED_EVENT_BUTTON_SHORT) {
// 短按:慢速闪烁
led_timer = 0;
led_state = LED_STATE_BLINK_SLOW;
}
else if(event == LED_EVENT_BUTTON_LONG) {
// 长按:关灯
LED_TurnOff();
led_state = LED_STATE_OFF;
}
break;
case LED_STATE_BLINK_SLOW:
if(event == LED_EVENT_BUTTON_SHORT) {
// 短按:快速闪烁
led_timer = 0;
led_state = LED_STATE_BLINK_FAST;
}
else if(event == LED_EVENT_BUTTON_LONG) {
// 长按:关灯
LED_TurnOff();
led_state = LED_STATE_OFF;
}
else if(event == LED_EVENT_TIMER_TICK) {
// 定时器事件:慢速闪烁(1Hz)
led_timer++;
if(led_timer >= 500) { // 500ms
led_timer = 0;
if(led_on) {
LED_TurnOff();
} else {
LED_TurnOn();
}
}
}
break;
case LED_STATE_BLINK_FAST:
if(event == LED_EVENT_BUTTON_SHORT) {
// 短按:呼吸灯
led_timer = 0;
led_brightness = 0;
led_state = LED_STATE_BREATH;
}
else if(event == LED_EVENT_BUTTON_LONG) {
// 长按:关灯
LED_TurnOff();
led_state = LED_STATE_OFF;
}
else if(event == LED_EVENT_TIMER_TICK) {
// 定时器事件:快速闪烁(5Hz)
led_timer++;
if(led_timer >= 100) { // 100ms
led_timer = 0;
if(led_on) {
LED_TurnOff();
} else {
LED_TurnOn();
}
}
}
break;
case LED_STATE_BREATH:
if(event == LED_EVENT_BUTTON_SHORT) {
// 短按:常亮
LED_TurnOn();
led_state = LED_STATE_ON;
}
else if(event == LED_EVENT_BUTTON_LONG) {
// 长按:关灯
LED_TurnOff();
led_state = LED_STATE_OFF;
}
else if(event == LED_EVENT_TIMER_TICK) {
// 定时器事件:呼吸效果
led_timer++;
if(led_timer >= 10) { // 10ms
led_timer = 0;
// 亮度渐变
static bool increasing = true;
if(increasing) {
led_brightness += 5;
if(led_brightness >= 250) {
increasing = false;
}
} else {
led_brightness -= 5;
if(led_brightness <= 5) {
increasing = true;
}
}
LED_SetBrightness(led_brightness);
}
}
break;
}
}
// 按键检测(带消抖和长短按识别)
typedef enum {
BUTTON_STATE_IDLE,
BUTTON_STATE_PRESSED,
BUTTON_STATE_LONG_PRESS
} Button_State_t;
Button_State_t button_state = BUTTON_STATE_IDLE;
uint32_t button_timer = 0;
void Button_StateMachine(void) {
bool button_pressed = Button_IsPressed();
switch(button_state) {
case BUTTON_STATE_IDLE:
if(button_pressed) {
button_timer = 0;
button_state = BUTTON_STATE_PRESSED;
}
break;
case BUTTON_STATE_PRESSED:
if(!button_pressed) {
// 按键释放:短按
if(button_timer < 1000) { // 小于1秒
LED_StateMachine(LED_EVENT_BUTTON_SHORT);
}
button_state = BUTTON_STATE_IDLE;
}
else {
button_timer++;
if(button_timer >= 1000) { // 1秒
// 长按
LED_StateMachine(LED_EVENT_BUTTON_LONG);
button_state = BUTTON_STATE_LONG_PRESS;
}
}
break;
case BUTTON_STATE_LONG_PRESS:
if(!button_pressed) {
// 按键释放
button_state = BUTTON_STATE_IDLE;
}
break;
}
}
// 主循环
int main(void) {
SystemInit();
PWM_Init();
Button_Init();
Timer_Init(); // 1ms定时器
while(1) {
// 按键状态机
Button_StateMachine();
// LED定时器事件
static uint32_t last_tick = 0;
if(system_ticks - last_tick >= 1) {
last_tick = system_ticks;
LED_StateMachine(LED_EVENT_TIMER_TICK);
}
// 延时1ms
Delay_ms(1);
}
return 0;
}
示例说明:
这个LED控制系统展示了状态机的实际应用:
- 多个状态:
-
关闭、常亮、慢闪、快闪、呼吸灯
-
多种事件:
-
短按、长按、定时器滴答
-
状态转换:
- 短按循环切换模式
-
长按直接关闭
-
嵌套状态机:
- LED控制状态机
- 按键检测状态机
示例2:通信协议状态机¶
实现一个简单的串口通信协议解析器:
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// 协议格式:[STX][LEN][CMD][DATA...][CHK][ETX]
// STX: 0x02, ETX: 0x03
#define STX 0x02
#define ETX 0x03
#define MAX_DATA_LEN 64
// 协议解析状态
typedef enum {
PROTO_STATE_IDLE, // 空闲,等待STX
PROTO_STATE_LENGTH, // 接收长度
PROTO_STATE_COMMAND, // 接收命令
PROTO_STATE_DATA, // 接收数据
PROTO_STATE_CHECKSUM, // 接收校验和
PROTO_STATE_ETX // 等待ETX
} Protocol_State_t;
// 接收缓冲区
typedef struct {
uint8_t length;
uint8_t command;
uint8_t data[MAX_DATA_LEN];
uint8_t data_index;
uint8_t checksum;
uint8_t calculated_checksum;
} RxBuffer_t;
// 全局变量
Protocol_State_t proto_state = PROTO_STATE_IDLE;
RxBuffer_t rx_buffer = {0};
// 计算校验和
uint8_t CalculateChecksum(uint8_t *data, uint8_t len) {
uint8_t sum = 0;
for(uint8_t i = 0; i < len; i++) {
sum += data[i];
}
return sum;
}
// 处理接收到的完整帧
void ProcessReceivedFrame(void) {
printf("Received command: 0x%02X\n", rx_buffer.command);
printf("Data length: %d\n", rx_buffer.length);
// 根据命令执行相应操作
switch(rx_buffer.command) {
case 0x01: // 读取命令
HandleReadCommand(rx_buffer.data, rx_buffer.length);
break;
case 0x02: // 写入命令
HandleWriteCommand(rx_buffer.data, rx_buffer.length);
break;
case 0x03: // 控制命令
HandleControlCommand(rx_buffer.data, rx_buffer.length);
break;
default:
printf("Unknown command\n");
break;
}
}
// 协议解析状态机
void Protocol_StateMachine(uint8_t byte) {
switch(proto_state) {
case PROTO_STATE_IDLE:
if(byte == STX) {
// 收到起始符,准备接收
memset(&rx_buffer, 0, sizeof(RxBuffer_t));
proto_state = PROTO_STATE_LENGTH;
}
break;
case PROTO_STATE_LENGTH:
// 接收数据长度
rx_buffer.length = byte;
if(rx_buffer.length > MAX_DATA_LEN) {
// 长度错误,重置
proto_state = PROTO_STATE_IDLE;
} else {
rx_buffer.calculated_checksum = byte;
proto_state = PROTO_STATE_COMMAND;
}
break;
case PROTO_STATE_COMMAND:
// 接收命令
rx_buffer.command = byte;
rx_buffer.calculated_checksum += byte;
if(rx_buffer.length > 0) {
proto_state = PROTO_STATE_DATA;
} else {
proto_state = PROTO_STATE_CHECKSUM;
}
break;
case PROTO_STATE_DATA:
// 接收数据
rx_buffer.data[rx_buffer.data_index] = byte;
rx_buffer.calculated_checksum += byte;
rx_buffer.data_index++;
if(rx_buffer.data_index >= rx_buffer.length) {
proto_state = PROTO_STATE_CHECKSUM;
}
break;
case PROTO_STATE_CHECKSUM:
// 接收校验和
rx_buffer.checksum = byte;
proto_state = PROTO_STATE_ETX;
break;
case PROTO_STATE_ETX:
if(byte == ETX) {
// 收到结束符,验证校验和
if(rx_buffer.checksum == rx_buffer.calculated_checksum) {
// 校验通过,处理帧
ProcessReceivedFrame();
} else {
printf("Checksum error!\n");
}
} else {
printf("ETX error!\n");
}
// 重置到空闲状态
proto_state = PROTO_STATE_IDLE;
break;
}
}
// UART接收中断
void UART_RxHandler(void) {
uint8_t byte = UART_ReadByte();
Protocol_StateMachine(byte);
}
// 发送帧
void Protocol_SendFrame(uint8_t command, uint8_t *data, uint8_t length) {
uint8_t checksum = 0;
// 发送STX
UART_SendByte(STX);
// 发送长度
UART_SendByte(length);
checksum += length;
// 发送命令
UART_SendByte(command);
checksum += command;
// 发送数据
for(uint8_t i = 0; i < length; i++) {
UART_SendByte(data[i]);
checksum += data[i];
}
// 发送校验和
UART_SendByte(checksum);
// 发送ETX
UART_SendByte(ETX);
}
示例说明:
这个通信协议解析器展示了状态机在数据处理中的应用:
- 逐字节解析:
- 每收到一个字节,状态机处理一次
-
根据当前状态决定如何处理字节
-
错误处理:
- 长度检查
- 校验和验证
-
格式错误恢复
-
状态转换清晰:
- 每个状态对应协议的一个部分
- 状态转换逻辑简单明了
示例3:完整的系统控制状态机¶
实现一个包含初始化、运行、错误处理的完整系统:
#include <stdint.h>
#include <stdbool.h>
// 系统状态定义
typedef enum {
SYS_STATE_INIT, // 初始化
SYS_STATE_SELF_TEST, // 自检
SYS_STATE_READY, // 就绪
SYS_STATE_RUNNING, // 运行
SYS_STATE_PAUSED, // 暂停
SYS_STATE_ERROR, // 错误
SYS_STATE_SHUTDOWN // 关机
} System_State_t;
// 系统事件定义
typedef enum {
SYS_EVENT_NONE,
SYS_EVENT_INIT_COMPLETE,
SYS_EVENT_TEST_PASS,
SYS_EVENT_TEST_FAIL,
SYS_EVENT_START,
SYS_EVENT_STOP,
SYS_EVENT_PAUSE,
SYS_EVENT_RESUME,
SYS_EVENT_ERROR,
SYS_EVENT_ERROR_CLEARED,
SYS_EVENT_SHUTDOWN
} System_Event_t;
// 系统数据
typedef struct {
System_State_t state;
uint32_t run_time;
uint32_t error_count;
uint8_t error_code;
bool sensors_ok;
bool actuators_ok;
} System_t;
System_t system = {
.state = SYS_STATE_INIT,
.run_time = 0,
.error_count = 0,
.error_code = 0,
.sensors_ok = false,
.actuators_ok = false
};
// 状态进入函数(Entry Actions)
void State_Init_Entry(void) {
printf("Entering INIT state\n");
// 初始化硬件
GPIO_Init();
UART_Init();
ADC_Init();
Timer_Init();
}
void State_SelfTest_Entry(void) {
printf("Entering SELF_TEST state\n");
// 开始自检
system.sensors_ok = false;
system.actuators_ok = false;
}
void State_Ready_Entry(void) {
printf("Entering READY state\n");
// 系统就绪,等待启动命令
LED_SetColor(LED_GREEN);
}
void State_Running_Entry(void) {
printf("Entering RUNNING state\n");
// 启动系统
system.run_time = 0;
LED_SetColor(LED_BLUE);
StartProcessing();
}
void State_Paused_Entry(void) {
printf("Entering PAUSED state\n");
// 暂停系统
LED_SetColor(LED_YELLOW);
PauseProcessing();
}
void State_Error_Entry(void) {
printf("Entering ERROR state\n");
// 错误处理
system.error_count++;
LED_SetColor(LED_RED);
StopProcessing();
LogError(system.error_code);
}
void State_Shutdown_Entry(void) {
printf("Entering SHUTDOWN state\n");
// 关机
LED_SetColor(LED_OFF);
StopAllPeripherals();
}
// 状态退出函数(Exit Actions)
void State_Running_Exit(void) {
printf("Exiting RUNNING state, run time: %lu s\n", system.run_time);
}
// 状态处理函数(Do Actions)
void State_Init_Do(void) {
// 初始化过程
static uint8_t init_step = 0;
switch(init_step) {
case 0:
printf("Initializing peripherals...\n");
init_step++;
break;
case 1:
printf("Loading configuration...\n");
init_step++;
break;
case 2:
printf("Initialization complete\n");
init_step = 0;
// 发送初始化完成事件
System_PostEvent(SYS_EVENT_INIT_COMPLETE);
break;
}
}
void State_SelfTest_Do(void) {
// 自检过程
static uint8_t test_step = 0;
switch(test_step) {
case 0:
printf("Testing sensors...\n");
system.sensors_ok = TestSensors();
test_step++;
break;
case 1:
printf("Testing actuators...\n");
system.actuators_ok = TestActuators();
test_step++;
break;
case 2:
// 自检完成
test_step = 0;
if(system.sensors_ok && system.actuators_ok) {
printf("Self-test PASSED\n");
System_PostEvent(SYS_EVENT_TEST_PASS);
} else {
printf("Self-test FAILED\n");
system.error_code = 0x01; // 自检失败
System_PostEvent(SYS_EVENT_TEST_FAIL);
}
break;
}
}
void State_Running_Do(void) {
// 运行状态的处理
system.run_time++;
// 读取传感器
uint16_t sensor_value = ReadSensor();
// 处理数据
ProcessData(sensor_value);
// 更新输出
UpdateActuators();
// 检查错误
if(CheckForErrors()) {
system.error_code = GetErrorCode();
System_PostEvent(SYS_EVENT_ERROR);
}
}
void State_Error_Do(void) {
// 错误状态的处理
DisplayErrorCode(system.error_code);
// 尝试自动恢复
if(system.error_count < 3) {
if(TryRecovery()) {
System_PostEvent(SYS_EVENT_ERROR_CLEARED);
}
}
}
// 事件队列
#define EVENT_QUEUE_SIZE 16
System_Event_t event_queue[EVENT_QUEUE_SIZE];
uint8_t event_head = 0;
uint8_t event_tail = 0;
void System_PostEvent(System_Event_t event) {
event_queue[event_tail] = event;
event_tail = (event_tail + 1) % EVENT_QUEUE_SIZE;
}
bool System_GetEvent(System_Event_t *event) {
if(event_head == event_tail) {
return false; // 队列空
}
*event = event_queue[event_head];
event_head = (event_head + 1) % EVENT_QUEUE_SIZE;
return true;
}
// 状态机主函数
void System_StateMachine(System_Event_t event) {
System_State_t old_state = system.state;
switch(system.state) {
case SYS_STATE_INIT:
if(event == SYS_EVENT_INIT_COMPLETE) {
system.state = SYS_STATE_SELF_TEST;
}
break;
case SYS_STATE_SELF_TEST:
if(event == SYS_EVENT_TEST_PASS) {
system.state = SYS_STATE_READY;
}
else if(event == SYS_EVENT_TEST_FAIL) {
system.state = SYS_STATE_ERROR;
}
break;
case SYS_STATE_READY:
if(event == SYS_EVENT_START) {
system.state = SYS_STATE_RUNNING;
}
else if(event == SYS_EVENT_SHUTDOWN) {
system.state = SYS_STATE_SHUTDOWN;
}
break;
case SYS_STATE_RUNNING:
if(event == SYS_EVENT_STOP) {
system.state = SYS_STATE_READY;
}
else if(event == SYS_EVENT_PAUSE) {
system.state = SYS_STATE_PAUSED;
}
else if(event == SYS_EVENT_ERROR) {
system.state = SYS_STATE_ERROR;
}
break;
case SYS_STATE_PAUSED:
if(event == SYS_EVENT_RESUME) {
system.state = SYS_STATE_RUNNING;
}
else if(event == SYS_EVENT_STOP) {
system.state = SYS_STATE_READY;
}
break;
case SYS_STATE_ERROR:
if(event == SYS_EVENT_ERROR_CLEARED) {
system.state = SYS_STATE_READY;
}
else if(event == SYS_EVENT_SHUTDOWN) {
system.state = SYS_STATE_SHUTDOWN;
}
break;
case SYS_STATE_SHUTDOWN:
// 关机状态,不响应事件
break;
}
// 状态转换处理
if(old_state != system.state) {
// 执行退出动作
switch(old_state) {
case SYS_STATE_RUNNING:
State_Running_Exit();
break;
// 其他状态的退出动作...
}
// 执行进入动作
switch(system.state) {
case SYS_STATE_INIT:
State_Init_Entry();
break;
case SYS_STATE_SELF_TEST:
State_SelfTest_Entry();
break;
case SYS_STATE_READY:
State_Ready_Entry();
break;
case SYS_STATE_RUNNING:
State_Running_Entry();
break;
case SYS_STATE_PAUSED:
State_Paused_Entry();
break;
case SYS_STATE_ERROR:
State_Error_Entry();
break;
case SYS_STATE_SHUTDOWN:
State_Shutdown_Entry();
break;
}
}
}
// 状态机执行函数
void System_Execute(void) {
// 执行当前状态的处理函数
switch(system.state) {
case SYS_STATE_INIT:
State_Init_Do();
break;
case SYS_STATE_SELF_TEST:
State_SelfTest_Do();
break;
case SYS_STATE_RUNNING:
State_Running_Do();
break;
case SYS_STATE_ERROR:
State_Error_Do();
break;
// 其他状态...
}
}
// 主循环
int main(void) {
// 进入初始化状态
State_Init_Entry();
while(1) {
// 处理事件
System_Event_t event;
if(System_GetEvent(&event)) {
System_StateMachine(event);
}
// 执行当前状态的处理
System_Execute();
// 延时
Delay_ms(100);
}
return 0;
}
示例说明:
这个完整的系统控制状态机展示了:
- 完整的状态生命周期:
- Entry动作:进入状态时执行
- Do动作:在状态中持续执行
-
Exit动作:离开状态时执行
-
复杂的状态转换:
- 初始化 → 自检 → 就绪 → 运行
- 错误处理和恢复
-
暂停和恢复
-
事件驱动:
- 使用事件队列
-
异步事件处理
-
实际应用场景:
- 系统启动流程
- 运行时监控
- 错误处理
深入理解¶
状态机设计原则¶
1. 单一职责原则¶
每个状态应该有明确的职责:
// 好的设计:状态职责明确
typedef enum {
STATE_IDLE, // 职责:等待命令
STATE_PROCESSING, // 职责:处理数据
STATE_SENDING, // 职责:发送结果
} State_t;
// 不好的设计:状态职责不清
typedef enum {
STATE_WORKING, // 职责不明确
STATE_BUSY, // 职责不明确
} State_t;
2. 状态完备性¶
确保所有可能的状态都被考虑:
// 完备的状态设计
typedef enum {
STATE_POWER_OFF, // 关机
STATE_POWER_ON, // 开机
STATE_STANDBY, // 待机
STATE_ACTIVE, // 活动
STATE_ERROR, // 错误
STATE_MAINTENANCE // 维护
} State_t;
3. 事件完备性¶
确保所有可能的事件都被处理:
void StateMachine(Event_t event) {
switch(current_state) {
case STATE_IDLE:
switch(event) {
case EVENT_START:
// 处理启动
break;
case EVENT_CONFIG:
// 处理配置
break;
default:
// 处理未知事件
HandleUnknownEvent(event);
break;
}
break;
}
}
状态机的调试技巧¶
1. 状态转换日志¶
void StateMachine_Transition(State_t new_state) {
printf("[%lu] State: %s -> %s\n",
system_ticks,
StateToString(current_state),
StateToString(new_state));
current_state = new_state;
}
const char* StateToString(State_t state) {
switch(state) {
case STATE_IDLE: return "IDLE";
case STATE_RUNNING: return "RUNNING";
case STATE_ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
2. 状态历史记录¶
#define STATE_HISTORY_SIZE 16
typedef struct {
State_t state;
uint32_t timestamp;
Event_t trigger_event;
} StateHistory_t;
StateHistory_t state_history[STATE_HISTORY_SIZE];
uint8_t history_index = 0;
void RecordStateChange(State_t new_state, Event_t event) {
state_history[history_index].state = new_state;
state_history[history_index].timestamp = system_ticks;
state_history[history_index].trigger_event = event;
history_index = (history_index + 1) % STATE_HISTORY_SIZE;
}
void PrintStateHistory(void) {
printf("State History:\n");
for(uint8_t i = 0; i < STATE_HISTORY_SIZE; i++) {
uint8_t idx = (history_index + i) % STATE_HISTORY_SIZE;
printf("[%lu] %s (Event: %d)\n",
state_history[idx].timestamp,
StateToString(state_history[idx].state),
state_history[idx].trigger_event);
}
}
3. 状态机可视化¶
// 生成Graphviz DOT格式的状态图
void GenerateStateDiagram(void) {
printf("digraph StateMachine {\n");
printf(" IDLE -> RUNNING [label=\"START\"];\n");
printf(" RUNNING -> IDLE [label=\"STOP\"];\n");
printf(" RUNNING -> PAUSED [label=\"PAUSE\"];\n");
printf(" PAUSED -> RUNNING [label=\"RESUME\"];\n");
printf(" RUNNING -> ERROR [label=\"ERROR\"];\n");
printf(" ERROR -> IDLE [label=\"RESET\"];\n");
printf("}\n");
}
性能优化¶
1. 减少状态转换开销¶
// 优化前:每次都检查状态转换
void StateMachine(Event_t event) {
State_t old_state = current_state;
// 状态转换逻辑...
if(old_state != current_state) {
OnStateExit(old_state);
OnStateEntry(current_state);
}
}
// 优化后:只在需要时检查
void StateMachine(Event_t event) {
switch(current_state) {
case STATE_IDLE:
if(event == EVENT_START) {
OnStateExit(STATE_IDLE);
current_state = STATE_RUNNING;
OnStateEntry(STATE_RUNNING);
}
break;
}
}
2. 使用查找表加速¶
// 使用二维数组实现快速查找
State_t transition_table[STATE_MAX][EVENT_MAX] = {
// STATE_IDLE的转换
[STATE_IDLE][EVENT_START] = STATE_RUNNING,
[STATE_IDLE][EVENT_CONFIG] = STATE_CONFIG,
// STATE_RUNNING的转换
[STATE_RUNNING][EVENT_STOP] = STATE_IDLE,
[STATE_RUNNING][EVENT_PAUSE] = STATE_PAUSED,
// 其他转换...
};
void StateMachine_Fast(Event_t event) {
State_t next_state = transition_table[current_state][event];
if(next_state != STATE_INVALID) {
current_state = next_state;
}
}
3. 内联小函数¶
// 对于简单的状态处理,使用内联函数
static inline void ProcessIdleState(Event_t event) {
if(event == EVENT_START) {
current_state = STATE_RUNNING;
}
}
常见问题¶
Q1: 状态机和超级循环有什么区别?¶
A: 它们是互补的概念:
- 超级循环:程序的执行框架,决定任务的执行顺序
- 状态机:程序的逻辑结构,管理系统的行为模式
可以在超级循环中使用状态机:
int main(void) {
while(1) {
// 超级循环
Task_ReadSensors();
Task_StateMachine(); // 状态机作为一个任务
Task_UpdateDisplay();
}
}
Q2: 什么时候应该使用状态机?¶
A: 以下情况建议使用状态机:
- 系统有明确的工作模式
-
例如:开机、运行、待机、关机
-
逻辑有多个分支和条件
-
避免深层嵌套的if-else
-
需要管理复杂的时序
-
例如:通信协议、启动流程
-
系统行为需要可预测
-
状态转换清晰明确
-
代码需要易于维护和扩展
- 添加新状态或事件很容易
Q3: 如何处理状态机中的超时?¶
A: 有几种方法:
方法1:在状态中维护计时器
typedef struct {
State_t state;
uint32_t state_entry_time;
uint32_t timeout;
} StateMachine_t;
void StateMachine_Process(void) {
uint32_t time_in_state = system_ticks - sm.state_entry_time;
switch(sm.state) {
case STATE_WAITING:
if(time_in_state >= sm.timeout) {
// 超时处理
sm.state = STATE_TIMEOUT;
}
break;
}
}
方法2:使用超时事件
void Timer_Handler(void) {
if(timeout_expired) {
PostEvent(EVENT_TIMEOUT);
}
}
void StateMachine(Event_t event) {
switch(current_state) {
case STATE_WAITING:
if(event == EVENT_TIMEOUT) {
current_state = STATE_TIMEOUT;
}
break;
}
}
Q4: 如何在状态机之间通信?¶
A: 几种常用方法:
方法1:共享变量
// 全局标志
volatile bool data_ready = false;
// 状态机A
void StateMachine_A(void) {
if(data_processed) {
data_ready = true; // 通知状态机B
}
}
// 状态机B
void StateMachine_B(void) {
if(data_ready) {
ProcessData();
data_ready = false;
}
}
方法2:事件队列
void StateMachine_A(void) {
// 发送事件给状态机B
PostEventToB(EVENT_DATA_READY);
}
void StateMachine_B(Event_t event) {
if(event == EVENT_DATA_READY) {
ProcessData();
}
}
方法3:回调函数
void StateMachine_A_SetCallback(void (*callback)(void)) {
sm_a_callback = callback;
}
void StateMachine_A(void) {
if(data_ready && sm_a_callback != NULL) {
sm_a_callback(); // 通知状态机B
}
}
Q5: 状态机可以嵌套吗?¶
A: 可以,这就是分层状态机(HSM):
// 主状态机
typedef enum {
MAIN_STATE_OFF,
MAIN_STATE_ON
} MainState_t;
// ON状态的子状态机
typedef enum {
SUB_STATE_IDLE,
SUB_STATE_ACTIVE,
SUB_STATE_SLEEP
} SubState_t;
MainState_t main_state = MAIN_STATE_OFF;
SubState_t sub_state = SUB_STATE_IDLE;
void StateMachine(Event_t event) {
switch(main_state) {
case MAIN_STATE_OFF:
if(event == EVENT_POWER_ON) {
main_state = MAIN_STATE_ON;
sub_state = SUB_STATE_IDLE;
}
break;
case MAIN_STATE_ON:
// 处理子状态机
SubStateMachine(event);
if(event == EVENT_POWER_OFF) {
main_state = MAIN_STATE_OFF;
}
break;
}
}
void SubStateMachine(Event_t event) {
switch(sub_state) {
case SUB_STATE_IDLE:
if(event == EVENT_START) {
sub_state = SUB_STATE_ACTIVE;
}
break;
case SUB_STATE_ACTIVE:
if(event == EVENT_SLEEP) {
sub_state = SUB_STATE_SLEEP;
}
break;
case SUB_STATE_SLEEP:
if(event == EVENT_WAKE) {
sub_state = SUB_STATE_ACTIVE;
}
break;
}
}
最佳实践¶
设计检查清单¶
在实现状态机前,检查以下项目:
- 是否列出了所有可能的状态?
- 是否定义了所有可能的事件?
- 是否考虑了所有的状态转换?
- 是否有初始状态和终止状态?
- 是否处理了非法状态转换?
- 是否考虑了超时情况?
- 是否有错误恢复机制?
- 状态转换是否有日志记录?
代码组织建议¶
// ============ 推荐的文件结构 ============
// state_machine.h
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
// 状态定义
typedef enum {
STATE_IDLE,
STATE_RUNNING,
// ...
} State_t;
// 事件定义
typedef enum {
EVENT_START,
EVENT_STOP,
// ...
} Event_t;
// 公共接口
void StateMachine_Init(void);
void StateMachine_Process(Event_t event);
State_t StateMachine_GetState(void);
#endif
// state_machine.c
#include "state_machine.h"
// 私有变量
static State_t current_state = STATE_IDLE;
// 私有函数
static void OnStateEntry(State_t state);
static void OnStateExit(State_t state);
// 公共函数实现
void StateMachine_Init(void) {
current_state = STATE_IDLE;
OnStateEntry(STATE_IDLE);
}
void StateMachine_Process(Event_t event) {
// 状态机逻辑
}
State_t StateMachine_GetState(void) {
return current_state;
}
命名规范¶
// 状态命名:STATE_前缀 + 大写
typedef enum {
STATE_IDLE,
STATE_RUNNING,
STATE_ERROR
} State_t;
// 事件命名:EVENT_前缀 + 大写
typedef enum {
EVENT_START,
EVENT_STOP,
EVENT_ERROR_OCCUR
} Event_t;
// 函数命名:模块名_功能
void StateMachine_Init(void);
void StateMachine_Process(Event_t event);
void StateMachine_Reset(void);
// 状态处理函数:State_状态名_动作
void State_Idle_Entry(void);
void State_Idle_Do(void);
void State_Idle_Exit(void);
文档化¶
为状态机编写清晰的文档:
/**
* @brief LED控制状态机
*
* 状态说明:
* - STATE_OFF: LED关闭
* - STATE_ON: LED常亮
* - STATE_BLINK: LED闪烁
*
* 状态转换:
* OFF --[短按]--> ON
* ON --[短按]--> BLINK
* BLINK --[短按]--> OFF
* 任何状态 --[长按]--> OFF
*
* @param event 触发事件
*/
void LED_StateMachine(LED_Event_t event);
总结¶
状态机是嵌入式系统中最重要的设计模式之一:
核心概念: - 状态:系统的工作模式 - 事件:触发状态转换的条件 - 转换:从一个状态到另一个状态 - 动作:状态转换时的操作
实现方法: - Switch-Case:简单直观 - 状态表驱动:易于维护 - 函数指针:模块化好
关键优势: - 逻辑清晰,易于理解 - 代码结构化,易于维护 - 便于调试和测试 - 易于扩展新功能
应用场景: - 系统控制流程 - 通信协议解析 - 用户界面管理 - 设备状态管理
设计原则: - 状态职责明确 - 状态和事件完备 - 转换逻辑清晰 - 错误处理完善
最佳实践: - 使用枚举定义状态和事件 - 实现Entry/Do/Exit动作 - 添加状态转换日志 - 编写清晰的文档
延伸阅读¶
推荐进一步学习的内容:
- 时间片轮询调度算法 - 学习更高级的任务调度
- 事件驱动架构设计 - 深入理解事件驱动
- 协作式多任务调度器实现 - 结合状态机的调度器
- RTOS任务管理基础 - 了解RTOS中的状态管理
参考资料¶
- "Practical UML Statecharts in C/C++" - Miro Samek
- "Design Patterns for Embedded Systems in C" - Bruce Powel Douglass
- "Embedded Software Development with C" - Kai Qian
- "State Machine Design in C++" - David Lafreniere
实践练习:
- 基础练习:实现一个交通信号灯状态机
- 红灯 → 绿灯 → 黄灯 → 红灯
- 每个状态持续固定时间
-
支持紧急模式(全部闪烁)
-
进阶练习:实现一个自动售货机状态机
- 空闲 → 选择商品 → 投币 → 出货 → 找零 → 空闲
- 支持取消操作
-
处理余额不足情况
-
挑战练习:实现一个完整的串口通信协议
- 支持多种命令类型
- 包含错误检测和重传机制
- 实现超时处理
- 添加状态转换日志
下一步:建议学习 时间片轮询调度算法,了解如何在状态机基础上实现更复杂的任务调度。