1.CANOpen协议的介绍
首先CAN的信号传输采用的差分传输,采用的是两根信号线进行传输的总线结构。CAN总线节点上的节点发送数据是以报⽂的形式⼴播给⽹络中所有节点。收发器接收到数据就把数据传送给控制器,再由控制器检查判断 是不是所需数据。不是则忽略。与其他总线相比can总线的优势就是帧数据量小,发送的时间段具有很好的实时性,被干扰的概率小抗干扰性强。
CANopen是can总线的一种常用的应用层协议,CANopen 的核⼼规范是由cia301定义,其中包含了⽹络管理(NMT):启动、停⽌、和重置⽹络节点。 同步(SYNC):周期性同步消息,⽤于时间同步。 过程数据对象(PDO):⽤于实时数据交换。 服务数据对象(SDO):⽤于访问和配置对象字典中的数据。 对象字典(OD):定义设备的所有功能和参数。 ⼼跳和节点 guarding:⽤于监控节点的状态和健康。
2.CANOpen源码的下载和移植
源码下载解压后的目录如下:

其中/src是canopen协议栈的标准源代码,/include是各种头文件,/drivers是各种驱动,/example是测试程序,/objdictgen是带有图形界面的对象字典编辑器,/doc是一些说明文档。然后将该文件下面的一些文件复制到工程对应文件夹里面即可,如下:

将图示的文件复制到src文件夹下。

复制这些文件到Inc文件下并创建一个stm32文件夹里面放入如下所示的文件。

然后将相应的路径添加到工程里面即可,然后再cubemx中进行can控制器的配置,如下:

接着我们在工程中添加CAN驱动接口头文件,程序如下:
cpp
/*
This file is part of CanFestival, a library implementing CanOpen Stack.
Copyright (C): Edouard TISSERANT and Francis DUPIN
AVR Port: Andreas GLAUSER and Peter CHRISTEN
See COPYING file for copyrights details.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CAN_CANFESTIVAL__
#define __CAN_CANFESTIVAL__
#include "applicfg.h"
#include "data.h"
#include <stdint.h>
typedef struct
{
uint32_t StdId; /*!< Specifies the standard identifier.
This parameter can be a value between 0 to 0x7FF. */
uint32_t ExtId; /*!< Specifies the extended identifier.
This parameter can be a value between 0 to 0x1FFFFFFF. */
uint8_t IDE; /*!< Specifies the type of identifier for the message that
will be transmitted. This parameter can be a value
of @ref CAN_identifier_type */
uint8_t RTR; /*!< Specifies the type of frame for the message that will
be transmitted. This parameter can be a value of
@ref CAN_remote_transmission_request */
uint8_t DLC; /*!< Specifies the length of the frame that will be
transmitted. This parameter can be a value between
0 to 8 */
uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0
to 0xFF. */
} CanTxMsg;
// --------- to be called by user app ---------
void initTimer(void);
UNS8 canSend(CAN_PORT notused, Message *m);
UNS8 canChangeBaudRate(CAN_PORT port, char* baud);
uint8_t CanFestival_Can_Init(void);
#endif
其中的四个函数分别为:初始化定时器为CanFestival提供时间基准,用于心跳、同步等时间相关功能。发送CAN消息。动态更改CAN总线波特率。初始化CAN控制器。然后添加对应的.c文件来实现该接口。
cpp
#include "stm32f1xx_hal.h"
#include "canfestival.h"
#include "tim.h"
#include "testslave.h"
#include "f1can.h"
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint8_t CanFestival_Can_Init(void)
{
CAN_FilterTypeDef sFilterConfig;
/* Configure the CAN Filter */
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}
/* Start the CAN peripheral */
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
/* Activate CAN RX notification */
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}
/* Configure Transmission process */
return 0;
}
/**
* @brief Rx Fifo 0 message pending callback in non blocking mode
* @param CanHandle: pointer to a CAN_HandleTypeDef structure that contains
* the configuration information for the specified CAN.
* @retval None
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle)
{
Message RxMSG ;
HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxMSG.data);
RxMSG.cob_id = (uint16_t)(RxHeader.StdId);
if( RxHeader.RTR == CAN_RTR_REMOTE )
{
RxMSG.rtr = 1;
}
else
{
RxMSG.rtr = 0;
}
RxMSG.len = RxHeader.DLC;
canDispatch(&TestSlave_Data, &(RxMSG));
}
uint8_t canSend(CAN_PORT notused, Message *message)
{
CanTxMsg TxMessage;
uint32_t TxMailbox = 0;
TxHeader.DLC = message->len;
memcpy(TxMessage.Data, message->data, message->len);
TxHeader.IDE = CAN_ID_STD;
TxHeader.StdId = message->cob_id;
TxHeader.RTR = (message->rtr == CAN_RTR_DATA) ? 0 : 2;
while(( HAL_CAN_AddTxMessage(&hcan,&TxHeader,TxMessage.Data,&TxMailbox)!=HAL_OK))
{
return 0;
}
return 1;
}
void setTimer(TIMEVAL value)
{
TIM2->ARR = TIM2->CNT + value;
}
TIMEVAL getElapsedTime(void)
{
return TIM2->CNT;
}
其中对应的函数功能如下:
cpp
uint8_t CanFestival_Can_Init(void)
初始化can控制器。
cpp
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle)
接收can的消息。
cpp
uint8_t canSend(CAN_PORT notused, Message *message)
数据的发送。
cpp
void setTimer(TIMEVAL value)
设置定时器的超时值。
cpp
TIMEVAL getElapsedTime(void)
获取已经过去的时间。
然后再使用cubemx来进行对应定时器的配置如下:

然后将对象字典文件文件添加到工程中,头文件内容如下:
cpp
/* File generated by gen_cfile.py. Should not be modified. */
#ifndef TESTSLAVE_H
#define TESTSLAVE_H
#include "data.h"
/* Prototypes of function provided by object dictionnary */
UNS32 TestSlave_valueRangeTest (UNS8 typeValue, void * value);
const indextable * TestSlave_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks);
/* Master node data struct */
extern CO_Data TestSlave_Data;
extern UNS8 DeviceInfo_Control; /* Mapped at index 0x2000, subindex 0x01 */
extern UNS16 DeviceInfo_TP; /* Mapped at index 0x2000, subindex 0x02 */
extern UNS16 DeviceInfo_RH; /* Mapped at index 0x2000, subindex 0x03 */
extern UNS16 DeviceInfo_VL; /* Mapped at index 0x2000, subindex 0x04 */
extern UNS16 DeviceInfo_CU; /* Mapped at index 0x2000, subindex 0x05 */
extern UNS16 DeviceInfo_PW; /* Mapped at index 0x2000, subindex 0x06 */
extern UNS16 DeviceInfo_VR; /* Mapped at index 0x2000, subindex 0x07 */
extern UNS16 DeviceInfo_CPU; /* Mapped at index 0x2000, subindex 0x08 */
extern UNS16 DeviceInfo_RES; /* Mapped at index 0x2000, subindex 0x09 */
extern UNS8 DeviceInfo_SlaveAddress; /* Mapped at index 0x2000, subindex 0x0A */
#endif // TESTSLAVE_H
源文件内容如下:
cpp
/* File generated by gen_cfile.py. Should not be modified. */
#include "TestSlave.h"
#include "modbus.h"
#include "modbus.h"
/**************************************************************************/
/* Declaration of mapped variables */
/**************************************************************************/
UNS8 DeviceInfo_Control = 0x0; /* Mapped at index 0x2000, subindex 0x01 */
UNS16 DeviceInfo_TP = 0x0; /* Mapped at index 0x2000, subindex 0x02 */
UNS16 DeviceInfo_RH = 0x0; /* Mapped at index 0x2000, subindex 0x03 */
UNS16 DeviceInfo_VL = 0x0; /* Mapped at index 0x2000, subindex 0x04 */
UNS16 DeviceInfo_CU = 0x0; /* Mapped at index 0x2000, subindex 0x05 */
UNS16 DeviceInfo_PW = 0x0; /* Mapped at index 0x2000, subindex 0x06 */
UNS16 DeviceInfo_VR = 0x0; /* Mapped at index 0x2000, subindex 0x07 */
UNS16 DeviceInfo_CPU = 0x0; /* Mapped at index 0x2000, subindex 0x08 */
UNS16 DeviceInfo_RES = 0x0; /* Mapped at index 0x2000, subindex 0x09 */
UNS8 DeviceInfo_SlaveAddress = 0x0; /* Mapped at index 0x2000, subindex 0x0A */
/**************************************************************************/
/* Declaration of value range types */
/**************************************************************************/
UNS32 Set_SlaveAdress_Callback(CO_Data* d, const indextable *table, UNS8 bSubindex)
{
//printf("value=%x\r\n",*(uint8_t*)table->pSubindex[bSubindex].pObject);
Modify_SlaveAddress_Flag = 1;
REG_HOLD_BUF[9] = *(uint8_t*)table->pSubindex[bSubindex].pObject ;
return OD_SUCCESSFUL;
}
#define valueRange_EMC 0x9F /* Type for index 0x1003 subindex 0x00 (only set of value 0 is possible) */
UNS32 TestSlave_valueRangeTest (UNS8 typeValue, void * value)
{
switch (typeValue) {
case valueRange_EMC:
if (*(UNS8*)value != (UNS8)0) return OD_VALUE_RANGE_EXCEEDED;
break;
}
return 0;
}
/**************************************************************************/
/* The node id */
/**************************************************************************/
/* node_id default value.*/
UNS8 TestSlave_bDeviceNodeId = 0x00;
/**************************************************************************/
/* Array of message processing information */
const UNS8 TestSlave_iam_a_slave = 1;
TIMER_HANDLE TestSlave_heartBeatTimers[1];
/*
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
OBJECT DICTIONARY
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
*/
/* index 0x1000 : Device Type. */
UNS32 TestSlave_obj1000 = 0x0; /* 0 */
subindex TestSlave_Index1000[] =
{
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1000 }
};
/* index 0x1001 : Error Register. */
UNS8 TestSlave_obj1001 = 0x0; /* 0 */
subindex TestSlave_Index1001[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_obj1001 }
};
/* index 0x1003 : Pre-defined Error Field */
UNS8 TestSlave_highestSubIndex_obj1003 = 0; /* number of subindex - 1*/
UNS32 TestSlave_obj1003[] =
{
0x0 /* 0 */
};
ODCallback_t TestSlave_Index1003_callbacks[] =
{
NULL,
NULL,
};
subindex TestSlave_Index1003[] =
{
{ RW, valueRange_EMC, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1003 },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1003[0] }
};
/* index 0x1005 : SYNC COB ID */
UNS32 TestSlave_obj1005 = 0x0; /* 0 */
/* index 0x1006 : Communication / Cycle Period */
UNS32 TestSlave_obj1006 = 0x0; /* 0 */
/* index 0x100C : Guard Time */
UNS16 TestSlave_obj100C = 0x0; /* 0 */
/* index 0x100D : Life Time Factor */
UNS8 TestSlave_obj100D = 0x0; /* 0 */
/* index 0x1014 : Emergency COB ID */
UNS32 TestSlave_obj1014 = 0x80 + 0x00; /* 128 + NodeID */
/* index 0x1016 : Consumer Heartbeat Time */
UNS8 TestSlave_highestSubIndex_obj1016 = 0;
UNS32 TestSlave_obj1016[]={0};
/* index 0x1017 : Producer Heartbeat Time */
UNS16 TestSlave_obj1017 = 0x0; /* 0 */
/* index 0x1018 : Identity. */
UNS8 TestSlave_highestSubIndex_obj1018 = 4; /* number of subindex - 1*/
UNS32 TestSlave_obj1018_Vendor_ID = 0x0; /* 0 */
UNS32 TestSlave_obj1018_Product_Code = 0x0; /* 0 */
UNS32 TestSlave_obj1018_Revision_Number = 0x0; /* 0 */
UNS32 TestSlave_obj1018_Serial_Number = 0x0; /* 0 */
subindex TestSlave_Index1018[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1018 },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1018_Vendor_ID },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1018_Product_Code },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1018_Revision_Number },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1018_Serial_Number }
};
/* index 0x1200 : Server SDO Parameter. */
UNS8 TestSlave_highestSubIndex_obj1200 = 2; /* number of subindex - 1*/
UNS32 TestSlave_obj1200_COB_ID_Client_to_Server_Receive_SDO = 0x600; /* 1536 */
UNS32 TestSlave_obj1200_COB_ID_Server_to_Client_Transmit_SDO = 0x580; /* 1408 */
subindex TestSlave_Index1200[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1200 },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1200_COB_ID_Client_to_Server_Receive_SDO },
{ RO, uint32, sizeof (UNS32), (void*)&TestSlave_obj1200_COB_ID_Server_to_Client_Transmit_SDO }
};
/* index 0x1400 : Receive PDO 1 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1400 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1400_COB_ID_used_by_PDO = 0x200; /* 512 */
UNS8 TestSlave_obj1400_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1400_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1400_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1400_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1400_SYNC_start_value = 0x0; /* 0 */
subindex TestSlave_Index1400[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1400 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1400_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1400_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1400_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1400_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1400_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1400_SYNC_start_value }
};
/* index 0x1401 : Receive PDO 2 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1401 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1401_COB_ID_used_by_PDO = 0x300; /* 768 */
UNS8 TestSlave_obj1401_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1401_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1401_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1401_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1401_SYNC_start_value = 0x0; /* 0 */
subindex TestSlave_Index1401[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1401 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1401_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1401_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1401_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1401_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1401_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1401_SYNC_start_value }
};
/* index 0x1402 : Receive PDO 3 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1402 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1402_COB_ID_used_by_PDO = 0x400; /* 1024 */
UNS8 TestSlave_obj1402_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1402_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1402_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1402_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1402_SYNC_start_value = 0x0; /* 0 */
subindex TestSlave_Index1402[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1402 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1402_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1402_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1402_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1402_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1402_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1402_SYNC_start_value }
};
/* index 0x1403 : Receive PDO 4 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1403 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1403_COB_ID_used_by_PDO = 0x500; /* 1280 */
UNS8 TestSlave_obj1403_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1403_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1403_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1403_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1403_SYNC_start_value = 0x0; /* 0 */
subindex TestSlave_Index1403[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1403 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1403_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1403_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1403_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1403_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1403_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1403_SYNC_start_value }
};
/* index 0x1600 : Receive PDO 1 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1600 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1600[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1600[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1600 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1600[7] }
};
/* index 0x1601 : Receive PDO 2 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1601 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1601[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1601[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1601 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1601[7] }
};
/* index 0x1602 : Receive PDO 3 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1602 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1602[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1602[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1602 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1602[7] }
};
/* index 0x1603 : Receive PDO 4 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1603 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1603[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1603[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1603 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1603[7] }
};
/* index 0x1800 : Transmit PDO 1 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1800 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1800_COB_ID_used_by_PDO = 0x180; /* 384 */
UNS8 TestSlave_obj1800_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1800_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1800_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1800_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1800_SYNC_start_value = 0x0; /* 0 */
ODCallback_t TestSlave_Index1800_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
subindex TestSlave_Index1800[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1800 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1800_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1800_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1800_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1800_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1800_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1800_SYNC_start_value }
};
/* index 0x1801 : Transmit PDO 2 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1801 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1801_COB_ID_used_by_PDO = 0x280; /* 640 */
UNS8 TestSlave_obj1801_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1801_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1801_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1801_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1801_SYNC_start_value = 0x0; /* 0 */
ODCallback_t TestSlave_Index1801_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
subindex TestSlave_Index1801[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1801 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1801_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1801_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1801_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1801_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1801_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1801_SYNC_start_value }
};
/* index 0x1802 : Transmit PDO 3 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1802 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1802_COB_ID_used_by_PDO = 0x380; /* 896 */
UNS8 TestSlave_obj1802_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1802_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1802_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1802_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1802_SYNC_start_value = 0x0; /* 0 */
ODCallback_t TestSlave_Index1802_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
subindex TestSlave_Index1802[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1802 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1802_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1802_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1802_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1802_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1802_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1802_SYNC_start_value }
};
/* index 0x1803 : Transmit PDO 4 Parameter. */
UNS8 TestSlave_highestSubIndex_obj1803 = 6; /* number of subindex - 1*/
UNS32 TestSlave_obj1803_COB_ID_used_by_PDO = 0x480; /* 1152 */
UNS8 TestSlave_obj1803_Transmission_Type = 0x0; /* 0 */
UNS16 TestSlave_obj1803_Inhibit_Time = 0x0; /* 0 */
UNS8 TestSlave_obj1803_Compatibility_Entry = 0x0; /* 0 */
UNS16 TestSlave_obj1803_Event_Timer = 0x0; /* 0 */
UNS8 TestSlave_obj1803_SYNC_start_value = 0x0; /* 0 */
ODCallback_t TestSlave_Index1803_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
subindex TestSlave_Index1803[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1803 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1803_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1803_Transmission_Type },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1803_Inhibit_Time },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1803_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16), (void*)&TestSlave_obj1803_Event_Timer },
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_obj1803_SYNC_start_value }
};
/* index 0x1A00 : Transmit PDO 1 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1A00 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1A00[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1A00[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1A00 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A00[7] }
};
/* index 0x1A01 : Transmit PDO 2 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1A01 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1A01[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1A01[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1A01 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A01[7] }
};
/* index 0x1A02 : Transmit PDO 3 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1A02 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1A02[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1A02[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1A02 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A02[7] }
};
/* index 0x1A03 : Transmit PDO 4 Mapping. */
UNS8 TestSlave_highestSubIndex_obj1A03 = 8; /* number of subindex - 1*/
UNS32 TestSlave_obj1A03[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex TestSlave_Index1A03[] =
{
{ RW, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj1A03 },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[0] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[1] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[2] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[3] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[4] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[5] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[6] },
{ RW, uint32, sizeof (UNS32), (void*)&TestSlave_obj1A03[7] }
};
/* index 0x2000 : Mapped variable DeviceInfo */
UNS8 TestSlave_highestSubIndex_obj2000 = 10; /* number of subindex - 1*/
ODCallback_t DeviceInfo_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
Set_SlaveAdress_Callback, // 设置从机地址的回调函数
};
subindex TestSlave_Index2000[] =
{
{ RO, uint8, sizeof (UNS8), (void*)&TestSlave_highestSubIndex_obj2000 },
{ RW, uint8, sizeof (UNS8), (void*)®_HOLD_BUF[0] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[1] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[2] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[3] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[4] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[5] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[6] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[7] },
{ RW, uint16, sizeof (UNS16), (void*)®_HOLD_BUF[8] },
{ RW, uint8, sizeof (UNS8), (void*)®_HOLD_BUF[9] }
};
/**************************************************************************/
/* Declaration of pointed variables */
/**************************************************************************/
const indextable TestSlave_objdict[] =
{
{ (subindex*)TestSlave_Index1000,sizeof(TestSlave_Index1000)/sizeof(TestSlave_Index1000[0]), 0x1000},
{ (subindex*)TestSlave_Index1001,sizeof(TestSlave_Index1001)/sizeof(TestSlave_Index1001[0]), 0x1001},
{ (subindex*)TestSlave_Index1018,sizeof(TestSlave_Index1018)/sizeof(TestSlave_Index1018[0]), 0x1018},
{ (subindex*)TestSlave_Index1200,sizeof(TestSlave_Index1200)/sizeof(TestSlave_Index1200[0]), 0x1200},
{ (subindex*)TestSlave_Index1400,sizeof(TestSlave_Index1400)/sizeof(TestSlave_Index1400[0]), 0x1400},
{ (subindex*)TestSlave_Index1401,sizeof(TestSlave_Index1401)/sizeof(TestSlave_Index1401[0]), 0x1401},
{ (subindex*)TestSlave_Index1402,sizeof(TestSlave_Index1402)/sizeof(TestSlave_Index1402[0]), 0x1402},
{ (subindex*)TestSlave_Index1403,sizeof(TestSlave_Index1403)/sizeof(TestSlave_Index1403[0]), 0x1403},
{ (subindex*)TestSlave_Index1600,sizeof(TestSlave_Index1600)/sizeof(TestSlave_Index1600[0]), 0x1600},
{ (subindex*)TestSlave_Index1601,sizeof(TestSlave_Index1601)/sizeof(TestSlave_Index1601[0]), 0x1601},
{ (subindex*)TestSlave_Index1602,sizeof(TestSlave_Index1602)/sizeof(TestSlave_Index1602[0]), 0x1602},
{ (subindex*)TestSlave_Index1603,sizeof(TestSlave_Index1603)/sizeof(TestSlave_Index1603[0]), 0x1603},
{ (subindex*)TestSlave_Index1800,sizeof(TestSlave_Index1800)/sizeof(TestSlave_Index1800[0]), 0x1800},
{ (subindex*)TestSlave_Index1801,sizeof(TestSlave_Index1801)/sizeof(TestSlave_Index1801[0]), 0x1801},
{ (subindex*)TestSlave_Index1802,sizeof(TestSlave_Index1802)/sizeof(TestSlave_Index1802[0]), 0x1802},
{ (subindex*)TestSlave_Index1803,sizeof(TestSlave_Index1803)/sizeof(TestSlave_Index1803[0]), 0x1803},
{ (subindex*)TestSlave_Index1A00,sizeof(TestSlave_Index1A00)/sizeof(TestSlave_Index1A00[0]), 0x1A00},
{ (subindex*)TestSlave_Index1A01,sizeof(TestSlave_Index1A01)/sizeof(TestSlave_Index1A01[0]), 0x1A01},
{ (subindex*)TestSlave_Index1A02,sizeof(TestSlave_Index1A02)/sizeof(TestSlave_Index1A02[0]), 0x1A02},
{ (subindex*)TestSlave_Index1A03,sizeof(TestSlave_Index1A03)/sizeof(TestSlave_Index1A03[0]), 0x1A03},
{ (subindex*)TestSlave_Index2000,sizeof(TestSlave_Index2000)/sizeof(TestSlave_Index2000[0]), 0x2000},
};
const indextable * TestSlave_scanIndexOD (UNS16 wIndex, UNS32 * errorCode, ODCallback_t **callbacks)
{
int i;
*callbacks = NULL;
switch(wIndex){
case 0x1000: i = 0;break;
case 0x1001: i = 1;break;
case 0x1018: i = 2;break;
case 0x1200: i = 3;break;
case 0x1400: i = 4;break;
case 0x1401: i = 5;break;
case 0x1402: i = 6;break;
case 0x1403: i = 7;break;
case 0x1600: i = 8;break;
case 0x1601: i = 9;break;
case 0x1602: i = 10;break;
case 0x1603: i = 11;break;
case 0x1800: i = 12;*callbacks = TestSlave_Index1800_callbacks; break;
case 0x1801: i = 13;*callbacks = TestSlave_Index1801_callbacks; break;
case 0x1802: i = 14;*callbacks = TestSlave_Index1802_callbacks; break;
case 0x1803: i = 15;*callbacks = TestSlave_Index1803_callbacks; break;
case 0x1A00: i = 16;break;
case 0x1A01: i = 17;break;
case 0x1A02: i = 18;break;
case 0x1A03: i = 19;break;
case 0x2000: i = 20;*callbacks = DeviceInfo_callbacks; break;
default:
*errorCode = OD_NO_SUCH_OBJECT;
return NULL;
}
*errorCode = OD_SUCCESSFUL;
return &TestSlave_objdict[i];
}
/*
* To count at which received SYNC a PDO must be sent.
* Even if no pdoTransmit are defined, at least one entry is computed
* for compilations issues.
*/
s_PDO_status TestSlave_PDO_status[4] = {s_PDO_status_Initializer,s_PDO_status_Initializer,s_PDO_status_Initializer,s_PDO_status_Initializer};
const quick_index TestSlave_firstIndex = {
3, /* SDO_SVR */
0, /* SDO_CLT */
4, /* PDO_RCV */
8, /* PDO_RCV_MAP */
12, /* PDO_TRS */
16 /* PDO_TRS_MAP */
};
const quick_index TestSlave_lastIndex = {
3, /* SDO_SVR */
0, /* SDO_CLT */
7, /* PDO_RCV */
11, /* PDO_RCV_MAP */
15, /* PDO_TRS */
19 /* PDO_TRS_MAP */
};
const UNS16 TestSlave_ObjdictSize = sizeof(TestSlave_objdict)/sizeof(TestSlave_objdict[0]);
CO_Data TestSlave_Data = CANOPEN_NODE_DATA_INITIALIZER(TestSlave);
然后在mian函数中的填写如下程序就可以完成最基本的移植工作然后实现通信了:
cpp
CanFestival_Can_Init(); //初始化can过滤器
setNodeId(&TestSlave_Data, SlaveAddress);
setState(&TestSlave_Data, Initialisation);
setState(&TestSlave_Data, Operational);