我是靠谱客的博主 动人长颈鹿,最近开发中收集的这篇文章主要介绍C语言实现状态机(一),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

状态机原理

状态机有4个要素:

  • 现态:是指当前所处的状态。
  • 条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
  • 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  • 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了

举例:

图1

STATE1是现态,STATE2是次态,EVENT是条件,action是动作。当产生EVENT时,触发action,action执行完毕后从STATE1迁移到STATE2,此时,STATE2为现态。

在这个例子中,action只是一个瞬时执行的动作,它只在现态迁移到次态的过程中执行,当迁移完成后,action不再执行。

对以上状态机模型进行改进:

在这里插入图片描述

STATE1是现态,STATE2是次态,EVENT是条件,动作分为entry、do、exit三步,而且STATE1和STATE2都有动作entry、do、exit(注意:STATE1中的entry、do、exit和STATE2中的entry、do、exit不是同一个东西,可以将STATE1理解为一个结构体变量,而entry、do、exit是结构体的元素)。假设现在没有触发条件EVENT,现态STATE1持续执行do动作(注意:持续执行的意思不止执行一次),直到触发条件EVENT产生,此时STATE1不再执行do动作,而是执行exit动作,执行完后执行STATE2中的entry动作,并将现态更新为STATE2,STATE2持续执行do动作。

改进后的状态机模型有很多好处,举个例子:如在STATE1这个状态下对计数器COUNT进行计数,使用改进后的状态机模式可以这样做:
(1)在STATE1的entry里面对COUNT进行初始化
(2)在STATE1的do里面对COUNT进行计数
(3)在STATE1的exit里面对COUNT进行复位

C语言实现状态机

假设有状态机流程图如图:

在这里插入图片描述
定义枚举类型STATE_t表示状态机状态:

typedef enum{
	STATE1 = 0,
	STATE2,
	STATE3,
	STATE4,
}STATE_t; 

定义ACTION_MAP_t结构体类型,表示状态机状态属性:

typedef void (*STATE_ACTION)(void);	
typedef struct ACTION_MAP
{
	STATE_t 		stStateID;
	STATE_ACTION 	EnterAct;	
	STATE_ACTION 	RunningAct;	
	STATE_ACTION 	ExitAct;
}ACTION_MAP_t;

建立“动作”表:

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("state1_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 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},
};

定义枚举类型EVENT_t表示事件:

typedef enum
{
	EVENT1 = 0,
	EVENT2,
	EVENT3,
	EVENT4,
	EVENT5,
	
	EVENT_MAP_END
}EVENT_t;

注:定义EVENT_MAP_END的目的是为了方便查表。

定义EVENT_MAP_t结构体类型,表示事件表属性:

typedef struct EVENT_MAP
{
	EVENT_t	stEventID;
	STATE_t stCurState;
	STATE_t stNextState;
}EVENT_MAP_t;

根据状态机流程图建立事件表:

EVENT_MAP_t eventMap[] = 
{
	{EVENT1,	STATE1,	STATE2},
	{EVENT2,	STATE2,	STATE3},	
	{EVENT3,	STATE3,	STATE4},
	{EVENT4,	STATE4,	STATE1},
	{EVENT5,	STATE1,	STATE4},

	{EVENT_MAP_END,	0,	0},		
};

定义状态机结构体类型:

typedef struct FSM
{
	STATE_t stCurState;
	STATE_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)
{
	pFsm->stCurState = 0;
	pFsm->stNextState = EVENT_MAP_END;
	pFsm->pEventMap = pEventMap;
	pFsm->pActionMap = pActionMap;
}

定义状态机转换函数:

void fsm_state_transfer(FSM_t* pFsm, EVENT_t stEventID)
{
	uint8_t i = 0;
	
	for(i=0; pFsm->pEventMap[i].stEventID<EVENT_MAP_END; i++)
	{
		if((stEventID == pFsm->pEventMap[i].stEventID) 
			&& (pFsm->stCurState == pFsm->pEventMap[i].stCurState))
		{
			pFsm->stNextState = pFsm->pEventMap[i].stNextState;
			
			return;
		}
	}	
}

定义动作执行函数:

void action_perfrom(FSM_t* pFsm)
{
	if(EVENT_MAP_END != pFsm->stNextState)
	{
		pFsm->pActionMap[pFsm->stCurState].ExitAct();
		pFsm->pActionMap[pFsm->stNextState].EnterAct();
		
		pFsm->stCurState = pFsm->stNextState;
		pFsm->stNextState = EVENT_MAP_END;
	}
	else
	{
		pFsm->pActionMap[pFsm->stCurState].RunningAct();
	}
}

测试:

int main(void)
{
	int i = 0;		
	FSM_t stFsmWeather;	//定义状态机
	
	fsm_init(&stFsmWeather,eventMap,actionMap);	//注册状态机
	
	while(1)
	{
		usleep(10);
		printf("i = %dn",i++);
		
		action_perfrom(&stFsmWeather);
		
		//利用i产生EVENT1~EVENT5
		if(0 == (i%11))
		{
			fsm_state_transfer(&stFsmWeather,EVENT1);
		}
		
		if(0 == (i%31))
		{
			fsm_state_transfer(&stFsmWeather,EVENT2);
		}
		
		if(0 == (i%74))
		{
			fsm_state_transfer(&stFsmWeather,EVENT3);
		}
		
		if(0 == (i%13))
		{
			fsm_state_transfer(&stFsmWeather,EVENT4);
		}	
		
		if(0 == (i%19))
		{
			fsm_state_transfer(&stFsmWeather,EVENT5);
		}
	}
	
	return 0;
}

https://blog.csdn.net/qq_36969264/article/details/122365696

最后

以上就是动人长颈鹿为你收集整理的C语言实现状态机(一)的全部内容,希望文章能够帮你解决C语言实现状态机(一)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部