对于之前的一篇博客《C语言实现状态机》(链接:https://blog.csdn.net/qq_36969264/article/details/105865099?spm=1001.2014.3001.5501),看网友的留言,似乎对pFsm->stNextState 和 EVENT_MAP_END的比较有一些误解。
这里需要解释一下,当时这么写是为了省事,但后面看这么写确实很容易让人误解,所以这篇文章的目的是为了修改掉这个容易让人误解的地方,同时对该状态机做了一些优化。
typedef void (*STATE_ACTION)(void); typedef struct ACTION_MAP { uint8_t stStateID; STATE_ACTION EnterAct; STATE_ACTION RunningAct; STATE_ACTION ExitAct; }ACTION_MAP_t; typedef struct EVENT_MAP { uint8_t stEventID; uint8_t stCurState; uint8_t stNextState; }EVENT_MAP_t; typedef struct FSM { uint8_t u8Flag; uint8_t u8EventSum; uint8_t u8ActSum; uint8_t stCurState; uint8_t stNextState; ACTION_MAP_t *pActionMap; EVENT_MAP_t *pEventMap; }FSM_t;
注:状态机控制结构FSM_t的元素u8Flag用于替代pFsm->stNextState 和 EVENT_MAP_END的比较,以实现相同的功能。
2、状态机初始化函数初始化函数主要目的是为了将状态机与事件表、动作表关联起来。
void fsm_init(FSM_t* pFsm,EVENT_MAP_t* pEventMap,ACTION_MAP_t *pActionMap, uint8_t u8EventSum,uint8_t u8ActSum,uint8_t curState) { pFsm->u8Flag = 0; pFsm->stNextState = 0; pFsm->u8EventSum = u8EventSum; pFsm->u8ActSum = u8ActSum; pFsm->stCurState = curState; pFsm->pEventMap = pEventMap; pFsm->pActionMap = pActionMap; }3、状态机转换函数
该函数的主要功能是通过查找事件表,以确定是否要进行状态切换,如果需要进行状态切换,则将标志位u8Flag 置1。
void fsm_state_transfer(FSM_t* pFsm, uint8_t stEventID) { uint8_t i = 0; for(i=0; i4、状态机动作执行函数u8EventSum; i++) { if((stEventID == pFsm->pEventMap[i].stEventID) && (pFsm->stCurState == pFsm->pEventMap[i].stCurState)) { pFsm->stNextState = pFsm->pEventMap[i].stNextState; pFsm->u8Flag = 1; return; } } }
该函数为此状态机的精髓所在,一般的状态机在状态切换时只执行一次动作,或者周期执行同一动作。
而此状态机则在状态切换时执行当前动作的退出函数(一次),即ExitAct函数,实际应用当中可对该状态的一些变量进行清0,或者打印相关调试信息等;同时还会执行下一个状态的进入函数(一次),即EnterAct函数,实际应用当中可以对该状态的变量进行初始化等 *** 作。在状态切换完成后,还会周期执行RunningAct函数。
这里的ExitAct函数和EnterAct函数类似于C++的构造函数和析构函数。
uint8_t get_action_sum(FSM_t* pFsm,uint8_t u8ID) { int i = 0; for(i=0; iu8ActSum; i++) { if(u8ID == pFsm->pActionMap[i].stStateID) return i; } return -1; }
void action_perfrom(FSM_t* pFsm) { uint8_t u8CurID = -1, u8NextID = -1; if(0 != pFsm->u8Flag) { u8CurID = get_action_sum(pFsm,pFsm->stCurState); u8NextID = get_action_sum(pFsm,pFsm->stNextState); if((-1 != u8CurID) && (-1 != u8NextID)) { pFsm->pActionMap[u8CurID].ExitAct(); pFsm->pActionMap[u8NextID].EnterAct(); } else { pFsm->u8Flag = 0; printf("State transition failed! curState = %d, nextState = %dn",pFsm->stCurState,pFsm->stNextState); return; } pFsm->stCurState = pFsm->stNextState; pFsm->stNextState = -1; pFsm->u8Flag = 0; } else { u8CurID = get_action_sum(pFsm,pFsm->stCurState); if(-1 != u8CurID) pFsm->pActionMap[u8CurID].RunningAct(); } }二、如何使用状态机
这里还是使用之前的博客里状态机流程图为例:
1、以流程图为标准定义事件表数组eventMap就是对以上流程图的全部描述:
#define EVENT1 0 #define EVENT2 1 #define EVENT3 2 #define EVENT4 3 #define EVENT5 4 EVENT_MAP_t eventMap[] = { {EVENT1, STATE1, STATE2}, {EVENT2, STATE2, STATE3}, {EVENT3, STATE3, STATE4}, {EVENT4, STATE4, STATE1}, {EVENT5, STATE1, STATE4}, };2、定义动作表
#define STATE1 0 #define STATE2 1 #define STATE3 2 #define STATE4 3 ACTION_MAP_t actionMap[] = { {STATE1, state1_entry, state1_do, state1_exit}, {STATE2, state2_entry, state2_do, state2_exit}, {STATE3, state3_entry, state3_do, state3_exit}, {STATE4, state4_entry, state4_do, state4_exit}, };3、实现动作函数
这里的每个函数的内容可以根据实际情况进行填充。
void state1_entry(void) { printf("state1_entryn"); } void state1_do(void) { printf("state1_don"); } void state1_exit(void) { printf("state1_exitn"); } void state2_entry(void) { printf("state2_entryn"); } void state2_do(void) { printf("state2_don"); } void state2_exit(void) { printf("state2_exitn"); } void state3_entry(void) { printf("state3_entryn"); } void state3_do(void) { printf("state3_don"); } void state3_exit(void) { printf("state3_exitn"); } void state4_entry(void) { printf("state4_entryn"); } void state4_do(void) { printf("state4_don"); } void state4_exit(void) { printf("state4_exitn"); }4、实现表获取函数
ACTION_MAP_t* get_action_map(uint8_t *total) { *total = sizeof(actionMap)/sizeof(ACTION_MAP_t); return actionMap; } EVENT_MAP_t* get_event_map(uint8_t *total) { *total = sizeof(eventMap)/sizeof(EVENT_MAP_t); return eventMap; }5、测试
int main(void) { int i = 0; uint8_t u8ActNum = 0, u8EventNum = 0; FSM_t stFsm; ACTION_MAP_t* stActMap; EVENT_MAP_t* stEventMap; stActMap = get_action_map(&u8ActNum); stEventMap = get_event_map(&u8EventNum); fsm_init(&stFsm,stEventMap,stActMap,u8EventNum,u8ActNum,STATE1); while(1) { sleep(1); printf("i = %dn",i++); action_perfrom(&stFsm); if(1 == (i%10)) { fsm_state_transfer(&stFsm,EVENT1); } if(3 == (i%10)) { fsm_state_transfer(&stFsm,EVENT2); } if(5 == (i%10)) { fsm_state_transfer(&stFsm,EVENT3); } if(7 == (i%10)) { fsm_state_transfer(&stFsm,EVENT4); } if(9 == (i%10)) { fsm_state_transfer(&stFsm,EVENT5); } } return 0; }
调试信息如下:
三、附上代码 fsm.c#includefsm.h#include "fsm.h" void fsm_init(FSM_t* pFsm,EVENT_MAP_t* pEventMap,ACTION_MAP_t *pActionMap, uint8_t u8EventSum,uint8_t u8ActSum,uint8_t curState) { pFsm->u8Flag = 0; pFsm->stNextState = 0; pFsm->u8EventSum = u8EventSum; pFsm->u8ActSum = u8ActSum; pFsm->stCurState = curState; pFsm->pEventMap = pEventMap; pFsm->pActionMap = pActionMap; } void fsm_state_transfer(FSM_t* pFsm, uint8_t stEventID) { uint8_t i = 0; for(i=0; i u8EventSum; i++) { if((stEventID == pFsm->pEventMap[i].stEventID) && (pFsm->stCurState == pFsm->pEventMap[i].stCurState)) { pFsm->stNextState = pFsm->pEventMap[i].stNextState; pFsm->u8Flag = 1; return; } } } uint8_t get_action_sum(FSM_t* pFsm,uint8_t u8ID) { int i = 0; for(i=0; i u8ActSum; i++) { if(u8ID == pFsm->pActionMap[i].stStateID) return i; } return -1; } void action_perfrom(FSM_t* pFsm) { uint8_t u8CurID = -1, u8NextID = -1; if(0 != pFsm->u8Flag) { u8CurID = get_action_sum(pFsm,pFsm->stCurState); u8NextID = get_action_sum(pFsm,pFsm->stNextState); if((-1 != u8CurID) && (-1 != u8NextID)) { pFsm->pActionMap[u8CurID].ExitAct(); pFsm->pActionMap[u8NextID].EnterAct(); } else { pFsm->u8Flag = 0; printf("State transition failed! curState = %d, nextState = %dn",pFsm->stCurState,pFsm->stNextState); return; } pFsm->stCurState = pFsm->stNextState; pFsm->stNextState = -1; pFsm->u8Flag = 0; } else { u8CurID = get_action_sum(pFsm,pFsm->stCurState); if(-1 != u8CurID) pFsm->pActionMap[u8CurID].RunningAct(); } }
#ifndef FSM_H #define FSM_H #include "common.h" typedef void (*STATE_ACTION)(void); typedef struct ACTION_MAP { uint8_t stStateID; STATE_ACTION EnterAct; STATE_ACTION RunningAct; STATE_ACTION ExitAct; }ACTION_MAP_t; typedef struct EVENT_MAP { uint8_t stEventID; uint8_t stCurState; uint8_t stNextState; }EVENT_MAP_t; typedef struct FSM { uint8_t u8Flag; uint8_t u8EventSum; uint8_t u8ActSum; uint8_t stCurState; uint8_t stNextState; ACTION_MAP_t *pActionMap; EVENT_MAP_t *pEventMap; }FSM_t; void fsm_init(FSM_t* pFsm,EVENT_MAP_t* pEventMap,ACTION_MAP_t *pActionMap, uint8_t u8EventSum,uint8_t u8ActSum,uint8_t curState); void fsm_state_transfer(FSM_t* pFsm, uint8_t stEventID); void action_perfrom(FSM_t* pFsm); #endifaction.c
#includeaction.h#include "action.h" void state1_entry(void); void state1_do(void); void state1_exit(void); void state2_entry(void); void state2_do(void); void state2_exit(void); void state3_entry(void); void state3_do(void); void state3_exit(void); void state4_entry(void); void state4_do(void); void state4_exit(void); ACTION_MAP_t actionMap[] = { {STATE1, state1_entry, state1_do, state1_exit}, {STATE2, state2_entry, state2_do, state2_exit}, {STATE3, state3_entry, state3_do, state3_exit}, {STATE4, state4_entry, state4_do, state4_exit}, }; void state1_entry(void) { printf("state1_entryn"); } void state1_do(void) { printf("state1_don"); } void state1_exit(void) { printf("state1_exitn"); } void state2_entry(void) { printf("state2_entryn"); } void state2_do(void) { printf("state2_don"); } void state2_exit(void) { printf("state2_exitn"); } void state3_entry(void) { printf("state3_entryn"); } void state3_do(void) { printf("state3_don"); } void state3_exit(void) { printf("state3_exitn"); } void state4_entry(void) { printf("state4_entryn"); } void state4_do(void) { printf("state4_don"); } void state4_exit(void) { printf("state4_exitn"); } ACTION_MAP_t* get_action_map(uint8_t *total) { *total = sizeof(actionMap)/sizeof(ACTION_MAP_t); return actionMap; }
#ifndef ACTION_H #define ACTION_H #include "common.h" #include "fsm.h" #define STATE1 0 #define STATE2 1 #define STATE3 2 #define STATE4 3 ACTION_MAP_t* get_action_map(uint8_t *total); #endifevent.c
#include "event.h" EVENT_MAP_t eventMap[] = { {EVENT1, STATE1, STATE2}, {EVENT2, STATE2, STATE3}, {EVENT3, STATE3, STATE4}, {EVENT4, STATE4, STATE1}, {EVENT5, STATE1, STATE4}, }; EVENT_MAP_t* get_event_map(uint8_t *total) { *total = sizeof(eventMap)/sizeof(EVENT_MAP_t); return eventMap; }event.h
#ifndef EVENT_H #define EVENT_H #include "fsm.h" #include "common.h" #include "action.h" #define EVENT1 0 #define EVENT2 1 #define EVENT3 2 #define EVENT4 3 #define EVENT5 4 EVENT_MAP_t* get_event_map(uint8_t* total); #endifcommon.h
#ifndef COMMON_H #define COMMON_H typedef unsigned char uint8_t; #endifmain.c
int main(void) { int i = 0; uint8_t u8ActNum = 0, u8EventNum = 0; FSM_t stFsm; ACTION_MAP_t* stActMap; EVENT_MAP_t* stEventMap; stActMap = get_action_map(&u8ActNum); stEventMap = get_event_map(&u8EventNum); fsm_init(&stFsm,stEventMap,stActMap,u8EventNum,u8ActNum,STATE1); while(1) { sleep(1); printf("i = %dn",i++); action_perfrom(&stFsm); if(1 == (i%10)) { fsm_state_transfer(&stFsm,EVENT1); } if(3 == (i%10)) { fsm_state_transfer(&stFsm,EVENT2); } if(5 == (i%10)) { fsm_state_transfer(&stFsm,EVENT3); } if(7 == (i%10)) { fsm_state_transfer(&stFsm,EVENT4); } if(9 == (i%10)) { fsm_state_transfer(&stFsm,EVENT5); } } return 0; }Makefile
objects = fsm.o action.o event.o main:*.o cc -o $@ $^ *.o:*.c cc -c $^ clean: rm *.o -rf rm main -rf
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)