3、通讯协议入门:RS232/RS485串口通讯原理、Modbus RTU协议详解、Modbus TCP协议详解
做视觉控制器跟PLC打交道,通讯协议是绕不开的坎。我刚开始搞自动化那会儿,总觉得协议这东西太抽象,不就是两根线来回传数据嘛?后来被现实狠狠教育了一顿——线接对了,数据传不过来;数据传过来了,解析出来全是乱码。说白了,通讯协议就是双方约定好的「说话方式」,你说中文我说英文,鸡同鸭讲。
这一章,咱们就把串口通讯和Modbus协议彻底捋清楚。你想想看,工厂里90%以上的PLC都支持Modbus,搞懂了它,基本就能搞定大部分设备。
核心知识点速览
- RS232 vs RS485:谁更适合工业现场?
- Modbus RTU:数据怎么打包、校验、解析?
- Modbus TCP:跟RTU有啥区别?
- 实战中常见的坑和避坑方法
3.1 RS232与RS485串口通讯原理
串口通讯,说白了就是一位一位地传数据。就像两个人打电话,一个字一个字地说。RS232和RS485是两种最常见的物理层标准,决定了信号怎么在线上跑。
RS232:老当益壮的点对点通讯
RS232是最早的串口标准之一。我记得十几年前调试第一台设备,用的就是RS232。它的特点是:
- 传输距离短:一般不超过15米。我在一个项目里硬拉了20米,结果数据全乱套了。
- 点对点通讯:一台设备只能跟另一台设备通信,不能多站组网。
- 电压信号:用-3V~-15V表示逻辑1,+3V~+15V表示逻辑0。抗干扰能力一般。
- 全双工:可以同时发送和接收数据。
实战小技巧
RS232的DB9接口,2脚是RXD(接收),3脚是TXD(发送),5脚是GND。我见过太多人把2和3接反了,结果死活通不上。记住:交叉连接——这边的TXD接那边的RXD。
RS485:工业现场的王者
RS485才是工业自动化里的主力。为什么?因为它能解决RS232的痛点。
- 差分信号传输:用两根线(A+和B-)的电压差来表示数据。抗干扰能力极强,我曾在变频器旁边拉RS485线,一点问题没有。
- 传输距离远:理论可达1200米。实际项目中我用到过800米,稳定得很。
- 多站组网:一条总线上可以挂32个节点(用中继器可以更多)。
- 半双工:同一时刻只能发送或接收,不能同时进行。
⚠️ 避坑指南
我曾经在一个项目里,RS485总线接了15台设备,结果通讯时好时坏。查了两天才发现——终端电阻没加!记住:总线两端必须各加一个120Ω的终端电阻,用来消除信号反射。不加的话,长距离通讯必出问题。
3.2 Modbus RTU协议详解
Modbus RTU是工业自动化领域最常用的通讯协议之一。它运行在RS232/RS485物理层之上,定义了数据怎么打包、怎么校验、怎么解析。
报文结构
Modbus RTU的报文结构很简单,就三部分:
| 地址码 | 功能码 | 数据区 | CRC校验 |
|---|---|---|---|
| 1字节 | 1字节 | N字节 | 2字节 |
| 设备地址 1~247 | 03读、06写、16批量写 | 寄存器地址+数据 | CRC16低字节在前 |
举个例子,读取地址为1的PLC的3个寄存器,从起始地址0x0000开始:
请求报文:01 03 00 00 00 03 05 CB
- 01:设备地址
- 03:功能码(读保持寄存器)
- 00 00:起始寄存器地址
- 00 03:读取数量(3个寄存器)
- 05 CB:CRC16校验
响应报文:01 03 06 00 01 00 02 00 03 9A 9B
- 01:设备地址
- 03:功能码
- 06:数据字节数(3个寄存器×2字节)
- 00 01 00 02 00 03:三个寄存器的值
- 9A 9B:CRC16校验
常用功能码
实际项目中,90%的情况只用这三个功能码:
- 03 (0x03):读取保持寄存器。读PLC的D寄存器、数据块都用这个。
- 06 (0x06):写单个寄存器。适合设置参数、启停控制。
- 16 (0x10):写多个寄存器。批量下数据时用,效率高。
寄存器地址的坑
Modbus协议里,寄存器地址从0开始编号。但很多PLC的编程软件里,地址是从1开始显示的。比如三菱PLC的D100,在Modbus里对应的地址是0x0063(99)。我刚开始做项目时,直接用了D100的编号100去读,结果读回来的数据完全不对。记住:协议地址 = PLC地址 - 1。
CRC16校验
CRC校验是Modbus RTU的保命符。没有它,数据传错了你都不知道。计算方法是:
uint16_t crc16(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
这段代码我用了十年,从来没出过问题。注意:发送时低字节在前,高字节在后。
3.3 Modbus TCP协议详解
Modbus TCP就是把Modbus RTU搬到以太网上。说白了,去掉CRC校验,加上一个MBAP报文头,用TCP/IP传输。
Modbus TCP vs Modbus RTU
| 对比项 | Modbus RTU | Modbus TCP |
|---|---|---|
| 物理层 | RS232/RS485 | 以太网 |
| 传输速率 | 9600~115200 bps | 10/100/1000 Mbps |
| 设备地址 | 需要(1~247) | 不需要(用IP区分) |
| 校验 | CRC16 | TCP/IP自带校验 |
| 报文头 | 无 | MBAP头(7字节) |
MBAP报文头
Modbus TCP的报文结构:
MBAP头(7字节) + 功能码(1字节) + 数据区(N字节)
MBAP头结构:
- 事务处理标识符(2字节):用于匹配请求和响应
- 协议标识符(2字节):固定为0x0000
- 长度(2字节):后续字节数
- 单元标识符(1字节):相当于RTU的设备地址
举个例子,读取IP为192.168.1.100的PLC的3个寄存器:
请求报文:00 01 00 00 00 06 01 03 00 00 00 03
- 00 01:事务ID
- 00 00:协议ID
- 00 06:后续长度(6字节)
- 01:单元ID(设备地址)
- 03:功能码
- 00 00:起始地址
- 00 03:读取数量
我的经验
Modbus TCP比RTU简单多了,不用算CRC,不用管地址冲突。但有个坑:很多PLC的Modbus TCP端口不是默认的502。我遇到过一台设备用的是5000端口,查了半天手册才发现。所以拿到设备第一件事——确认端口号。
3.4 实战中的通讯调试技巧
通讯调试是门手艺活。我总结了几条经验:
- 先确认物理层:用示波器看波形,或者用串口助手发数据看回显。物理层不通,上层协议再对也没用。
- 用Modbus调试工具:我常用ModScan(模拟主站)和ModSim(模拟从站)。先跟模拟器通,再跟真实设备通。
- 抓包分析:Wireshark抓Modbus TCP包,Serial Port Monitor抓串口数据。看原始报文,问题一目了然。
- 注意超时处理:PLC的响应时间一般在10~100ms。我习惯设500ms超时,重试3次。太短容易误判,太长影响效率。
⚠️ 我曾经踩过的坑
有一次调试视觉控制器跟西门子S7-1200通讯,Modbus TCP怎么都连不上。查了IP、端口、寄存器地址,全对。最后发现——S7-1200默认不开启Modbus TCP服务器功能,需要在程序里调用"MB_SERVER"指令块。嗯,这种软配置问题最坑人。
通讯协议这东西,说白了就是约定。你遵守约定,设备就听你的。RS232/RS485是物理层的约定,Modbus是应用层的约定。搞懂了这些,视觉控制器跟PLC对话就是小菜一碟。
公众号:蓝海资料掘金营,微信deep3321