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********************************/
结果:

-
单片机
+关注
关注
6074文章
45340浏览量
663562 -
嵌入式
+关注
关注
5186文章
20146浏览量
328837 -
Switch
+关注
关注
1文章
541浏览量
61341 -
状态机
+关注
关注
2文章
497浏览量
28851
原文标题:单片机最好用的程序框架,莫过于状态机了
文章出处:【微信号:玩转嵌入式,微信公众号:玩转嵌入式】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
嵌入式状态机的几种大牛才懂的操作

嵌入式框架Zorb Framework状态机的实现
评论