这里,单片机侧实现的是主站,主节点的状体如下面代码中的几种:
/* The nodes states
* -----------------
* values are choosen so, that they can be sent directly
* for heartbeat messages...
* Must be coded on 7 bits only
* */
/* Should not be modified */
enum enum_nodeState {
Initialisation = 0x00,
Disconnected = 0x01,
Connecting = 0x02,
Preparing = 0x02,
Stopped = 0x04,
Operational = 0x05,
Pre_operational = 0x7F,
Unknown_state = 0x0F
};
typedef enum enum_nodeState e_nodeState;
- Initialisation
- Disconnected
- Connecting
- Preparing
- Stopped
- Operational
- Pre_operational
- Unknow_state
主机的初始状态是Unknow_state,我们需要在初始化节点时进行设置节点的状态为initialisation,
这时候主站的会自动切换到预操作状态,这个时候主站的各个通信服务的功能才打开。
下面时通信状态的代码,
typedef struct
{
INTEGER8 csBoot_Up;//current state
INTEGER8 csSDO;
INTEGER8 csEmergency;
INTEGER8 csSYNC;
INTEGER8 csHeartbeat;
INTEGER8 csPDO;
INTEGER8 csLSS;
} s_state_communication;
下面时显示调用主站设备为初始化的代码如下:
/*************************** INIT *****************************************/
void InitNodes(CO_Data* d, UNS32 id)
{
/****************************** INITIALISATION MASTER *******************************/
if(strcmp(MasterBoard.baudrate, "none"))
{
/* init */
setState(&TestMaster_Data, Initialisation);
}
}
这里把主站节点的状态设置为初始化状态,然后自动切换到预操作状态;
在预操作状态下,打开了多种的通信功能,代码如下:
UNS8 setState(CO_Data* d, e_nodeState newState)
{
if(newState != d->nodeState){
switch( newState ){
case Initialisation:
{
s_state_communication newCommunicationState = {1, 0, 0, 0, 0, 0, 0};
d->nodeState = Initialisation;
switchCommunicationState(d, &newCommunicationState);
/* call user app init callback now. */
/* d->initialisation MUST NOT CALL SetState */
(*d->initialisation)(d); // 2023-01-06 调用主站节点的初始化的回调函数
}
/* Automatic transition - No break statement ! */
/* Transition from Initialisation to Pre_operational */
/* is automatic as defined in DS301. */
// 这里没有break,会自动执行下面的代码,说明状态自行切换到预操作状态
case Pre_operational:
{
s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 0, 1};
d->nodeState = Pre_operational;
switchCommunicationState(d, &newCommunicationState);
if (!(*(d->iam_a_slave)))
{
masterSendNMTstateChange (d, 0, NMT_Reset_Node);
}
(*d->preOperational)(d);
}
break;
case Operational:
if(d->nodeState == Initialisation) return 0xFF;
{
s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 1, 0};
d->nodeState = Operational;
newState = Operational;
switchCommunicationState(d, &newCommunicationState);
(*d->operational)(d);
}
break;
case Stopped:
if(d->nodeState == Initialisation) return 0xFF;
{
s_state_communication newCommunicationState = {0, 0, 0, 0, 1, 0, 1};
d->nodeState = Stopped;
newState = Stopped;
switchCommunicationState(d, &newCommunicationState);
(*d->stopped)(d);
}
break;
default:
return 0xFF;
}/* end switch case */
}
/* d->nodeState contains the final state */
/* may not be the requested state */
return d->nodeState;
}
下面是主站设备进行通信状态切换实现的代码:
#define StartOrStop(CommType, FuncStart, FuncStop) \
if(newCommunicationState->CommType && d->CurrentCommunicationState.CommType == 0){\
MSG_WAR(0x9999,#FuncStart, 9999);\
d->CurrentCommunicationState.CommType = 1;\
FuncStart;\
}else if(!newCommunicationState->CommType && d->CurrentCommunicationState.CommType == 1){\
MSG_WAR(0x9999,#FuncStop, 9999);\
d->CurrentCommunicationState.CommType = 0;\
FuncStop;\
}
#define None
/*!
**
**
** @param d
** @param newCommunicationState
**/
void switchCommunicationState(CO_Data* d, s_state_communication *newCommunicationState)
{
#ifdef CO_ENABLE_LSS
StartOrStop(csLSS, startLSS(d), stopLSS(d))
#endif
StartOrStop(csSDO, None, resetSDO(d))
StartOrStop(csSYNC, startSYNC(d), stopSYNC(d))
StartOrStop(csHeartbeat, heartbeatInit(d), heartbeatStop(d))
StartOrStop(csEmergency, emergencyInit(d), emergencyStop(d))
StartOrStop(csPDO, PDOInit(d), PDOStop(d))
StartOrStop(csBoot_Up, None, slaveSendBootUp(d))
}
// 状态有变化才执行相对应的函数;
// 0变1,执行开始函数
// 1变0,执行停止函数
在设置主设备为初始化状态的时候的函数调用:
StartOrStop(csBoot_Up, None, slaveSendBootUp(d))
中的Start,即None,说明没有函数被执行;
然后进入预操作状态,执行的函数顺序为:
startSYNC()
heartbeatInit()
emergencyInit()
slaveSendBootUp()
协议栈运行到这里,除了PDO不能正常外,其他的都可以正常工作了;
下图是打印的log:
需要等到主站配置完成从站设备节点后,需要显示调用函数来切换主站到操作状态,这时候就可以进行PDO的数据通信了。