4、核心通信协议(二):Modbus TCP 协议、与RTU的区别、网关配置

好,咱们接着聊。上一章我们把 Modbus RTU 扒了个底朝天,今天轮到它的“大哥”——Modbus TCP 登场了。

说实话,在充电桩这个行当里,RTU 和 TCP 你都得玩得转。RTU 多见于桩体内部,比如主控板和充电模块之间的通信;而 TCP 呢,更多是桩和后台系统、桩和云平台之间的“对话”。

我个人习惯把 Modbus TCP 看作是 RTU 的“网络升级版”。它俩本质上是同一套“语言”,只是“传输方式”变了。你想想看,RTU 走的是串口,一根线一根线地传;TCP 走的是以太网,用网线或者 WiFi,速度更快,距离更远。

4.1 Modbus TCP 协议:到底改了啥?

Modbus TCP 的报文结构,说白了就是在 RTU 的基础上,去掉了 CRC 校验,加了一个 MBAP 报文头。为什么去掉 CRC?因为 TCP/IP 协议栈自己会做校验,你再加一层就是画蛇添足。

MBAP 头一共 7 个字节,结构如下:

字段 长度(字节) 说明
事务处理标识符 2 用于匹配请求和响应,一般每次通信加1
协议标识符 2 固定为 0x0000,表示 Modbus 协议
长度 2 后续数据的字节数(从单元标识符开始算)
单元标识符 1 相当于 RTU 里的从站地址

嗯,这里要注意:单元标识符 这个字段,在纯 TCP 模式下其实用处不大,因为 IP 地址已经能区分设备了。但很多充电桩厂家为了兼容老系统,还是会用它来区分桩内的不同模块。

核心区别一句话总结:

RTU = 地址 + 功能码 + 数据 + CRC

TCP = MBAP头 + 功能码 + 数据

我在项目中遇到过一台老款充电桩,后台系统死活连不上。查了半天,发现是 MBAP 头里的“长度”字段算错了。它把整个报文长度都算进去了,而标准要求只算“单元标识符+功能码+数据”的长度。就这一个字节的偏差,折腾了我一整天。

4.2 Modbus TCP 与 RTU 的深度对比

很多新手会问:既然 TCP 这么好,为什么还要用 RTU?

原因很简单:成本和场景。一个 RS485 收发器几毛钱,一个以太网 PHY 芯片要几块钱。而且很多充电桩内部空间有限,走串口布线比走网线方便得多。

我整理了一个对比表,你一看就明白:

对比项 Modbus RTU Modbus TCP
物理层 RS232/RS485 以太网(RJ45、光纤)
传输距离 约 1200 米(RS485) 100 米(网线),可扩展
传输速率 一般 9600~115200 bps 10/100/1000 Mbps
从站数量 最多 247 个 理论上无限制(靠 IP 区分)
校验方式 CRC16 TCP/IP 协议栈校验
报文格式 地址+功能码+数据+CRC MBAP头+功能码+数据
典型应用 充电模块、电表、温控 后台系统、云平台、HMI

你看,两者各有千秋。我个人建议:桩内通信用 RTU,桩外通信用 TCP。这是最稳妥的方案。

避坑指南:

我曾经在一个项目中,把充电桩的 BMS 通信也改成了 TCP。结果发现 BMS 报文对实时性要求极高,TCP 的重传机制反而导致了延迟。后来乖乖换回 RTU,问题迎刃而解。所以,别盲目追求“高大上”,合适才是最好的。

4.3 网关配置:让 RTU 和 TCP 握手

现实中的充电桩系统,往往是 RTU 和 TCP 混用的。比如:桩内的充电模块走 RTU,但桩本身要跟云平台走 TCP。这时候就需要一个“翻译官”——Modbus 网关

网关的作用很简单:把 TCP 请求转成 RTU 请求,再把 RTU 响应转回 TCP 响应。你想想看,云平台发一个 TCP 报文过来,网关收到后,剥掉 MBAP 头,加上地址和 CRC,通过串口发给充电模块;充电模块回复后,网关再剥掉地址和 CRC,加上 MBAP 头,通过网口回给云平台。

配置网关时,有几个关键参数必须设对:

  1. IP 地址和端口:网关的 IP 要跟后台系统在同一个网段,端口一般用 502(Modbus TCP 默认端口)。
  2. 串口参数:波特率、数据位、停止位、校验位,必须跟充电模块一致。我见过最坑的情况是,网关和模块的波特率都是 9600,但一个设了偶校验,一个设了无校验,结果通信时好时坏。
  3. 从站地址映射:TCP 报文里的单元标识符,要能正确映射到 RTU 的从站地址。比如单元标识符 1 对应从站地址 0x01。
  4. 超时时间:网关等待 RTU 响应的超时时间。设太短,模块还没回复就超时了;设太长,系统响应慢。我一般设 500ms~1000ms。

下面是一个典型的网关配置示例(以某品牌网关为例):

# 网络参数
IP地址:192.168.1.100
子网掩码:255.255.255.0
默认网关:192.168.1.1
监听端口:502

# 串口参数(COM1)
波特率:9600
数据位:8
停止位:1
校验位:无

# 映射规则
单元标识符 1 -> 从站地址 0x01
单元标识符 2 -> 从站地址 0x02
单元标识符 3 -> 从站地址 0x03

# 超时设置
RTU响应超时:800ms
TCP连接超时:30000ms

重要提醒:

网关的“RTU响应超时”一定要比充电模块的“处理时间”长。我曾经遇到一个情况:模块处理一个写命令需要 200ms,但网关的超时设成了 150ms。结果每次写操作都失败,后台报“通信超时”。查了三天才找到原因,真是血的教训。

4.4 实战经验:调试中的那些坑

最后,分享几个我在调试 Modbus TCP 网关时遇到的典型问题:

  • 端口被占用:有时候电脑上开了多个 Modbus 调试工具,端口 502 被占用了。用 netstat -ano | findstr :502 查一下,把占用的进程干掉。
  • 防火墙拦截:Windows 防火墙默认会拦截 502 端口。要么关防火墙,要么加一条入站规则。我建议加规则,别图省事直接关防火墙。
  • IP 冲突:同一个局域网里,两个设备用了同一个 IP。用 ping 命令先测一下,确保 IP 没被占用。
  • 报文长度不对:TCP 是流式协议,没有帧的概念。有时候一次 recv 可能只收到半个报文,或者收到多个报文。代码里一定要做“粘包处理”,根据 MBAP 头的长度字段来分包。

嗯,说到粘包处理,我给大家一个简单的思路:先收 6 个字节(MBAP 头的前 6 个字节),解析出“长度”字段,再收剩下的字节。这样就能保证一次收一个完整的报文。

好了,这一章的内容就到这里。Modbus TCP 其实不难,关键是理解它和 RTU 的差异,以及网关的配置逻辑。下一章我们聊聊更高级的协议——OCPP,那是充电桩和云平台之间的“官方语言”,内容会更精彩。