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;iChildList->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********************************/
結果:
-
單片機
+關注
關注
6001文章
43973瀏覽量
620831 -
嵌入式
+關注
關注
4982文章
18281瀏覽量
288432 -
Switch
+關注
關注
1文章
514瀏覽量
57539 -
狀態機
+關注
關注
2文章
486瀏覽量
27165
原文標題:單片機最好用的程序框架,莫過于狀態機了
文章出處:【微信號:玩轉嵌入式,微信公眾號:玩轉嵌入式】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論