# fsm **Repository Path**: redocCheng/fsm ## Basic Information - **Project Name**: fsm - **Description**: 纯头文件的 C 语言有限状态机(FSM)辅助宏,适用于嵌入式/RTOS 场景。 - **Primary Language**: C - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-10-22 - **Last Updated**: 2025-12-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # fsm 一个轻量、纯头文件的 C 语言有限状态机(FSM)辅助宏集合,适用于嵌入式/RTOS 场景。 本仓库包含: - `fsm.h`:FSM 核心宏与 `state_t/event_t` 定义(无 RTOS 依赖) - `motor_state.c`/`motor_event.c`:在 RT-Thread 下的使用示例(mailbox + 周期心跳驱动) ## 快速开始 1) 引入头文件: ```c #include "fsm.h" ``` 2) 定义状态与事件: ```c typedef enum { ST_ROOT = 0, ST_IDLE, ST_RUN } my_state_t; typedef enum { EVT_NULL = 0, EVT_HEARTBEAT, EVT_START_STOP } my_event_t; ``` 3) 创建 FSM 实例(至少需要一个 `state_t`)并初始化: ```c state_t fsm; fsm.previous_state = 0xFF; fsm.current_state = ST_ROOT; fsm.next_state = ST_ROOT; ``` 4) 编写状态机函数(`state_t *` 参数名必须叫 `me`,因为宏内部直接使用 `me`): ```c int my_fsm_run(state_t *me, event_t *event) { switch (me->current_state) { case ST_ROOT: STATE_ENTRY_ACTION /* entry:仅在切入该状态时运行 */ STATE_TRANSITION_ACTION /* do:仅在 next_state == current_state 时运行 */ if (event->sig == EVT_HEARTBEAT) { TRAN(ST_IDLE); } STATE_EXIT_ACTION /* exit:仅在发生状态迁移时运行 */ STATE_END case ST_IDLE: STATE_ENTRY_ACTION STATE_TRANSITION_ACTION if (event->sig == EVT_START_STOP) { TRAN(ST_RUN); } STATE_EXIT_ACTION STATE_END case ST_RUN: STATE_ENTRY_ACTION STATE_TRANSITION_ACTION if (event->sig == EVT_START_STOP) { TRAN(ST_IDLE); } STATE_EXIT_ACTION STATE_END } return 0; } ``` 5) 事件驱动:把 `event->sig` 设置为当前事件,然后周期性调用一次 `my_fsm_run(&fsm, &event)`。 ## 宏的含义(核心) - `TRAN(state)`:请求跳转到 `state`(真正切换发生在 `STATE_END`) - `TRAN_CURRENT()`:强制“重进当前状态”(下一次派发会再次执行 entry) - `STATE_ENTRY_ACTION`:entry 块开始(仅 `current_state != previous_state` 时进入) - `STATE_TRANSITION_ACTION`:do 块开始(先把 `previous_state = current_state`,然后仅 `next_state == current_state` 时进入 do) - `STATE_EXIT_ACTION`:exit 块开始(仅 `next_state != current_state` 时进入) - `STATE_END`:提交 `current_state = next_state` 并 `break`(必须在 `switch-case` 内使用) - `STATE_PREVIOUS`:读取 `previous_state` ## 示例:motor 状态机 示例文件: - `motor_state.c`:状态机 `motor_state_run()` + 线程周期心跳驱动 - `motor_event.c`:RT-Thread mailbox 事件队列 在 `motor_state.c` 中你可以看到典型用法:用 `MOTOR_EVENT_HEARTBEAT` 作为周期 tick,把状态机“跑起来”,再通过 `motor_event_change()` 注入其它业务事件。 ## 注意事项 - `STATE_END` 内部带 `break;`,所以每个 `case` 都必须以 `STATE_END` 结束。 - `event_t.sig` 和 `state_t` 的状态字段都是 `uint8_t`;状态/事件枚举值应保持在 `0~255`。 - `STATE_TRANSITION_ACTION_EXCLUSIVE` / `STATE_EXIT_ACTION_EXCLUSIVE` 是 `else if` 版本:当你希望 entry 与 do(或 do 与 exit)互斥时使用。