Zorb Framework是一个基于面向对象的思想来搭建一个轻量级的嵌入式框架。
本次分享的是Zorb Framework的状态机的实现。
中小型嵌入式程序说白了就是由各种状态机组成,因此掌握了如何构建状态机,开发嵌入式应用程序可以说是手到拈来。
简单的状态机可以用Switch-Case实现,但复杂一点的状态机再继续使用Switch-Case的话,层次会变得比较乱,不方便维护。因此我们为Zorb Framework提供了函数式状态机。
状态机的功能
我们先来看看要实现的状态机提供什么功能:
初步要提供的功能如下:
1、可以设置初始状态
2、可以进行状态转换
3、可以进行信号调度
4、最好可以在进入和离开状态的时候可以做一些自定义的事情
5、最好可以有子状态机
因此,初步设计的数据结构如下:
/*状态机结构*/ struct_Fsm { uint8_tLevel;/*嵌套层数,根状态机层数为1,子状态机层数自增*/ /*注:严禁递归嵌套和环形嵌套*/ List*ChildList;/*子状态机列表*/ Fsm*Owner;/*父状态机*/ IFsmStateOwnerTriggerState;/*当父状态机为设定状态时,才触发当前状态机*/ /*若不设定,则当执行完父状态机,立即运行子状态机*/ IFsmStateCurrentState;/*当前状态*/ boolIsRunning;/*是否正在运行(默认关)*/ /*设置初始状态*/ void(*SetInitialState)(Fsm*constpFsm,IFsmStateinitialState); /*运行当前状态机*/ bool(*Run)(Fsm*constpFsm); /*运行当前状态机和子状态机*/ bool(*RunAll)(Fsm*constpFsm); /*停止当前状态机*/ bool(*Stop)(Fsm*constpFsm); /*停止当前状态机和子状态机*/ bool(*StopAll)(Fsm*constpFsm); /*释放当前状态机*/ bool(*Dispose)(Fsm*constpFsm); /*释放当前状态机和子状态机*/ bool(*DisposeAll)(Fsm*constpFsm); /*添加子状态机*/ bool(*AddChild)(Fsm*constpFsm,Fsm*constpChildFsm); /*移除子状态机(不释放空间)*/ bool(*RemoveChild)(Fsm*constpFsm,Fsm*constpChildFsm); /*调度状态机*/ bool(*Dispatch)(Fsm*constpFsm,FsmSignalconstsignal); /*状态转移*/ void(*Transfer)(Fsm*constpFsm,IFsmStatenextState); /*状态转移(触发转出和转入事件)*/ void(*TransferWithEvent)(Fsm*constpFsm,IFsmStatenextState); };
关于信号,Zorb Framework做了以下定义:
/*状态机信号0-31保留,用户信号在32以后定义*/ enum{ FSM_NULL_SIG=0, FSM_ENTER_SIG, FSM_EXIT_SIG, FSM_USER_SIG_START=32 /*用户信号请在用户文件定义,不允许在此定义*/ };
创建状态机:
boolFsm_create(Fsm**ppFsm) { Fsm*pFsm; ZF_ASSERT(ppFsm!=(Fsm**)0) /*分配空间*/ pFsm=ZF_MALLOC(sizeof(Fsm)); if(pFsm==NULL) { ZF_DEBUG(LOG_E,"mallocfsmspaceerror "); returnfalse; } /*初始化成员*/ pFsm->Level=1; pFsm->ChildList=NULL; pFsm->Owner=NULL; pFsm->OwnerTriggerState=NULL; pFsm->CurrentState=NULL; pFsm->IsRunning=false; /*初始化方法*/ pFsm->SetInitialState=Fsm_setInitialState; pFsm->Run=Fsm_run; pFsm->RunAll=Fsm_runAll; pFsm->Stop=Fsm_stop; pFsm->StopAll=Fsm_stopAll; pFsm->Dispose=Fsm_dispose; pFsm->DisposeAll=Fsm_disposeAll; pFsm->AddChild=Fsm_addChild; pFsm->RemoveChild=Fsm_removeChild; pFsm->Dispatch=Fsm_dispatch; pFsm->Transfer=Fsm_transfer; pFsm->TransferWithEvent=Fsm_transferWithEvent; /*输出*/ *ppFsm=pFsm; returntrue; }
调度状态机:
/****************************************************************************** *描述:调度状态机 *参数:(in)-pFsm 状态机指针 *(in)-signal调度信号 *返回:-true 成功 *-false失败 ******************************************************************************/ boolFsm_dispatch(Fsm*constpFsm,FsmSignalconstsignal) { /*返回结果*/ boolres=false; ZF_ASSERT(pFsm!=(Fsm*)0) if(pFsm->IsRunning) { if(pFsm->ChildList!=NULL&&pFsm->ChildList->Count>0) { uint32_ti; Fsm*pChildFsm; for(i=0;i< pFsm->ChildList->Count;i++) { pChildFsm=(Fsm*)pFsm->ChildList ->GetElementDataAt(pFsm->ChildList,i); if(pChildFsm!=NULL) { Fsm_dispatch(pChildFsm,signal); } } } if(pFsm->CurrentState!=NULL) { /*1:根状态机时调度 2:没设置触发状态时调度 3:正在触发状态时调度 */ if(pFsm->Owner==NULL||pFsm->OwnerTriggerState==NULL ||pFsm->OwnerTriggerState==pFsm->Owner->CurrentState) { pFsm->CurrentState(pFsm,signal); res=true; } } } returnres; }
篇幅有限,其它接口实现可阅读:
https://github.com/54zorb/Zorb-Framework
状态机测试
/** ***************************************************************************** *@fileapp_fsm.c *@authorZorb *@versionV1.0.0 *@date2018-06-28 *@brief状态机测试的实现 ***************************************************************************** *@history * *1.Date:2018-06-28 *Author:Zorb *Modification:建立文件 * ***************************************************************************** */ #include"app_fsm.h" #include"zf_includes.h" /*定义用户信号*/ enumSignal { SAY_HELLO=FSM_USER_SIG_START }; Fsm*pFsm;/*父状态机*/ Fsm*pFsmSon;/*子状态机*/ /*父状态机状态1*/ staticvoidState1(Fsm*constpFsm,FsmSignalconstfsmSignal); /*父状态机状态2*/ staticvoidState2(Fsm*constpFsm,FsmSignalconstfsmSignal); /****************************************************************************** *描述:父状态机状态1 *参数:-pFsm 当前状态机 *-fsmSignal当前调度信号 *返回:无 ******************************************************************************/ staticvoidState1(Fsm*constpFsm,FsmSignalconstfsmSignal) { switch(fsmSignal) { caseFSM_ENTER_SIG: ZF_DEBUG(LOG_D,"enterstate1 "); break; caseFSM_EXIT_SIG: ZF_DEBUG(LOG_D,"exitstate1 "); break; caseSAY_HELLO: ZF_DEBUG(LOG_D,"state1sayhello,andwanttobestate2 "); /*切换到状态2*/ pFsm->TransferWithEvent(pFsm,State2); break; } } /****************************************************************************** *描述:父状态机状态2 *参数:-pFsm 当前状态机 *-fsmSignal当前调度信号 *返回:无 ******************************************************************************/ staticvoidState2(Fsm*constpFsm,FsmSignalconstfsmSignal) { switch(fsmSignal) { caseFSM_ENTER_SIG: ZF_DEBUG(LOG_D,"enterstate2 "); break; caseFSM_EXIT_SIG: ZF_DEBUG(LOG_D,"exitstate2 "); break; caseSAY_HELLO: ZF_DEBUG(LOG_D,"state2sayhello,andwanttobestate1 "); /*切换到状态1*/ pFsm->TransferWithEvent(pFsm,State1); break; } } /****************************************************************************** *描述:子状态机状态 *参数:-pFsm 当前状态机 *-fsmSignal当前调度信号 *返回:无 ******************************************************************************/ staticvoidSonState(Fsm*constpFsm,FsmSignalconstfsmSignal) { switch(fsmSignal) { caseSAY_HELLO: ZF_DEBUG(LOG_D,"sonsayhelloonlyinstate2 "); break; } } /****************************************************************************** *描述:任务初始化 *参数:无 *返回:无 ******************************************************************************/ voidApp_Fsm_init(void) { /*创建父状态机,并设初始状态*/ Fsm_create(&pFsm); pFsm->SetInitialState(pFsm,State1); /*创建子状态机,并设初始状态*/ Fsm_create(&pFsmSon); pFsmSon->SetInitialState(pFsmSon,SonState); /*设置子状态机仅在父状态State2触发*/ pFsmSon->OwnerTriggerState=State2; /*把子状态机添加到父状态机*/ pFsm->AddChild(pFsm,pFsmSon); /*运行状态机*/ pFsm->RunAll(pFsm); } /****************************************************************************** *描述:任务程序 *参数:无 *返回:无 ******************************************************************************/ voidApp_Fsm_process(void) { ZF_DELAY_MS(1000); /*每1000ms调度状态机,发送SAY_HELLO信号*/ pFsm->Dispatch(pFsm,SAY_HELLO); } /********************************ENDOFFILE********************************/
结果:
-
单片机
+关注
关注
6035文章
44554浏览量
634590 -
嵌入式
+关注
关注
5082文章
19104浏览量
304780 -
Switch
+关注
关注
1文章
533浏览量
58219 -
状态机
+关注
关注
2文章
492浏览量
27527
原文标题:单片机最好用的程序框架,莫过于状态机了
文章出处:【微信号:玩转嵌入式,微信公众号:玩转嵌入式】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论