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_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("state1_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 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 = %d\n",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

  • 37
    点赞
  • 310
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
以下是一个使用C语言实现的简单状态机代码示例: ```c #include <stdio.h> // 状态枚举 typedef enum { STATE_A, STATE_B, STATE_C } State; // 事件枚举 typedef enum { EVENT_1, EVENT_2, EVENT_3 } Event; // 状态机结构体 typedef struct { State current_state; } StateMachine; // 状态处理函数 State handle_event(StateMachine *machine, Event event) { switch (machine->current_state) { case STATE_A: if (event == EVENT_1) { printf("State A handles event 1\n"); return STATE_B; } else if (event == EVENT_2) { printf("State A handles event 2\n"); return STATE_C; } else { printf("State A ignores the event\n"); return STATE_A; } case STATE_B: if (event == EVENT_2) { printf("State B handles event 2\n"); return STATE_A; } else { printf("State B ignores the event\n"); return STATE_B; } case STATE_C: if (event == EVENT_1) { printf("State C handles event 1\n"); return STATE_B; } else { printf("State C ignores the event\n"); return STATE_C; } default: printf("Invalid state\n"); return STATE_A; } } int main() { StateMachine machine; machine.current_state = STATE_A; machine.current_state = handle_event(&machine, EVENT_1); // 输出:State A handles event 1 machine.current_state = handle_event(&machine, EVENT_2); // 输出:State A handles event 2 machine.current_state = handle_event(&machine, EVENT_3); // 输出:State A ignores the event return 0; } ``` 这个示例中,我们使用枚举定义了状态和事件。`handle_event`函数根据当前状态和接收到的事件进行处理,并返回新的状态。`main`函数中创建了一个状态机实例,并通过调用`handle_event`函数触发事件,并更新当前状态。在每个状态处理函数中,你可以根据需要执行相应的逻辑操作。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值