3、SDO基础:SDO协议格式、加速传输与分段传输机制
说到CANopen里的数据交换,大家最先接触的肯定是SDO。我刚开始学CANopen那会儿,总觉得SDO这个名字挺唬人——服务数据对象,听着就抽象。其实说白了,SDO就是用来读写对象字典的通道。你想配置参数、查状态、下载固件,都得靠它。
今天咱们就把SDO的底裤扒干净。从协议格式讲起,再到两种传输模式:加速传输和分段传输。嗯,这两个概念搞明白了,你写代码的时候就知道什么时候该用谁了。
3.1 SDO协议格式——报文里藏了什么秘密?
SDO通信用的是CAN标准帧,11位ID。客户端发请求,服务器回响应。我习惯把SDO报文分成三部分看:
- CAN-ID:0x600 + 节点号(请求),0x580 + 节点号(响应)
- 字节0:命令字,也叫CCS(Client Command Specifier)
- 字节1-3:对象字典索引(2字节)+ 子索引(1字节)
- 字节4-7:数据区,最多4字节
举个例子你就明白了。假设节点1的驱动器,我想把它的“电机额定电流”改成5000mA。这个参数存在对象字典0x2001,子索引0x01。那么我发的SDO请求报文长这样:
CAN-ID: 0x601
数据: 23 01 20 01 88 13 00 00
拆开看:
- 0x23:命令字,表示“写数据,加速传输,4字节有效”
- 0x01 0x20:索引0x2001(注意小端模式,低字节在前)
- 0x01:子索引
- 0x88 0x13 0x00 0x00:数据5000,十六进制0x1388,小端排列
服务器收到后,如果成功,会回复:
CAN-ID: 0x581
数据: 60 01 20 01 00 00 00 00
0x60就是“写成功”的响应码。嗯,这里要注意:如果服务器报错,返回的就不是0x60了,而是0x80开头的错误报文,后面跟着错误码。
核心记忆点:SDO请求的CAN-ID = 0x600 + 节点号,响应CAN-ID = 0x580 + 节点号。这个公式我闭着眼睛都能写出来。
3.2 加速传输——小数据就该快刀斩乱麻
加速传输,英文叫Expedited Transfer。名字起得好,就是“加急”的意思。什么时候用?当你要传输的数据不超过4字节时。
你想想看,电机参数、PID系数、限位值,这些哪个不是4字节以内?所以加速传输在实际项目里用得最多。我做过一个伺服项目,90%的SDO通信都是加速传输,又快又省事。
加速传输的命令字格式如下:
| 位7-5 | 位4 | 位3 | 位2 | 位1-0 |
|---|---|---|---|---|
| CCS | 1(加速标志) | 1(数据有效) | e(数据大小编码) | 保留 |
CCS的值:1=下载(写),2=上传(读)。
e的编码:00=4字节,01=3字节,10=2字节,11=1字节。
举个例子,我要读节点2的“设备类型”(4字节,索引0x1000,子索引0x00):
请求: 40 00 10 00 00 00 00 00
响应: 43 00 10 00 01 00 00 00
请求的0x40表示“上传请求,加速”。响应的0x43表示“上传响应,加速,4字节有效”,数据是0x00000001,表示设备类型是“通用驱动器”。
我的小技巧:写代码时,我习惯把命令字定义成宏。比如#define SDO_DOWNLOAD_EXPEDITED_4 0x23,这样一看就懂,不容易写错。
3.3 分段传输——大数据就得慢慢来
那如果数据超过4字节呢?比如你要下载一个100字节的配置文件,或者上传一段固件程序。这时候加速传输就无能为力了。怎么办?用分段传输(Segmented Transfer)。
分段传输的原理很简单:把大数据切成小块,一块一块发。每块最多7字节(因为CAN报文数据区8字节,去掉1字节命令字,剩7字节可用)。
我曾经在一个项目中,需要给驱动器升级固件。固件大小128KB,用分段传输,一包7字节,算下来要发将近2万包。嗯,那时候我才真正体会到什么叫“耐心是美德”。
分段传输的流程分三步:
- 初始化:客户端发一个“分段下载请求”,告诉服务器我要传大数据了。命令字0x21(下载,不分段,但数据长度超过4字节)。
- 数据分段:客户端一包一包发数据。每包命令字0x00或0x10(0x10表示最后一包)。数据区最多7字节。
- 结束确认:服务器收到最后一包后,回复0x60确认。
看个例子,下载一个10字节的数据到对象字典0x2002:
第一步:初始化
请求: 21 02 20 00 0A 00 00 00
解释: 0x21=下载,索引0x2002,子索引0x00,数据长度10字节
第二步:分段发送
第1包: 00 01 02 03 04 05 06 07
第2包: 10 08 09 00 00 00 00 00
解释: 第1包命令字0x00(中间包),第2包0x10(最后一包)
第三步:服务器确认
响应: 60 02 20 00 00 00 00 00
避坑指南:我曾经在分段传输时犯过一个低级错误——忘记设置toggle位。分段传输的每一包都有一个toggle位(命令字的位4),用来做交替校验。第1包toggle=0,第2包toggle=1,第3包toggle=0……以此类推。如果toggle位不对,服务器会直接丢弃报文。这个坑我踩过一次,调试了一下午才发现。
3.4 加速 vs 分段——到底怎么选?
这个问题我经常被问到。其实选择标准就一条:看数据长度。
- 数据 ≤ 4字节:用加速传输。简单、高效、实时性好。
- 数据 > 4字节:用分段传输。但要注意,分段传输会占用总线时间,如果系统里有多个节点同时做分段传输,总线负载会飙升。
我个人的经验是:能用加速就别用分段。比如有些工程师习惯把所有参数都打包成结构体,一次下载几十个字节。其实完全可以把每个参数单独用加速传输写,代码更清晰,调试也方便。
当然,有些场景不得不分段。比如下载固件、上传历史故障记录。这时候我建议:分段传输期间,暂停其他高优先级PDO的发送,避免总线冲突。
3.5 知识体系总览
下面这张图是我自己画的SDO传输机制总览,帮你把今天的内容串起来:
这张图把今天的内容都串起来了。左边是加速传输,右边是分段传输。你写代码的时候,先问自己一句:数据有没有超过4字节?答案出来了,选哪个也就清楚了。
好了,SDO的基础就讲到这里。协议格式、加速传输、分段传输,这三个点你搞明白了,CANopen的数据交互就算入门了。下一节咱们聊聊SDO的超时处理和错误码,那才是真正考验工程能力的地方。
公众号:蓝海资料掘金营,微信deep3321