Germanjet 德敏哲 CANopen 位移传感器主站实现:命令字与状态机
在 PLC 里接一支 CANopen 磁致伸缩位移传感器,组态软件里填个节点号、导一下 EDS,位置值就出现在变量表里了。换成自制的板子,或者客户拿去做嵌入式开发,这些"填一下就好"的东西全部消失:PDO 要自己收、状态机要自己推、参数要自己拼成 8 字节发出去。
厂家给的资料是 PLC 视角的通讯范例,看着像"某个 PLC 牌子的操作说明"。但报文本身跟主站无关——同一批帧,PLC 发出去是这样,单片机发出去也是这样。把这些范例里的帧抽出来,加上对象字典,就是一份能直接落到代码里的协议。
有件事要先说清楚。下面出现的索引和对象,都是 Germanjet 德敏哲 194 系列(19 系列 CANopen 型)专有的。CANopen 是标准协议,对象字典却不是——换一家的 CANopen 位移传感器,0x2010 未必是波特率,0x300B 未必是节点地址,0x6020 里放的也未必是位置。同品牌同系列可以照搬,跨品牌照搬一定出错。判断依据是对方提供的 EDS 文件,不是网上能找到的通用表。
先确认这台设备是谁,不要猜
接线、上电之前,把身份参数抄下来。它们既是 EDS 里的固定值,也是 LSS 用来认设备的凭据。
- 厂商号 0x40,产品码 0x43333034。后者按 ASCII 读就是 "C304",型号里的 C304 由此而来。
- 设备类型 0x1000 = 0x0A0196。低 16 位 0x0196 是 406,即 CiA DS406 编码器行规;高位 0x0A 表示多传感器接口,所以一台设备能同时挂多个磁块。
- 行规版本 0x6507 = 3.1,后面跟厂商软件版本 4.01。
- 出厂 node-id 是 127,波特率按订货时指定,印在传感器标签上。
EDS 文件在裸机开发里用不上,组态软件才需要它。但它的对象字典必须当参数表用:哪个索引可写、哪个只是只读、数据类型几位,写错一个字节整条配置就废。DS406 行规解决了什么讲的是这个行规的边界,本文讲怎么按它发帧。
SDO:一个命令字决定写几个字节
SDO 是 8 字节定长帧,结构固定:字节 0 是命令字,字节 1~2 是索引(低字节在前),字节 3 是子索引,字节 4~7 是数据。命令字决定这次要写几个字节,这是它最容易出错的地方。
| 命令字 | 含义 | 典型数据长度 |
|---|---|---|
| 0x2F | 写,1 字节有效 | 1 |
| 0x2B | 写,2 字节有效 | 2 |
| 0x27 | 写,3 字节有效 | 3 |
| 0x23 | 写,4 字节有效 | 4 |
| 0x40 | 读请求,不带数据 | 0 |
| 0x60 | 写成功确认(从站回) | 0 |
| 0x43 / 0x47 / 0x4B / 0x4F | 读响应,分别带 4 / 3 / 2 / 1 字节数据 | 4 / 3 / 2 / 1 |
| 0x80 | 中止,字节 4~7 是中止码 | 4 |
读一个参数长这样:主站发 40 0B 10 00 00 00 00 00(读 0x100B 子索引 0,即当前 node-id),从站回 43 0B 10 00 7F 00 00 00,最后 4 字节 7F 就是 127。写一个参数:2F 10 20 00 E8 03 00 00,把 0x2010 写成 0x03E8,即 1000 kbps。注意 E8 03 是低字节先行,看着像 0x03E8 倒过来写。
命令字与声明类型对不上,设备会回中止帧。对象字典里标 Unsigned32 的索引,用 0x2F 只写 1 字节,有的设备宽容、有的直接拒绝。保存参数这一条尤其乱:0x1010 子索引 1 声明是 32 位,标准写法是 0x23 加签名 73 61 76 65("save"),但资料里的范例用的是 0x2F 只带首字节。两份范例各自都完成了存盘,说明这两种写法设备都认。选一种写死在代码里,别在两条之间来回试——反复保存失败的现场,多数是这个原因。
不知道 node-id 时的两条路
传感器是从货架上拿的,标签磨掉、或者一次接了三支同型号,谁也不知道哪支是几号。这时候有两条路。
第一条是反推:上电瞬间传感器会先发一帧空的 EMCY,COB-ID 是 0x80 加 node。收到 0xFF 就是 127,收到 0x9B 就是 0x1B(27)。这条最快,只适用总线上只有一支、或者你确定只接了一支的时候。
第二条是 LSS:0x7E5 是主站发、0x7E4 是设备回,这两条 ID 不随 node 变化,所以能在"不知道 node"的前提下通话。流程四步——进配置模式、用厂商号加产品码加版本号加序列号这四段身份参数确认是哪一台、写新 addr 或新波特率、存盘退回操作态。多台同型号混在一条总线时,靠序列号区分,这也是为什么第一段要把序列号抄下来。
LSS 的具体命令字按 CiA 301 的 LSS 章节,各家主站库基本都封装好了,不必自己从零拼。但要知道它存在:设备侧已经支持(EDS 里 LSS_Supported = 1),遇到"整条总线都说不上话、也不知道 node"的现场,用 LSS 扫一遍比挨个拆下来试快得多。
资料里改 node 和改波特率走的是厂商私有对象——0x300B 写新 node、0x2010 写波特率,前提是你已经知道当前 node。已知地址时这条路更短,不知道地址时用 LSS,两条不冲突。
守护:这台设备没有 0x1017
这是从 PLC 转到自研板子最容易踩的一脚。标准做法是设备做心跳生产者,往 0x700+node 周期发一帧;194 的对象字典里没有 0x1017 这一项。翻 EDS 的对象清单能看得很清楚:0x100C 守护时间、0x100D 生命期系数、0x100E 守护 COB-ID(默认 0x700+node)三项都在,唯独没有心跳生产者那一项。
节点守护是反过来问的:主站主动发一帧远程帧(RTR)到 0x700+node,从站回 1 字节。这一字节的 bit7 每次应答翻转一次,bit0~6 是当前 NMT 状态(4 停止、5 运行、127 预操作)。主站据此判断两件事:设备还在不在,以及它在哪个状态。
- 超时算法:守护时间乘生命期系数。写 0 就是关闭守护,此时从站不会因为主站不发轮询而报错。
- 开了守护就必须轮询。主站开了守护却忘了发 RTR,从站超时后会认为通信断了,发 EMCY 报
81 30(life guard error),并可能停掉 PDO。现场表现是"读了几秒就没数据了"。 - 别照抄标准心跳。按 0x1017 配好心跳、等 0x700+node 的报文,会一直等到超时——因为设备根本不发。
单片机侧要自己补的四件事
- 位定时。500 kbps 和 1 Mbps 是常用档,采样点取 80%~87.5%。具体寄存器值按芯片的位定时公式算,别抄别人板子的数——同一颗控制器外接晶振不同,算出来的值就不同,抄错了表现为"偶尔能收到、怀疑接线"。
- 验收滤波器。只放四类进来:0x080、0x180~0x480 加 node、0x580+node、0x80+node。全通过模式在实验室能跑,装到现场一条总线上十几台设备,中断会被别人的报文打满。
- 字节序。位置是 32 位整数,低字节先发。四个字节拼回来要按小端处理,而且是有符号数——行程零点设在中间、或者磁块在负方向时,高位全 1,按无符号解会得到四十几亿的读数。
- 事件计时器与中断预算。0x1800 子索引 5 是事件计时器,出厂 1 ms。一条总线上接 8 支、每支 1 ms 一帧,光 PDO 就是每秒 8000 帧,500 kbps 撑不住。先算总线负载,再定周期。
位置换算的三层,别写死一个数
收到 TPDO1 的 7 个字节,拆成位置 4 字节、速度 2 字节、限位状态 1 字节。位置要乘上测量步长才是毫米。
- 0x6005 子索引 1:位置测量步长,单位 0.001 µm,出厂默认 5000,即 5 µm。
- 0x6501:当前实际使用的测量步长。它和 0x6005 都是只读的,装机时两个一起读一遍对照,最稳。
- 换算:资料里的原例——收到
03 83 00 00,按低字节先拼成 0x00008303,十进制 33539;步长 0.005 mm,则 33539 × 0.005 = 167.695 mm。
0.005 mm 是常见值,不是全部。同一个系列不同量程、不同分辨率订货,步长都不一样。把步长写成常量而不是读参数,换一批设备就会出现整段比例错,而且错得很整齐,容易被误判成机械问题。
上电到出数:最短那条路
上电先收 EMCY(0x80+node),发一帧 NMT 启动(0x000,01 00),传感器立刻回一帧 TPDO1。之后是同步还是异步,取决于 0x1800 子索引 2 的传输类型:0 表示收到 SYNC 才发,254 表示按事件计时器自己发。
同步模式每发一次 SYNC(0x080,长度 0),四个磁块各回一帧,帧序稳定、时刻一致;异步模式省掉 SYNC,但多台设备的时间戳会错开。两种模式的完整帧序见 19 系列通讯范例,本文不重复列。
三个联调卡点
- SDO 通、PDO 不通。设备停在预操作态。预操作态允许 SDO 配置,但不发 PDO,必须发 NMT 启动进运行态。反过来,运行态也能收 SDO,所以"能读参数"不代表"已经启动"。
- 改了 node,主站没收成。0x300B 写下去后传感器的 COB-ID 立刻跟着变,主站这边的接收 ID 和过滤器必须同步改,否则表现为"改完就失联"。存盘那条 SDO 也要发到新地址。
- 数据是负数时读数离谱。位置按无符号解。int32 的高位被当成数值位,负方向的位置会变成天文数字。
改参数的完整帧序(node、波特率、事件计时器三条)见 CANopen 参数修改;PDO 与 SDO 的分工、对象字典怎么读见 CANopen 入门;多个磁块挤在 8 字节里的取舍见 多磁块与 8 字节帧限。194 系列与 CANbus 集成模块是这类现场最常用的两件东西,选型边界见 按 PLC 本体接口选总线。
一句话
帧是标准的,难的是状态机、字节序和那几个厂商私有索引——把这三样对齐,单片机主站和 PLC 收到的是同一批数。
常见问题
Q:没有 EDS 文件能用单片机读吗?
能。EDS 是给组态软件读的,裸机开发只需要它的内容当参数表:每个索引的类型、长度、可读还是可写。真正跑在总线上的是 8 字节报文,跟 EDS 文件本身无关。但对象字典不能猜,写错长度设备会回中止帧。
Q:为什么按标准心跳配置收不到 0x700+node 的报文?
这台设备的对象字典里没有 0x1017 心跳生产者,只有节点守护的三个参数(0x100C、0x100D、0x100E)。守护是主站发远程帧去问、从站答 1 字节,方向跟心跳相反。按心跳那套配,会一直等到超时。
Q:位置读出来是很大的正数,是不是坏了?
先看符号。位置是 32 位有符号整数,四个字节低字节先发。按无符号解析时,负方向的位置高位全 1,会变成四十多亿。把变量声明成 int32、按小端重组,再乘测量步长。
Q:一条总线上能接几支 194?
协议上限是 node 1~127,实际受总线负载和波特率限制。每支按事件计时器周期发一帧 7 字节的 TPDO,8 支各 1ms 就是每秒 8000 帧,500 kbps 撑不住。先算负载:把周期放宽到 5~10 ms 通常不影响控制,却能省下大半带宽。
这篇讲的问题,说到底都绕不开磁致伸缩位移传感器本身。磁致伸缩位移传感器产品中心按行程、安装方式与输出接口把全部系列排开,选型从这里进最省事。
← 返回行业动态



