本文介绍CANopen中的NMT状态机,及在CanFestival中的实现过程。
一、NMT状态机
CANopen中状态机包含4个状态:Initialisation、Pre-operational、Operational和Stopped。
相互之间的关系和跳转条件如下:
其中,从Initialisation到Pre-operational的跳转一般是从节点自动完成的,其它跳转一般由主节点发送NMT帧触发。
二、NMT帧格式
NMT帧的ID为0,NodeID为需要控制的节点号,若要控制所有节点则NodeID为0。
其中cs(Command Specifier)在def.h中定义:
/* NMT Command Specifier, sent by master to change a slave state */
/* ------------------------------------------------------------- */
/* Should not be modified */
#define NMT_Start_Node 0x01
#define NMT_Stop_Node 0x02
#define NMT_Enter_PreOperational 0x80
#define NMT_Reset_Node 0x81
#define NMT_Reset_Comunication 0x82
三、CanFestival中的实现
CanFestival关于NMT的代码主要在nmtMaster.c、nmtSlave.c和States.c中,以从节点为例,当收到NMT帧时的处理流程为:
canDispatch() -> proceedNMTstateChange() :
void proceedNMTstateChange(CO_Data* d, Message *m)
{
......
if( ( (*m).data[1] == 0 ) || ( (*m).data[1] == *d->bDeviceNodeId ) ){
switch( (*m).data[0]){ /* command specifier (cs) */
case NMT_Start_Node:
if ( (d->nodeState == Pre_operational) || (d->nodeState == Stopped) )
setState(d,Operational);
break;
case NMT_Stop_Node:
if ( d->nodeState == Pre_operational ||
d->nodeState == Operational )
setState(d,Stopped);
case NMT_Enter_PreOperational:
if ( d->nodeState == Operational ||
d->nodeState == Stopped )
setState(d,Pre_operational);
break;
case NMT_Reset_Node:
setState(d,Initialisation);
case NMT_Reset_Comunication:
setState(d,Initialisation);
break;
}/* end switch */
}/* end if( ( (*m).data[1] == 0 ) || ( (*m).data[1] == bDeviceNodeId ) ) */
}
}
在setState()中将d->nodeState设为相应的状态,并执行相应状态下的动作。
四、实例
帧0:停止节点1。
帧1:停止所有节点。
帧2:复位所有节点通信。
帧3::启动节点1。
帧4:启动所有节点。