什么是 MODCAR?
MODCAR是一个面向工业现场总线与以太网的并发通信协议。它的名字由两部分组成:
MOD—— 致敬经典的 Modbus 协议,继承了其功能码、寄存器/位操作等易用特性。
CAR——ConcurrentAccess &Response(并发访问与响应)的缩写,寓意像一辆灵活的小汽车(Car),而不是按固定路线停靠的公交车(Bus),可以一次携带多个命令,让所有设备同时接收、按顺序回复。
为什么需要 MODCAR?
传统 Modbus 采用“一问一答”的轮询方式:主站依次询问每个从站,总线利用率低,命令到达时间差大,无法满足多轴同步启动、分布式 IO 批量采集等需求。EtherCAT 等实时以太网虽快,但需要专用硬件且成本较高。
MODCAR 在保留 RS‑485 和以太网廉价物理层的前提下,设计了一种复合帧结构:一帧内可包含发给不同从站的多个子请求,所有从站同时收到命令,然后按主站指定的顺序依次返回响应。它实现了:
一帧多命令:减少总线往返次数。
命令同时到达:所有从站在同一时刻收到指令,没有轮询时间差。
响应有序:主站可自由指定回复顺序,从站无需地址排序。
实现简单:仅需微控制器 UART 或 Socket 编程,无需专用芯片。
MODCAR 帧格式(统一版)
MODCAR 同时支持RTU(RS‑485 串行)和TCP/UDP(以太网),两种版本使用完全相同的帧结构,且都保留CRC16校验,确保数据完整性。
主站请求帧
| Len (1B) | N_sub (1B) | 跳转表 (N_sub×1B) | 子请求1 | 子请求2 | ... | 子请求N | CRC16 (2B) |
Len:1 字节,表示从
N_sub开始到最后一个子请求末尾的总字节数(不包含 Len 自身和 CRC)。最大 255,满足多数现场总线。N_sub:子请求个数(1~247)。
跳转表:N 个 1 字节的绝对偏移量。第 i 个值表示第 i 个子请求的起始字节位置(从帧的第一个字节,即 Len 所在位置算起)。
子请求:
[从站地址] [功能码] [参数](地址和数据均为字,即 2 字节,大端序)。CRC16:对
N_sub到最后一个子请求末尾的所有字节计算(多项式 CRC‑16‑CCITT,初值 0xFFFF)。
从站响应帧
| Len (1B) | 从站地址 | 功能码 | 响应数据 | CRC16 (2B) |
Len:表示从站地址到响应数据末尾的字节数(不含 CRC)。
响应数据:
写操作成功:
0x06写操作失败:
0x08(地址/数据非法)或0x09(忙碌/拒绝)读操作成功:读取的数据(长度随功能码变化)
异常:
[Len] [地址] [功能码|0x80] [异常码] CRC
功能码定义(字单位,1字=2字节)
| 码 | 操作 | 请求参数(字节) | 成功响应数据 |
|---|---|---|---|
| 0x01 | 读1字 | [字地址2B] | [数据2B] |
| 0x02 | 读连续2字 | [起始地址2B] | [数据1 2B][数据2 2B] |
| 0x03 | 读N字 | [起始地址2B][字数1B] | [字节数=2N][数据...] |
| 0x04 | 读不连续字 | [数量M1B][地址1 2B]...[地址M 2B] | [字节数=2M][数据1 2B]...[数据M 2B] |
| 0x05 | 读1位 | [字地址2B][位掩码1B] | [位值0/1] |
| 0x11 | 写1字 | [字地址2B][数据2B] | 0x06 |
| 0x12 | 写连续2字 | [起始地址2B][数据1 2B][数据2 2B] | 0x06 |
| 0x13 | 写N字 | [起始地址2B][字数1B][数据...] | 0x06 |
| 0x14 | 写不连续字 | [数量M1B][地址1 2B][数据1 2B]... | 0x06 |
| 0x15 | 写1位 | [字地址2B][位掩码1B][位值0/1] | 0x06 |
位掩码只有 1 个 bit 为 1,例如
0x04表示 bit2。
从站处理流程(六步法)
接收完整帧:根据 Len 字节确定帧长度,收齐所有字节(含 CRC)。
查找自己的 ID 与排名:遍历跳转表指向的地址,若匹配则记录排名序号(第几个子请求)和起始偏移。
CRC 校验:全局校验,错误则丢弃此帧,不发送任何响应。
截取自己的子请求:从偏移处读取功能码和参数。
执行命令:根据功能码进行读/写操作,准备好响应数据(含 Len 字段)。
按排名顺序发送响应:
排名为 1:在帧结束后的最短帧间隔(RTU 为 3.5 字符时间)后立即发送。
排名 > 1:监听总线,等待前一个排名的从站响应结束,然后发送自己的响应。
这样,从站无需关心地址大小,完全由主站通过子请求顺序控制响应次序。
实例:一帧控制三个从站
场景:主站同时向三个从站下达命令,从站地址分别为 0x01、0x03、0x05。
从站 0x01:写 1 个字到地址 0x0001,数据 0x0002。(功能码 0x11)
从站 0x03:写 2 个连续字,从地址 0x0002 开始,数据 0x0000、0x0001。(功能码 0x12)
从站 0x05:读 1 个字,地址 0x0004。(功能码 0x01)
主站请求帧(十六进制)
首先构造子请求原始字节:
子请求1:
01 11 00 01 00 02(6 字节)子请求2:
03 12 00 02 00 00 00 01(8 字节)子请求3:
05 01 00 04(4 字节)
总子请求长度 = 6+8+4 = 18 字节。N_sub = 3,跳转表需要 3 个 1 字节偏移。
跳转表 = [4, 10, 18](因为 Len 占 1 字节,N_sub 占 1 字节,跳转表占 3 字节,共 5 字节前缀;子请求1 从偏移 5 开始?注意:从帧首字节(Len)算起,偏移 0 是 Len,偏移1 是 N_sub,偏移2~4 是跳转表。所以子请求1 的起始偏移 = 5,子请求2 = 5+6=11,子请求3 = 11+8=19。但为了与常见例子一致,我们使用绝对偏移,此处按实际计算。)
重新计算:
Len = 1(N_sub) + 3(跳转表) + 18(子请求总长) = 22 →
0x16跳转地址:
子请求1 从字节索引 5 开始(Len 索引0,N_sub索引1,跳转表索引2~4) → 5
子请求2 从 5+6=11 → 11
子请求3 从 11+8=19 → 19
跳转表字节:
05 0B 13
最终请求帧(不含 CRC):
16 03 05 0B 13 01 11 00 01 00 02 03 12 00 02 00 00 00 01 05 01 00 04
最后附加 CRC16(假设计算值为XX YY)。
从站响应(假设全部成功)
响应顺序由子请求顺序决定:先响应地址 01,再地址 03,最后地址 05。
从站 01(写成功):
03 01 11 06+ CRC从站 03(写成功):
03 03 12 06+ CRC从站 05(读成功,读出 0x1234):
04 05 01 12 34+ CRC
主站依次收到这三个响应帧,通过 Len 字段可正确解析每个响应的边界。
RTU 与 TCP 的区别
| 项目 | MODCAR‑RTU | MODCAR‑TCP/UDP |
|---|---|---|
| 物理层 | RS‑485 半双工 | 以太网全双工 |
| 帧边界 | Len + 空闲时间(3.5字符) | Len(TCP流需拆包,UDP一个报文一帧) |
| 一帧多从 | 广播到所有从站 | UDP广播/组播可达到同样效果;TCP需分别发送 |
| 响应冲突 | 从站按排名顺序+总线监听避让 | 无冲突(独立连接或UDP独立响应) |
| CRC | 必须 | 建议保留(统一且开销很小) |
错误处理
全局 CRC 错:所有从站丢弃整帧,无响应。主站超时后重发。
子请求执行错误:从站返回
[Len] [地址] [功能码|0x80] [异常码] CRC,主站记录并决定是否重试。响应超时:如果主站在预期时间内未收到某个排名的响应,则跳过,继续等待下一个排名,超时结束后统一处理缺失。
总结
MODCAR 是一个轻量级、高效率的工业通信协议,它继承了 Modbus 的易用性,通过复合帧+跳转表+按序响应的设计,实现了“一帧多命令、命令同时到达、响应有序”。无论是老旧 RS‑485 网络还是现代以太网,都可以轻松部署 MODCAR,显著提升多设备协同控制的表现。如果你正在寻找一种比 Modbus 更高效、比 EtherCAT 更简单的协议,不妨试试 MODCAR —— 这辆灵活的小汽车。
MODCAR 协议版本 1.0
开源、免费、欢迎使用和改进