C语言实现状态机

前言

对于之前的一篇博客《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
                
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值