Modbus、CAN 与工业协议
本文性质声明:本机无开发板,全部内容未实测,为手册级框架。站内对照:net-application-protocol-design(帧格式/序号/心跳的本机实测)、emb-bus(UART/DMA 收发)、dbg-log(日志与可观测性)。
一、Modbus:寄存器表的远程读写
Modbus 的本质是”主从轮询 + 寄存器地址表”——协议极老极简单,因此活得极好。
RTU 帧(串口二进制):
[从站地址 1B][功能码 1B][数据 N B][CRC16 2B(低字节在前)]
常用功能码:01 读线圈、02 读离散输入、03 读保持寄存器、04 读输入寄存器、06 写单寄存器、16 写多寄存器。请求-响应一一对应:主站发 03 00 00 00 0A(读从站 1 的 10 个保持寄存器),从站回 03 14 <20 字节> CRC——字节数 0x14 = 20 跟着,这是响应帧的自描述字段。
TCP 帧:同样的 PDU,外面包 MBAP 头(事务号/协议号/长度)+ 端口 502——没有 CRC 了(TCP 有校验),但多了”一个连接多个从站”的多路复用(事务号区分)。
从站实现五要点:CRC16 查表法(别逐位算,本站 net-application-protocol-design 量过表 vs 计算的取舍族)、超时与静默丢弃(帧不完整/CRC 错 = 一个字不回,等主站超时——别回错误帧,那会让总线更乱)、异常响应(功能码 | 0x80 + 异常码 02 非法地址/03 非法值)、广播地址 0(只写不读,从站不应答)、寄存器表的合法性(地址映射到实际变量——映射表是协议层和业务层之间唯一的翻译处,写错地址的故障全在这儿)。
二、CAN:仲裁、报文与 DBC
CAN 的基因决定它的性格:多主竞争、按 ID 仲裁、报文短、错误帧机制激进。
仲裁:节点同时发,逐位比较,显性位(0)压过隐性位(1)——ID 数值小的赢,且输家自动退出让道。推论:ID 就是优先级——关键报文(制动、急停)分配小 ID。
帧:标准帧 11 位 ID / 扩展帧 29 位 ID,数据 0–8 字节。超过 8 字节的 payload 要用应用层分包(CANopen 的 SDO、J1939 的传输协议)。
DBC 文件:文本格式的”报文字典”——哪个 ID、叫什么名字、几个信号、每个信号几位、缩放系数(物理值 = 原始值 × factor + offset)、枚举定义、发送周期。DBC 是 CAN 团队的共同语言:工具(CANoe/dbc 解析库)读它生成代码,两个人对”这个字节是什么”的争论终结于 DBC。没有 DBC 的 CAN 项目 = 用甲骨文写业务代码。
三、错误帧与总线关闭恢复
CAN 控制器自己有一套错误治理,理解它才能解释”总线突然全体安静”:
- 五种错误:位错误、填充错误、CRC 错误、形式错误、应答错误——任一节点检测到就发错误帧打断当前传输(6 个显性位,所有人都听见)。
- TEC/REC 计数器:发送错误计数 / 接收错误计数,随收发错误增减、随成功收发递减。TEC > 255 → 总线关闭(Bus Off)——节点自己把自己关掉了,不再收发。
- 恢复:总线关闭后节点要等 128 次 ×11 隐性位的”恢复序列”,自动重进;反复关闭进”总线关闭保护”状态。软件侧的对应处理:检测到 Bus Off → 复位 CAN 控制器 + 记录现场(emb-reliability 的取证),别静默重试。
排障口径:ip -s link show can0 看 error counters、candump 看谁在发错误帧。总线 100% 负载 + 错误帧飞舞 = 波特率不匹配或终端电阻错(120Ω 两端各一,万用表量总线 60Ω 才对)。
四、网关与协议转换
工业现场的常态是”多协议并存”:Modbus 的老设备、CAN 的车上网络、MQTT 的上云通道——网关就是翻译层:
Modbus 从站 ─┐
CAN 节点 ──┼─→ [网关:协议栈 × N + 数据模型] ──→ MQTT/HTTP 上云
MQTT 设备 ─┘
网关内部四层(照抄 OSI 的务实版):接入层(各协议的收发,用 DMA/中断,emb-bus)、数据模型层(所有协议翻译成统一的”点表”:地址、类型、值、时间戳、质量位——这是网关的核心资产)、路由层(点表到点表的映射/告警/聚合)、出口层(对上协议的组帧)。
三条工程教训:数据模型先行(没有统一点表的网关,加第三种协议时必然重写前两种的代码);质量位(quality)不可少(值是旧的/通道坏了/超时未更新——下游需要知道”这个数可不可信”,本站 net-application-protocol-design 的 heartbeat 是同一思想的协议层版本);背压与丢弃策略(上游刷得快下游发不出——环形缓冲 + 明确丢弃最旧/阻塞,本站 conc-task-queue 量过无界队列的危险)。
五、排障索引
| 症状 | 入口 |
|---|---|
| Modbus 全体无响应 | CRC 错/帧不完整(从站静默丢弃);波特率校验位不匹配 |
| 单设备无响应 | 地址配错;RS-485 方向脚(DE/RE)时序——发完没关驱动会锁总线 |
| CAN 总线静默 | Bus Off(第三节);终端电阻;波特率 |
| 信号值差一个系数 | DBC 的 factor/offset 与实际不符(第二节);字节序(Motorola vs Intel) |
| 网关数据延迟/丢 | 无界队列堆积或丢弃策略太激进;质量位缺了下游无法判断 |
| 加新协议就崩 | 数据模型层没独立(第四节)——前两种协议的代码被第三次污染 |
六、未实测清单
- 本文所有协议行为——无开发板,未测。
- Modbus CRC/CAN 控制器的具体行为——以你的器件手册和协议规范为准。
- 网关的吞吐与延迟——未部署。
- 用户 Linux 开发机上的项目总线——该机不可达,未涉及。