一、CANopen 协议基础
- CANopen 简介
定位:基于 CAN 总线的应用层协议(CiA 301/302/402等标准)。
应用场景:
工业自动化(伺服电机、PLC、I/O模块)。
医疗设备(手术机器人、监护仪)。
轨道交通(车门控制、牵引系统)。
核心组成:
对象字典(Object Dictionary, OD):设备的参数数据库(索引+子索引)。
通信协议:SDO(配置参数)、PDO(实时数据)、NMT(网络管理)。
设备配置文件:EDS(电子数据表)、DCF(设备配置)。
- CANopen 通信模型
二、CANopen 设备配置实战
- 对象字典(Object Dictionary)
结构:16位索引(主参数) + 8位子索引(子参数)。
常用索引范围:
0x1000-0x1FFF:通信参数(波特率、节点ID)。
0x2000-0x5FFF:制造商自定义参数。
0x6000-0x9FFF:标准化设备参数(CiA 402电机参数)。
示例:配置节点ID(索引 0x2000,子索引 0x00)为2:
c
// 通过SDO写入命令
SDO Write: Index=0x2000, Subindex=0x00, Data=0x02
- EDS/DCF 文件
EDS文件:描述设备对象字典的标准化文本文件(ASCII格式)。
DCF文件:包含实际配置值的设备配置文件(基于EDS生成)。
工具支持:CANopen Magic、CANoe、Kvaser CanKing。
- 配置步骤
导入EDS文件:加载设备描述文件到主站。
设置节点ID:确保每个设备有唯一ID(通常通过DIP开关或软件配置)。
配置PDO映射:
定义哪些参数通过PDO传输(如电机转速、温度)。
示例:映射索引 0x6040(控制字)到PDO1:
ini
; PDO1映射参数(索引0x1600)
[PDO1_Mapping]
0x1600sub0 = 2 ; 映射条目数量
0x1600sub1 = 0x60400010 ; 控制字(16位)
0x1600sub2 = 0x60600008 ; 目标位置(32位)
设置通信参数:波特率(索引 0x1002)、同步周期(索引 0x1006)。
三、CANopen 通信实现
- SDO(服务数据对象)
功能:读写对象字典(可靠但速度慢)。
通信模式:
快速SDO(COB-ID 0x580+NodeID / 0x600+NodeID)。
分段传输:用于大数据块(如固件升级)。
示例:读取节点ID:
c
// 主站发送SDO读取请求
CAN ID: 0x600 + NodeID (e.g., 0x602)
Data: 0x40 0x00 0x20 0x00 0x00 0x00 0x00 0x00
// 从站响应
CAN ID: 0x580 + NodeID (e.g., 0x582)
Data: 0x43 0x00 0x20 0x00 0x02 0x00 0x00 0x00
- PDO(过程数据对象)
功能:实时传输过程数据(速度快但不可靠)。
传输类型:
同步传输(基于SYNC信号)。
事件驱动(数据变化时发送)。
周期性传输(定时发送)。
PDO映射配置:
c
// 映射索引0x6040(控制字)到PDO1
Write SDO: 0x1600sub1 = 0x60400010
- NMT(网络管理)
主站命令:
启动所有节点:CAN ID 0x000,数据 0x01 0x00。
复位节点:CAN ID 0x000,数据 0x82 0xNodeID。
节点状态机:
图表
代码
四、CANopen 高级应用
- 心跳协议(Heartbeat)
功能:监测节点存活状态。
配置:
主站设置心跳周期(索引 0x1017sub0)。
从节点定期发送心跳报文(COB-ID 0x700 + NodeID)。
- 节点保护(Node Guarding)
功能:主站定期轮询节点状态。
命令:主站发送 0x700 + NodeID,从节点回复状态。
- 同步与时间戳
SYNC报文:协调多个PDO的传输时机。
时间戳:索引 0x1012 记录事件发生时间。
五、常见问题与调试
- 通信失败
可能原因:
节点ID冲突。
波特率不匹配(检查索引 0x1002)。
物理层故障(终端电阻、线缆短路)。
调试工具:
CAN分析仪(如PCAN-USB Pro)。
Wireshark(配合SocketCAN)。
- PDO数据未更新
检查项:
PDO映射是否启用(索引 0x1400sub1=1)。
传输模式是否配置为周期或事件驱动。
- SDO超时
解决方法:
确认从站是否响应(检查CAN ID过滤)。
验证对象字典索引/子索引是否存在。
六、代码示例(基于STM32 + CANopenNode库)
- 初始化CANopen节点
c
#include "CO_driver.h"
#include "CO_OD.h"
CO_NODE_SPEC canSpec = {
.NodeID = 0x01,
.Baudrate = 1000000, // 1Mbps
.OD = &OD, // 对象字典结构体
};
CO_NODE canNode;
void main() {
CO_ReturnError_t err;
err = CO_init(&canNode, &canSpec);
while (1) {
CO_process(&canNode); // 处理CANopen协议栈
}
}
- PDO发送示例
c
// 在对象字典中映射索引0x6040到PDO1
OD_PDO1[0].mappedObject = OD_ENTRY_H2000_ControlWord;
// 周期性发送PDO1
if (CO_TmrIsExpired(&canNode.Tmr, 100)) { // 100ms周期
CO_PDOsend(&canNode.PDO[0]);
}
七、学习资源
标准文档:CiA 301(CANopen基础)、CiA 402(电机控制)。
开源库:CANopenNode(C语言)、CANopen-stm32(STM32 HAL库)。
书籍:《CANopen Implementation Guide》。
总结
CANopen协议通过对象字典和标准化的通信机制,为工业设备互联提供了高效解决方案。掌握其核心概念(SDO/PDO/NMT)、配置流程(EDS/DCF)和调试技巧,是开发稳定CANopen系统的关键。实际应用中需结合硬件特性(如STM32的bxCAN)和协议栈(如CANopenNode),逐步实现复杂功能。