4. SDO协议原理与数据流:请求/应答、上传/下载与块传输
SDO,全称 Service Data Object,是 CANopen 协议栈里最基础、也最常用的数据通道。说白了,它就是用来访问对象字典的——你想读一个参数、写一个配置,都得走 SDO。
我刚开始接触 CANopen 时,总觉得 SDO 和 PDO 差不多。后来踩了坑才明白:SDO 是确认型服务,PDO 是非确认型。一个要握手,一个只管发。今天我们就把它彻底讲透。
4.1 SDO 请求/应答机制
SDO 通信基于 客户端/服务器模型。通常,主站是客户端,从站是服务器。客户端发起请求,服务器返回应答。一来一回,确保数据可靠。
核心特征:
- 每个 SDO 请求必须对应一个应答
- 支持分段传输(数据超过 4 字节时)
- 支持块传输(大量数据时效率更高)
- 使用两个 CAN 标识符:一个用于发送,一个用于接收
我记得第一次调试 SDO 时,发现从站没反应。查了半天,原来是 CAN-ID 配反了。嗯,这种低级错误,犯过一次就记住了。
4.2 SDO 通信流程:上传与下载
SDO 的通信流程分为两种基本模式:上传(从站→主站)和下载(主站→从站)。
4.2.1 下载(写对象字典)
主站想写一个值到从站的对象字典。流程如下:
- 主站发送 下载请求(包含索引、子索引、数据)
- 从站接收并写入对象字典
- 从站返回 下载应答(成功或错误码)
举个例子,我想把从站的节点 ID 改成 5:
// 主站发送:写 0x2000 子索引 0x01,数据 0x05
// CAN 报文:601 [8] 23 00 20 01 05 00 00 00
// 从站应答:581 [8] 60 00 20 01 00 00 00 00
这里 23 是命令码,表示写 4 字节数据。60 是应答码,表示成功。
我的经验:下载时一定要确认对象字典的访问权限。有些对象是只读的,你写进去它也不认,返回错误码 0x08000000。我曾经在项目里被这个坑过,查了半天文档才发现。
4.2.2 上传(读对象字典)
主站想读从站的某个参数。流程更简单:
- 主站发送 上传请求(包含索引、子索引)
- 从站读取对象字典
- 从站返回 上传应答(包含数据)
// 主站请求:读 0x2000 子索引 0x01
// CAN 报文:601 [8] 40 00 20 01 00 00 00 00
// 从站应答:581 [8] 43 00 20 01 05 00 00 00
40 是读请求命令码。43 表示成功返回 4 字节数据,数据是 05。
4.3 SDO 分段传输
当数据超过 4 字节时,SDO 会自动进入分段模式。比如你要下载一个 100 字节的配置文件。
分段传输的规则:
- 第一段:包含索引、子索引,数据最多 4 字节
- 后续段:纯数据,每段最多 7 字节
- 最后一段:用特定标志位表示结束
注意:分段传输时,主站和从站之间需要交替发送。主站发一段,从站应答一段,才能发下一段。不能连续发。我曾经在压力测试时忽略了这一点,导致从站缓冲区溢出,整个网络都卡死了。
4.4 SDO 块传输模式
块传输是 SDO 的增强模式,专门用于大数据量传输。它把数据分成多个块,每个块包含多个段,然后一次性确认。
我建议你在以下场景使用块传输:
- 固件升级(几百 KB 到几 MB)
- 批量参数配置
- 日志数据上传
块传输的流程:
- 初始化:主站发送块下载/上传请求
- 数据传输:连续发送多个数据段,不需要逐段应答
- 块结束:发送块结束请求,从站返回确认
- 循环:重复步骤 2-3,直到所有数据传完
对比一下效率:
| 传输模式 | 每段数据量 | 应答方式 | 适用场景 |
|---|---|---|---|
| 普通 SDO | ≤4 字节 | 逐段应答 | 小数据量(参数读写) |
| 分段 SDO | ≤7 字节 | 逐段应答 | 中等数据量(配置表) |
| 块传输 SDO | ≤7 字节/段,多段一确认 | 块确认 | 大数据量(固件升级) |
你想想看,固件升级如果用普通 SDO,每 4 字节就要等一次应答,几百 KB 的数据得等到什么时候?块传输把确认次数减少了 90% 以上,效率提升非常明显。
4.5 SDO 数据流全景图
下面这张图展示了 SDO 通信的完整数据流。我把它画成了流程图,方便你理解。
4.6 实际调试中的避坑指南
我在多个项目里调试 SDO,总结了几条经验:
我曾经犯过的错:
- CAN-ID 配置错误:主站和从站的 SDO 通道 ID 必须匹配。我有一回把 0x600+NodeID 写成了 0x700+NodeID,结果从站死活不应答。
- 对象字典索引越界:读一个不存在的索引,从站返回错误码
0x06020000。调试时一定要先确认对象字典范围。 - 分段传输超时:分段模式下,段与段之间的间隔不能太长。我建议设置 100ms 超时,超过就重发。
- 块传输的块大小:块传输的块大小(每块包含的段数)要匹配从站的缓冲区。我一般设为 16 段/块,兼容性最好。
我的调试习惯:
- 先用普通 SDO 读写单个参数,验证基本通信
- 再用分段 SDO 测试中等数据量
- 最后用块传输做固件升级测试
- 全程用 CAN 分析仪抓报文,对照协议分析
嗯,SDO 这块内容就讲到这里。你只要把请求/应答机制、上传/下载流程、块传输模式这三个核心点吃透,后面调试 CANopenNode 从站工程时就会顺手很多。