对于之前的一篇博客《C语言实现状态机》(链接:https://blog.csdn.net/qq_36969264/article/details/105865099?spm=1001.2014.3001.5501),看网友的留言,似乎对pFsm->stNextState 和 EVENT_MAP_END的比较有一些误解。
这里需要解释一下,当时这么写是为了省事,但后面看这么写确实很容易让人误解,所以这篇文章的目的是为了修改掉这个容易让人误解的地方,同时对该状态机做了一些优化。
一、实现状态机的基本函数
1、定义相关结构体
typedef void (*STATE_ACTION)(void);
typedef struct ACTION_MAP
{
uint8_t stStateID;
STATE_ACTION EnterAct;
STATE_ACTION RunningAct;
STATE_ACTION ExitAct;
}ACTION_MAP_t; /* 动作action表描述 */
typedef struct EVENT_MAP
{
uint8_t stEventID;
uint8_t stCurState;
uint8_t stNextState;
}EVENT_MAP_t; /* 事件event表描述 */
typedef struct FSM
{
uint8_t u8Flag; /* 状态切换标志位,1表示要进行状态切换 */
uint8_t u8EventSum; /* 事件event总数 */
uint8_t u8ActSum; /* 动作action总数 */
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; i<pFsm->u8EventSum; i++)
{
if((stEventID == pFsm->pEventMap[i].stEventID)
&& (pFsm->stCurState == pFsm->pEventMap[i].stCurState))
{
pFsm->stNextState = pFsm->pEventMap[i].stNextState;
pFsm->u8Flag = 1;
return;
}
}
}
4、状态机动作执行函数
该函数为此状态机的精髓所在,一般的状态机在状态切换时只执行一次动作,或者周期执行同一动作。
而此状态机则在状态切换时执行当前动作的退出函数(一次),即ExitAct函数,实际应用当中可对该状态的一些变量进行清0,或者打印相关调试信息等;同时还会执行下一个状态的进入函数(一次),即EnterAct函数,实际应用当中可以对该状态的变量进行初始化等操作。在状态切换完成后,还会周期执行RunningAct函数。
这里的ExitAct函数和EnterAct函数类似于C++的构造函数和析构函数。
uint8_t get_action_sum(FSM_t* pFsm,uint8_t u8ID)
{
int i = 0;
for(i=0; i<pFsm->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) /* 标志位不为0表示要进行状态切换 */
{
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 = %d\n",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();/* 标志位为0不进行状态切换,执行当前状态的do动作 */
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
二、如何使用状态机
这里还是使用之前的博客里状态机流程图为例:
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},
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3、实现动作函数
这里的每个函数的内容可以根据实际情况进行填充。
void state1_entry(void)
{
printf("state1_entry\n");
}
void state1_do(void)
{
printf("state1_do\n");
}
void state1_exit(void)
{
printf("state1_exit\n");
}
void state2_entry(void)
{
printf("state2_entry\n");
}
void state2_do(void)
{
printf("state2_do\n");
}
void state2_exit(void)
{
printf("state2_exit\n");
}
void state3_entry(void)
{
printf("state3_entry\n");
}
void state3_do(void)
{
printf("state3_do\n");
}
void state3_exit(void)
{
printf("state3_exit\n");
}
void state4_entry(void)
{
printf("state4_entry\n");
}
void state4_do(void)
{
printf("state4_do\n");
}
void state4_exit(void)
{
printf("state4_exit\n");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
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 = %d\n",i++);
action_perfrom(&stFsm);
/* 利用i产生EVENT1~EVENT5 */
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
调试信息如下:
三、附上代码
fsm.c
#include <stdio.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<pFsm->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<pFsm->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) /* 标志位不为0表示要进行状态切换 */
{
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 = %d\n",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();/* 标志位为0不进行状态切换,执行当前状态的do动作 */
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
fsm.h
#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; /* 动作action表描述 */
typedef struct EVENT_MAP
{
uint8_t stEventID;
uint8_t stCurState;
uint8_t stNextState;
}EVENT_MAP_t; /* 事件event表描述 */
typedef struct FSM
{
uint8_t u8Flag; /* 状态切换标志位,1表示要进行状态切换 */
uint8_t u8EventSum; /* 事件event总数 */
uint8_t u8ActSum; /* 动作action总数 */
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);
#endif
action.c
#include <stdio.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_entry\n");
}
void state1_do(void)
{
printf("state1_do\n");
}
void state1_exit(void)
{
printf("state1_exit\n");
}
void state2_entry(void)
{
printf("state2_entry\n");
}
void state2_do(void)
{
printf("state2_do\n");
}
void state2_exit(void)
{
printf("state2_exit\n");
}
void state3_entry(void)
{
printf("state3_entry\n");
}
void state3_do(void)
{
printf("state3_do\n");
}
void state3_exit(void)
{
printf("state3_exit\n");
}
void state4_entry(void)
{
printf("state4_entry\n");
}
void state4_do(void)
{
printf("state4_do\n");
}
void state4_exit(void)
{
printf("state4_exit\n");
}
ACTION_MAP_t* get_action_map(uint8_t *total)
{
*total = sizeof(actionMap)/sizeof(ACTION_MAP_t);
return actionMap;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
action.h
#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);
#endif
event.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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
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);
#endif
common.h
#ifndef COMMON_H
#define COMMON_H
typedef unsigned char uint8_t;
#endif
main.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 = %d\n",i++);
action_perfrom(&stFsm);
/* 利用i产生EVENT1~EVENT5 */
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
Makefile
objects = fsm.o action.o event.o main:*.o cc -o $@ $^ *.o:*.c cc -c $^ clean: rm *.o -rf rm main -rf