一.状态机。
状态机的实现的三个要素:状态、事件、响应。
二.c语言代码实现
1.一般实现方式
if...else : 大堆if else, 一个函数写很长很长......
swich...case : 搞一大堆一个函数写很长很长......
如果说时间比较少(5个以内),还是基本可控的,还是可以用的。
但如果事件超过十个,再加上超过三个状态的切换,那代码逻辑看起来就会非常混乱
2.表驱动法
这种方式把状态和事件进行模块化分离,同时用一张表再连接起来,就从根本上解决了这个问题,而且时间和状态也多越能发挥出优势来,
几乎可以说是没有上限限制。
代码实现:
这里我们首先定义一个结构体如下:
typedef struct {
State curState;//当前状态
EventID eventId;//事件ID
State nextState;//下个状态
Action action;//具体表现
}
StateTransform;
我们假设有3种状态,这里可以随意增加,状态枚举如下:
typedef enum {
state_1=1,
state_2,
state_3}
State;
我们假设有5个事件,也可以随意增加,事件ID枚举如下:
typedef enum{
event_1=1,
event_2,
event_3,
event_4,
event_5
}EventID;
将其封装起来在StateMachine中:
typedef struct{
State state;
int transNum;
StateTransform* transform;
}StateMachine;
具体流程:当前状态-有事件触发-跳到下个状态-具体表现,重构代码
StateTransform* findTranss(StateMachine* pSM, const EventID evt){
int i;
for (i = 0; i < pSM->transNum; i++) {
if ((pSM->transform[i].curState == pSM->state) && (pSM->transform[i].eventId == evt)) {
return &pSM->transform[i];
}
}
return NULL;
}
状态机实现如下:
StateTransformm* pTrans;
pTrans = findTrans(pSM, evt);
if (pTrans == NULL)
{
xil_printf( "CurState= %s Do not process enent: %s\r\n", pSM->state,evt);
return;
}
pSM->state = pTrans->nextState;
Action act = pTrans->action;
if (act == NULL) {
xil_printf( "change state to %s. No action\r\n",pSM->state);
return;
}
act(&evt);
最后我模拟一些随机事件,我们只需要弄清楚事件ID,状态切换,具体表现就可以了,在代码中就是填写 stateTran[] 这个表,一旦有增减事件,状态等等,
也不需要再去使用switch/case,特费脑,其代码如下:
int run()
{
StateMachine stateMachine;
stateMachine.state = state_1;
stateMachine.transNum = 7;
StateTransform stateTran[] = {
{state_1,event_3,state_2,f121},
{state_1,event_4,state_2,NULL},
{state_2,event_1,state_3,f231},
{state_2,event_4,state_2,f221},
{state_3,event_2,state_1,f311},
{state_3,event_3,state_2,f321},
{state_3,event_5,state_3,f331}
};
stateMachine.transform = stateTran;
EventID inputEvent[15] = { event_1, event_2, event_3, event_4, event_5,
event_1, event_2, event_3, event_4, event_5,
event_1, event_2, event_3, event_4, event_5 };
int i;
for (i = 0; i < 15; i++) {
runStateMachine(&stateMachine, inputEvent[i]);
}
return 0;
}