一种灵活通用的C语言状态机架构
在一般单片机开发过程中通常不会使用到操作系统,一方面是因为很多单片机的资源不够用,另一方面是因为还没有到使用操作系统的时候。因为要使用嵌入式操作系统需要一定的学习时间,但很多时候我们是没有这么多的时间来学习嵌入式操作系统的。而且就算是学会了操作系统后对应不同平台的移植操作也是比较费时费力的。
之前写过了关于单片机裸机开发中经常使用的时间片轮询法进行了简单的描述,并且给出了相应的源码,后来还改进了一版,将其整理成一个通用框架,能够动态增删任务,十分方便好用。链接如下:
其实在单片机开发过程中还有一种十分常用的模式,叫做状态机。就是将不同任务划分到不同的状态当中,只有在满足一定条件的情况下才进入该状态,执行该函数。通常实现方式是使用switch...case结构实现。
但是switch...case结构在状态机规模较小的时候用着还行,但是当状态较多或者状态处理太复杂的时候会导致switch..case结构太长,不好维护的情况。而且如果用到层次状态机的时候会导致代码更加冗长,可读性极差。
同样,这里提供一个同之前时间片轮询法相似结构的状态机框架,用户只需将相应文件加入自己工程中即可使用,不用修改任何代码。当然,具体的任务处理代码需要自己在外部写上,然后通过库函数加到相应的状态机当中。
这里的思路是将状态机和状态当成两种对象,可以创建多个状态机,创建多个状态机状态对象。然后把相应的状态对象添加到相应的状态机中即可。
这样做有很多好处,不如要实现层次状态机,只需要将层次深的状态机放到上一级状态机的相应状态函数中调用即可。
OK,废话不多说,直接上测试例程:
#include <thread>
#include <cstdio>
#include <windows.h>
#include "fsm_test.h"
#include "fsm.h"
// 状态机1的状态
enum fsm_1_state
FSM1_STATE_1 = 11,
FSM1_STATE_2 = 12,
FSM1_STATE_3 = 13
// 状态机2的状态
enum fsm_2_state
FSM2_STATE_1 = 21,
FSM2_STATE_2 = 22,
FSM2_STATE_3 = 23
// 创建两个状态机对象
FsmObj fsm_1;
FsmObj fsm_2;
// 给每个状态机创建3个状态对象
FsmStateObj fsm1_state_1, fsm1_state_2, fsm1_state_3;
FsmStateObj fsm2_state_1, fsm2_state_2, fsm2_state_3;
// 声明一下每个状态对象的状态处理函数
unsigned char fsm1_state_1_hdl(void);
unsigned char fsm1_state_2_hdl(void);
unsigned char fsm1_state_3_hdl(void);
unsigned char fsm2_state_1_hdl(void);
unsigned char fsm2_state_2_hdl(void);
unsigned char fsm2_state_3_hdl(void);
void fsm_test_init()
// 初始化状态机
fsm_init(&fsm_1, "fsm 1", FSM1_STATE_1);
fsm_init(&fsm_2, "fsm 2", FSM2_STATE_1);
// 初始化状态对象
fsm_state_init(&fsm1_state_1, FSM1_STATE_1, fsm1_state_1_hdl);
fsm_state_init(&fsm1_state_2, FSM1_STATE_2, fsm1_state_2_hdl);
fsm_state_init(&fsm1_state_3, FSM1_STATE_3, fsm1_state_3_hdl);
fsm_state_add(&fsm_1, &fsm1_state_1);
fsm_state_add(&fsm_1, &fsm1_state_2);
fsm_state_add(&fsm_1, &fsm1_state_3);
// 将状态对象添加到相应的状态机中
fsm_state_init(&fsm2_state_1, FSM2_STATE_1, fsm2_state_1_hdl);
fsm_state_init(&fsm2_state_2, FSM2_STATE_2, fsm2_state_2_hdl);
fsm_state_init(&fsm2_state_3, FSM2_STATE_3, fsm2_state_3_hdl);
fsm_state_add(&fsm_2, &fsm2_state_1);
fsm_state_add(&fsm_2, &fsm2_state_2);
fsm_state_add(&fsm_2, &fsm2_state_3);
int fsm_test()
unsigned int i = 0;
fsm_test_init();
// 测试状态机框架的一些函数
printf("\n");
printf(">> FSM 1 current state is: %d \n", fsm_state_get(&fsm_1));
printf(">> FSM 2 current state is: %d \n", fsm_state_get(&fsm_2));
printf("\n");
printf(">> fsm1_state_1 link is: %d \n", fsm_state_link(&fsm1_state_1));
printf(">> fsm1_state_2 link is: %d \n", fsm_state_link(&fsm1_state_2));
printf(">> fsm1_state_3 link is: %d \n", fsm_state_link(&fsm1_state_3));
printf("\n");
printf(">> fsm2_state_1 link is: %d \n", fsm_state_link(&fsm2_state_1));
printf(">> fsm2_state_2 link is: %d \n", fsm_state_link(&fsm2_state_2));
printf(">> fsm2_state_3 link is: %d \n", fsm_state_link(&fsm2_state_3));
printf("\n");
printf(">> fsm1_state_2 is belongs to: %s \n", fsm_state_blelong_to(&fsm1_state_2));
printf(">> fsm2_state_3 is belongs to: %s \n", fsm_state_blelong_to(&fsm2_state_3));
printf("\n ================ FSM start run =====================\n\n");
while (true)
printf("\n>> %d\n", i++);
// 运行状态机, 这个可以嵌套形成层次状态机
fsm_exec(&fsm_1);
fsm_exec(&fsm_2);
Sleep(1000);
return 0;
// 相应的状态处理函数实现
unsigned char fsm1_state_1_hdl()
printf(">> Fsm1 state 1 is running ... ");
printf(":: fsm1 next state is state 2 \n");
fsm_change_state(&fsm_1, FSM1_STATE_2);
return 0;
unsigned char fsm1_state_2_hdl()
printf(">> Fsm1 state 2 is running ... ");
printf(":: fsm1 next state is state 3 \n");
fsm_change_state(&fsm_1, FSM1_STATE_3);
return 0;
unsigned char fsm1_state_3_hdl()
printf(">> Fsm1 state 3 is running ... ");
printf(":: fsm1 next state is state 1 \n");
fsm_change_state(&fsm_1, FSM1_STATE_1);
return 0;
unsigned char fsm2_state_1_hdl()
printf(">> Fsm2 state 1 is running ... ");
printf(":: fsm2 next state is state 3 \n");
fsm_change_state(&fsm_2, FSM2_STATE_3);
return 0;
unsigned char fsm2_state_2_hdl()
printf(">> Fsm2 state 2 is running ... ");
printf(":: fsm2 next state is state 1 \n");
fsm_change_state(&fsm_2, FSM2_STATE_1);
return 0;
unsigned char fsm2_state_3_hdl()
printf(">> Fsm2 state 3 is running ... ");
printf(":: fsm2 next state is state 2 \n");
fsm_change_state(&fsm_2, FSM2_STATE_2);
return 0;
下面是运行结果:
可以看到这个框架还是非常不错的。
下面是源码,由于该框架的基础数据结构是侵入式链表,在时间片轮询法框架中有讲到,所以这里就不讲了。源码如下:
h文件:
#ifndef _FSM_H
#define _FSM_H
#include "list.h"
typedef struct fsm_object {
const char* name;
unsigned int fsm_state_id_base;
int curr_state;
int next_state;
ListObj fsm_list_head;
} FsmObj;
typedef struct fsm_state_object {
unsigned int id;
const char* belong_to;
int link_state;
unsigned char (*fsm_state_task_hdl)(void);
ListObj fsm_state_list;
} FsmStateObj;
void fsm_init(FsmObj* obj, const char* name, int init_state);
void fsm_change_state(FsmObj* obj, int next_state);
int fsm_state_get(FsmObj* obj);
unsigned char fsm_exec(FsmObj* obj);
void fsm_state_init(FsmStateObj* obj, int link_state, unsigned char (*fsm_state_task_hdl)(void));
void fsm_state_add(FsmObj* fsm_obj, FsmStateObj* state_obj);
void fsm_state_del(FsmStateObj* obj);
int fsm_state_link(FsmStateObj* obj);
const char* fsm_state_blelong_to(FsmStateObj* obj);
#endif
C文件
#include "fsm.h"
#include <cstdio>
void fsm_init(FsmObj* obj, const char* name, int init_state)
obj->name = name;
obj->curr_state = init_state;
obj->next_state = init_state;
obj->fsm_state_id_base = 0;
list_init(&obj->fsm_list_head);
unsigned char fsm_exec(FsmObj* obj)
ListObj* node;
FsmStateObj* state;
obj->curr_state = obj->next_state;
list_for_each(node, &obj->fsm_list_head)
state = list_entry(node, FsmStateObj, fsm_state_list);
if (state->link_state == obj->curr_state)
return state->fsm_state_task_hdl();
return 0;
void fsm_change_state(FsmObj* obj, int next_state)
obj->next_state = next_state;
void fsm_state_init(FsmStateObj* obj, int link_state, unsigned char (*fsm_state_task_hdl)(void))
obj->id = 0;
obj->link_state = link_state;
obj->fsm_state_task_hdl = fsm_state_task_hdl;
void fsm_state_add(FsmObj* fsm_obj, FsmStateObj* state_obj)
if (state_obj->id == 0)
fsm_obj->fsm_state_id_base++;
state_obj->id = fsm_obj->fsm_state_id_base;
state_obj->belong_to = fsm_obj->name;
list_insert_before(&fsm_obj->fsm_list_head, &state_obj->fsm_state_list);
void fsm_state_del(FsmStateObj* obj)
list_remove(&obj->fsm_state_list);
int fsm_state_get(FsmObj* obj)
return obj->curr_state;
int fsm_state_link(FsmStateObj* obj)
return obj->link_state;