CanOpen协议栈学习笔记1-帧格式,SYNC和NMT报文介绍

前面已经记录过can协议,后面开始CanOpen协议栈学习。其实协议栈代码已经看过了,而且已经在开发板上跑过了。这里回过头来,重新看下之前遇到的坑,记录下学习笔记。下面均以标准帧为例

1.CanOpen帧格式

下面是CanOpen协议帧格式,数据大小上和标准Can帧没什么区别,只不过对头部进行了划分。
在这里插入图片描述

  • 1.头部变化:

    • 标准Can帧有11位的ID位,这个ID并不一定是设备地址,它可以表示一类通讯命令。什么样的设备接收处理什么样的命令,设备自己最清楚。这样算的话,最多大概有2048种命令了。
    • CanOpen在这个11位的基础上拿出4位,当做功能码,用来表示这个报文的意图。那么每个功能码可以表示128种报文,这里的NodeId也可以理解为设备地址。
  • 2.功能码
    这个和ModBus中的功能码很类似。每一类功能码表示一类功能集合。 下面简单介绍一下各个功能码的作用
    在这里插入图片描述

    • EMCY:设备上发生错误时,发出一类报文。设备上每一类报文只会发送一次。当设备恢复后不会在发送报文,不管之前的报文有没有被其它设备接收。

    • PDO:(Process Data Object)过程数据对象,用于处理实时的数据,比如项目开发过程中,需要实时读取某一设备的传感器数据,就可以使用PDO报文。协议栈允许同时能处理4个的PDO消息,这好比CAN发送时的发送邮箱。用于缓存临时来不及发送的数据。

    • SDOtx/SDOrx:service data object,服务处理对象,用来对数据字典的访问。这里就是说的发送SDO对象,用于存放需要访问数据字典的相关信息。

    • NMT:(Network Management Objects) 网络管理对象,用来控制器节点的工作状态,这个工作状态是有一个标准的状态机的。

    • SYNC:(Synchronisation Object (SYNC))同步对象,一个系统中只能有一个sync站点,发送sync的未生产者(producer),其它接收站点为消费者(consumer)。它提供一中同步机制,同步网络上的时钟节拍。防止硬件差异导致各个设备之间的时钟相位偏差,从而导致数据发送接收出现问题。

    • TIME STAMP:(Time Stamp)高精端时间报文,用来同步时间。目前Canopen中还没有实现这部分的处理。如果你们项目需要的话话可以自己添加。stage.c/canDispatch()方法。

  • 3.功能码对应的cobid
    从下图中可以看到PDOtx,PDOrx的cob-id可以达512个,这也就是说可以处理512个不同的消息。
    在这里插入图片描述

2.SYNC

2.1 sync报文介绍

sync报文相当简答,其报文如下所示:
在这里插入图片描述

  • cobid:0x80
  • rtr:0
  • data:没有数据

关于sync报文的格式,可以从下面代码中也能看到数据结构。

UNS8 sendSYNCMessage(CO_Data* d)
{
  Message m;
  
  MSG_WAR(0x3001, "sendSYNC ", 0);
  
  m.cob_id = (UNS16)UNS16_LE(*d->COB_ID_Sync); //注意这了取低16位
  m.rtr = NOT_A_REQUEST; //RTR=0
  m.len = 0;//数据长度为0
  
  return canSend(d->canHandle,&m); //通过can控制器发送出去
}

下面是定义sync cob-id的地方,可以看到SYNC COB ID 为0x40000080,为什么不是0x80.因为30bit是用来确定是否使能sync.此外控制sync是否使能还有别的地方可以修改。所以在控制是否使能sync的时候,可以单独写个函数来控制这一位。

/* index 0x1005 :   SYNC COB ID. */
                    UNS32 TestMaster_obj1005 = 0x40000080;	/* 1073741952 */
                    subindex TestMaster_Index1005[] = 
                     {
                       { RW, uint32, sizeof (UNS32), (void*)&TestMaster_obj1005, NULL }
                     };

2.2从哪里开始触发sync

当状态切换到Pre_operational时,就会触发sync函数,以及sync定时器,并且周期性的发送sync报文。

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);//如果注册了nitialisation回调方法,这里会调用。		
			}

			/* Automatic transition - No break statement ! */
			/* Transition from Initialisation to Pre_operational */
			/* is automatic as defined in DS301. */
			/* App don't have to call SetState(d, Pre_operational) */
								
			case Pre_operational:
			{
				
				s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 0, 1};
				d->nodeState = Pre_operational;
				switchCommunicationState(d, &newCommunicationState);
                (*d->preOperational)(d);
			}
			break;

2.2 如何关闭sync功能

关闭sync功能,有2中方法。目前代码中用的方法1

  • 将数据字典中的COB_ID_Sync 数据域30bit位置位0即可。
  • Sync_Cycle_Period:将时间周期设置为0。即没有sync功能
void startSYNC(CO_Data* d)
{
	if(d->syncTimer != TIMER_NONE){
		stopSYNC(d);
	}
	RegisterSetODentryCallBack(d, 0x1005, 0, &OnCOB_ID_SyncUpdate);
	RegisterSetODentryCallBack(d, 0x1006, 0, &OnCOB_ID_SyncUpdate);

	if(*d->COB_ID_Sync & 0x40000000ul && *d->Sync_Cycle_Period)
	{
		d->syncTimer = SetAlarm( //设置定时器,如果开启了定时器,而且循环周期也设置了,这了会设置一个定时器。每隔一段时间触发一次
				d,
				0 /*No id needed*/,
				&SyncAlarm,
				US_TO_TIMEVAL(*d->Sync_Cycle_Period), 
				US_TO_TIMEVAL(*d->Sync_Cycle_Period));
	}
}

2.3 sync实验

根据实验可以看到,当master设备使能sync功能后,从设备能源源不断的收到master的sync报文。具体收到的频率要看主设备设置的发射频率。下图左为Master,右为Slave。
在这里插入图片描述

3.NMT

3.1 NMT报文

NMT报文很简单,具有下面特点

  • 没有数据域
  • 功能码为0
  • 为数据帧,RTR=0
    在这里插入图片描述
    上面是从官方文档中截取的,可以发现上面的operational对应0x01.这和协议栈中的代码是有出入的。具体以协议栈代码为准。
enum enum_nodeState {
  Initialisation  = 0x00, 
  Disconnected    = 0x01,
  Connecting      = 0x02,
  Preparing       = 0x02,
  Stopped         = 0x04,
  Operational     = 0x05,
  Pre_operational = 0x7F,
  Unknown_state   = 0x0F
}

3.2 NMT实验

NMT功能,要注意下面几点。

  • CAN网络中,只允许有一个NMT管理员。Master在实验前一定要先设置为master,默认为Master.
  • 其它设备在进行NMT控制期间,必须设置为从设备对象.

下面为主设备的代码,可以看到主设备关闭了sync功能,然后才将从设备的网络开启。

int main(int argc,char **argv)
{
    usart_config(2, 115200);
    delay_init();
    led_init();

	SYS_DEBUG(("welcome come to weiduwulian!!!"));
	if (canOpen(&MasterBoard,&TestMaster_Data)) {               //打开CAN协议栈,初始化can硬件设备
	      setNodeId(&TestMaster_Data, MASTER_NODE_ID);          //定义主设备的ID为0x01
	      set_sync(1);                                          //关闭sync功能,总线就看不到那么多报文了
	      setState(&TestMaster_Data, Initialisation);           //设置站点为初始化状态
	      setState(&TestMaster_Data, Operational);              //设置站点为可操作性状态
	      masterSendNMTstateChange (&TestMaster_Data, SLAVE_NODE_ID, NMT_Start_Node); //设置从设备进入可操作性状态
	      SYS_DEBUG(("Starting node %d (%xh) ...",(int)SLAVE_NODE_ID,(int)SLAVE_NODE_ID));
	}

下图左侧为Master,右侧为Slave。可以看到右侧Slave接收到NMT报文后才将设备状态设置为operational.
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值