您的位置:首页 > 其它

有限状态机——The finite state machine

2013-10-23 23:11 591 查看
依据状态之间是否有包含关系,分以下两种

(1)常规状态机。状态机中的所有状态是不相交的、互斥的。

(2)层次状态机。状态机中的状态之间要么是互斥的,要么是真包含的,可以用树性结构来描述这些状态集,包含其它状态的状态称为枝节点,不包含其它状态的状态称为叶节点,为方便单树描述,总是设计一个状态包含所有的状态节点,称为根节点。状态机的状态只能停留在叶节点,而不能停留在枝节点,每个枝节点需要指定一个子节点为它的默认子节点,以便状态机进入枝节点的时候能够停留到叶节点。

一般都用switch/case if/else方式实现。在少量状态(3个及其以下)的时候,不需要引入专门的状态机模块。

常规状态机模块实现涉及到的结构由上而下为:

顶层结构是状态机:当前状态id,缺省操作,状态表,

状态表:状态数组

状态结构:状态id,状态名,进入操作,退出操作,缺省操作,状态事件表(数组)

状态事件结构:操作,事件,下一状态的id

***************************************************************************************

从代码易读及美观角度来说,建议用switch/case来实现。

从经验来看,在一些稍大的程序设计中一般都会有状态机的实现,特别是在分层实现,协议栈实现,编解码方面。

下面通过一个简单的例子来看下。这个例子是zigbee精简协议栈实现中的【这里只讲APS层的有限状态机,这是开放源代码的,对于该协议总体上是分层来实现的,每一次层都有状态机来进行实际的数据业务处理】。

(1)定义各状态

typedef enum _APS_STATE_ENUM

{

APS_STATE_IDLE,

APS_STATE_COMMAND_START,

APS_STATE_GENERIC_TX_WAIT,

APS_STATE_NWK_PASSTHRU_WAIT,

APS_STATE_INDIRECT_GETDST,

APS_STATE_INDIRECT_TX,

#ifdef LRWPAN_COORDINATOR

APS_STATE_INJECT_INDIRECT,

#endif

APS_STATE_ACK_SEND_START,

APS_STATE_INDIRECT_TX_WAIT,

APS_STATE_INJECT_LOOPBACK,

APS_STATE_INDIRECT_LOOPBACK

} APS_STATE_ENUM;

(2)设计有限状态机函数

void apsFSM(void)

{

apsFSM_start://状态机入口
switch (apsState) //全局变量,指示当前状态

{

case APS_STATE_IDLE:

if (aps_pib.flags.bits.ackSendPending)

{

apsState = APS_STATE_ACK_SEND_START;//状态转换

goto apsFSM_start;

}

break;

case APS_STATE_ACK_SEND_START:

if (phyTxLocked())

{

break;

}

//send an ACK

//lock the TX buffer

phyGrabTxLock();

//we are now ready

apsFormatAck();

phy_pib.currentTxFlen = 0; //set frame length to zero, build from scratch

apsTxData(TRUE);

//data sent, release the RX buffer, will let RX FSM resume

aps_pib.flags.bits.ackSendPending = 0;

apsState = APS_STATE_GENERIC_TX_WAIT;
break;
case APS_STATE_GENERIC_TX_WAIT:

if (!apsTXIdle())

{

break;

}

//TX is finished, copy status

a_aps_service.status = apsTxFSM_status;

//release the TX buffer lock before exiting.

phyReleaseTxLock();

apsState = APS_STATE_IDLE;

if (aps_pib.flags.bits.indirectPending)

{

//have used this state to wait for finishing sending an

//ACK back to the source of an indirect transmit. Now

//finish resolving the indirect

goto apsFSM_start;

}

break;
case APS_STATE_NWK_PASSTHRU_WAIT:

//for split-phase passthrus

if (nwkBusy())

{

break;

}

a_aps_service.status = a_nwk_service.status;

apsState = APS_STATE_IDLE;

break;
case APS_STATE_INJECT_LOOPBACK:

//wait for RX to become idle

if (apsRxState != APS_RXSTATE_IDLE)

{

break;

}

//inject packet into RX FSM

apsInjectPacket(FALSE);

aps_pib.flags.bits.IsUsrBufferFree = 1;

apsState = APS_STATE_IDLE;

goto apsFSM_start;

default:

break;

}

}

(3)大致结构:状态机入口,状态转换,状态机退出
从这个函数实现,我们可以简单了解有限状态机的实现过程。当程序的实现有多个状态的时候,也就是要根据不同的状态做不同的事情的时候,可以考虑把某个操作过程拆分为几个步骤【很多时候这是必须的】,对应状态机操作的几个不同状态。多数情况下,这些状态是多个操作可以共用的。一般的状态机函数都会提供一个状态退出操作,每个状态操作可以根据条件来判断是要退出,还是要转换进行下一个状态的。

状态机是程序设计时的一种思想,尤如设计模式,只有在恰当的时候用来才回体现出其价值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐