CanOpen介绍
一、CanOpen与CIA301协议
CAN 报文可以分为数据部分和 ID 部分,各个厂家可以根据自己的喜好进行编写协议。所以就会出现各种各样的协议。为了消除这种乱糟糟的场面,让 CAN 报文有更加明确的分类和用途,所以产生了 CIA301协议.CIA301基本上就等同于CanOpen了。CIA301协议是CanOpen最基础的协议。它规定了 |D 和报文的分类用法,之后大家都按照这个协议去做。
CIA301协议根据ID的不同,区分不同种类报文: 表格ID
SDO: 是CANopen 协议中用于主从设备间进行可靠、点对点参数配置和数据传输的通信机制;收发一次才传输成功(效率不高);会出现超时或格式错误
PDO: CANopen 协议中实现高效率、实时数据传输的关键机制,其通信方向以从站设备为视角进行定义:发送 PDO(TxPDO)指关节模组向主站发送数据, 接收 PDO(RxPDO)指模组从主站接收数据;
SYNC: 用于实现同步通信, (没有SYNC, 可以定时器定时发送)
NMT: 网络管理, 控制节点工作状态
EMCY: 紧急报文(错误相应)
CAN 通信的一个特点是有 ID; 针对 ID,CanOpen做了下面的功能:

二、字典
上面的报文就是通信的基础, 通信是为了改变参数。通信还需要配置间隔时间, 通讯方式等。这些是配置参数, 传输过程中的数据和配置参数在字典中保存。字典是CanOpen重要的概念,字典里面存有数据和配置。
表格字典(索引编号): 字典是柜子, 柜子上有格子(索引), 格子还有格子(子索引)
通信参数: 速度,温度,角度,加速度,工作模式
配置参数: 配置传输模式,时间间隔,一帧数据包含多少个参数
CIA402: 驱动器行业(有的索引是固定的参数)
索引60FF 子索引00---速度
索引6040 子索引00---位置
举例: CAN 总线上接收的报文
601,40 ff 60 00 00 00 00 00
601 = 600 + 1; 在表格ID中查找: 600h代表了它是一条SDO, 1代表向1号节点发送的数据
40: 代表读指令
ff60是小端: 正确顺序 60ffh, 代表索引是60ff : 在字典ID中查找
00: 子索引
00 00 00 00: 表示数据
字典表格ID:针对从机


三、流程
1. 上电
2. 初始化状态(主机)
3. 预操作状态(主机): 这个状态下,不能发送 PDO,但是可以发送 SDO 或 SYNC;
通过 SDO 配置 PDO
0X06 ... 0x07 ... 0x0f(从机)
准备 打开 运行
4. 操作状态(主机) : 可以进行所有的操作 PDO,SDO,SYNC
四、NMT数据格式
0x0000 + 01 + 01
ID + 命令CS + 节点号(01~07)
0x01: 启动;
0x02: 停止;
0x08: 预开始;
0x81: 复位节点(应用层);
0x82: 复位节点通信;
CanOpen保存指令:601, 22 10 10 01 73 61 76 65: save--->65 76 61 73
五、SDO,PDO数据格式
SDO: 比较慢,但是稳定,会有回复
PDO: 是直接读写索引的(PDO 需要前期进行配置)
使用PDO配置: 1.通过SDO读写取 PDO 的"通讯参数"和"映射参数”; 2. 或者通过上位机

展开通信参数的索引
展开字典上映射参数的索引
要通过通讯和映射参数: 从机决定发送的数据内容
SDO的格式:

SDO 是有回复的: 所以发送一条指令,如果成功就会返回60开头的报文反之; 返回 80开头的报文(错误返回,需要查找原因)
PDO的格式:

SDO配置PDO流程:



六、Sync,Emcy,Lss数据格式
Sync: 帧ID = 0X08

0X1005: 使能的开关
0X1006: 一个周期
0X1007: 同步时间
0X1009: SYNC计数器最大值: 来一个Sync加1
Emcy: 一种错误



Lss: 用于配置节点号和波特率
修改节点号:
七、字典的组成
canfestival字典:.c和.h文件(上位机生成.c和.h文件)
Data Type Definitions: 参数的类型
Communication Parameters: 传输的数据
Transmit PDO Parameters: 通信参数
Transmit PDO Mapping: 映射参数
Manufacturer Specific: 厂家参数
.c文件的流程:
1.声明变量;变量赋值
2.填充数组;类型,数据类型,数据的长度,数据值,回调函数
3.const indextable Master_objdict:最后所有的填充这个数组中
4.const UNS16 Master_ObjdictSize = sizeof(Master_objdict)/sizeof(Master_objdict[0]); 计算对象字典大小
5.CO_Data Master_Data = CANOPEN_NODE_DATA_INITIALIZER(Master); 初始化主站数据结构
八、CanFestival周期性发送Sync
1.配置字典:SetAlarm(d, SYNC, &SendSync, 1000000, 1000000);
UNS32 Master_obj1005 = 0x40000080;4表示使能
UNS32 Master_obj1006 = 1000000;SYNC的周期 = 1us *1000000 = 1s
UNS32 Master_obj1007 = 1000000;SYNC窗口宽度是SYNC一个周期的有效时
2.配置时钟: TimeDispatch():通过SetAlarm()更新闹钟本
tmr_base_init(TMR1, 999, (crm_clocks_freq_struct.ahb_freq / 1000000) - 1);
ahb_freq:240M
分频系数:240
定时器时钟:1MHZ = 1us
中断周期:1000 ×1us = 1ms
#define TIMEVAL UNS32 // 32 位无符号整数:0~ 4,294,967,295
#define TIMEVAL_MAX 0xFFFF // 1 ms = 1 个时间单位
#define MS_TO_TIMEVAL(ms) ((ms) * 1) // 1 ms = 1 个时间单位
#define US_TO_TIMEVAL(us) ((us) / 1000) // 1000 µs = 1 ms = 1 个时间单位
CanFestival协议栈默认使用微秒作为时间单位;定时器中断周期为1ms,统一使用毫秒为单位。
#define TIMEVAL UNS32:
改成UNS16不可以: CanFestival 协议栈内部的时间值通常需要表示较大的数值; 16 位无符号整数的最大值仅为 65535, 远远不够
TIMEVAL_MAX:
数值太小时: 时间范围太小,所有超时判断失效
数值太大时: 0XFFFFFFFF回绕处理逻辑有 bug,导致 SetAlarm 陷入无限循环,程序卡死
3.发送流程:
setNodeId(&Master_Data, 0x00); //主函数
setState(&Master_Data, Initialisation); //初始化状态:发送SYNC
switchCommunicationState(d, &newCommunicationState); //应用通信状态:底层通信模块更新状态
1s发送一次sync,执行回调函数SyncAlarm,最后进入canSend()函数
九、CanFestival周期性发送Pdo
1.配置字典:
通讯参数:
index 0x1800 : Transmit PDO 1 Parameter.
UNS8 Master_highestSubIndex_obj1800 = 6; //对象字典条目支持的最大子索引号
UNS32 Master_obj1800_COB_ID_used_by_PDO = 0x201; //COB-ID
UNS8 Master_obj1800_Transmission_Type = 0xff;
同步传输:Transmission Type = 1~240 (每发送Type 个 SYNC 报文,就发送1次 TPDO)
异步/事件触发:= 0xFE, 0xFF (按 Event Timer 周期发,1s)
UNS16 Master_obj1800_Inhibit_Time = 0x0; //表示无禁止,即允许连续发送
UNS8 Master_obj1800_Compatibility_Entry = 0x0; //保留或兼容性条目,通常为 0,未使用
UNS16 Master_obj1800_Event_Timer = 1000; //事件定时器单位 ms
UNS8 Master_obj1800_SYNC_start_value = 0x0; //前 n 个 SYNC 忽略,从第 n+1 个 SYNC 开始发送PDO
映射参数:
UNS8 Master_highestSubIndex_obj1A00 = 1; //1 个有效的映射对象
UNS32 Master_obj1A00[] = { 0x20000008 }; // 唯一的一个映射条目0x2000:索引0x00:子索引0x08:一个 1 字节(8 位)变量
结果:TPDO以1 秒定时触发,协议栈会去读取对象 0x2000:00 的当前值,用 COB-ID 0x201 发出去
2.配置时钟:与CanFestival周期性发送Sync一样
3.发送流程:
setNodeId(&Master_Data, 0x00); //主函数
setState(&Master_Data, Initialisation); //初始化状态:发送SYNC
setState(&Master_Data, Pre_operational); //预操作模式
setState(&Master_Data, Operational); //操作模式
switchCommunicationState(d, &newCommunicationState); //应用通信状态:通信模块更新状态
StartOrStop(csPDO, PDOInit(d), PDOStop(d)); //创建软件计时器:计时器触发执行回调函数,最后进入canSend()函数
SetAlarm (d, pdoNum, &PDOEventTimerAlarm, MS_TO_TIMEVAL (EventTimerDuration), 0);
十、CanFestival上电发送Sdo
1.配置字典:
UNS8 Master_highestSubIndex_obj1280 = 3; //子索引 1~3
UNS32 Master_obj1280_COB_ID_Client_to_Server_Transmit_SDO = 0x601; //客户端→服务器
UNS32 Master_obj1280_COB_ID_Server_to_Client_Receive_SDO = 0x581; //服务器→客户端
UNS8 Master_obj1280_Node_ID_of_the_SDO_Server = 0x1; //目标SDO服务器的节点ID
2.简单发送数据
// 发送Sdo: 601,22,60,60,00,03,00,00,00
601: 客户端→服务器; 22: SDO 命令字节; 索引:60,60; 子索引:00; 4 字节数据:03,00,00,01
unsigned long abortCode = 0;
char size = 1;
char sendDate[4] = {0};
sendDate[0] = 0x03;
sendDate[1] = 0x00;
sendDate[2] = 0x00;
sendDate[3] = 0x00;
writeNetworkDict(&Master_Data, 0x01, 0x6060, 0x00, size, uint8, &sendDate, 0);
while(getWriteResultNetworkDict(&Master_Data, 0x01, &abortCode) != SDO_FINISHED)
0x601上的 0x80错误响应是自己的协议栈发出的:SDO 超时时间 (SDO_TIMEOUT_MS = 3000U)
Sdo发送会出现报错:
1. sdo报错, 中止(需要查找协议)
2. emcy: 紧急报文 error code
十一、备注
1.发送NMT命令是什么意思:
发送NMT, 从站什么时候可以使用了; 主站需要发送NMT命令来同步从站的状态
start_node() → masterSendNMTstateChange() → CAN_Transmit()
masterSendNMTstateChange() 直接调用 CAN_Transmit()
2.从站处理时间:
收到完整CAN消息后,在USBFS_L_CAN1_RX0_IRQHandler()立即开始处理: 解析SDO → 查找对象字典 → 执行操作 → 发送响应
更多推荐



所有评论(0)