概述
状态机原理
状态机有4个要素:
- 现态:是指当前所处的状态。
- 条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
- 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
- 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了
举例:
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语言实现状态机(一)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复