2. 通信协议基础:OSI七层模型与TCP/IP四层模型对比、串行通信(RS485/RS232)电气特性、Modbus RTU协议帧结构解析
各位同学,欢迎来到第二讲。今天我们要聊的,是暖通空调通信协议栈的「地基」。
说实话,很多做暖通开发的工程师,一上来就调Modbus,调不通就抓瞎。为什么?因为底层的东西没搞透。我见过太多项目,现场RS485死活通不了,最后发现是A/B线接反了,或者终端电阻没加。这种低级错误,说白了就是基础不牢。
好,我们开始。
2.1 OSI七层模型 vs TCP/IP四层模型
先问大家一个问题:你写Modbus RTU的时候,有没有想过数据是怎么从你的单片机,跑到几公里外的PLC上的?
这就是分层模型要解决的问题。
2.1.1 OSI七层模型——理论上的「完美」
OSI七层模型,从上到下分别是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
我个人习惯把七层模型当成一个「参考系」。实际项目中,没人会完整实现七层。但理解它,能帮你定位问题出在哪一层。
| 层级 | 名称 | 暖通场景举例 |
|---|---|---|
| 7 | 应用层 | Modbus应用命令(读寄存器、写线圈) |
| 6 | 表示层 | 数据编码、加密(暖通很少用) |
| 5 | 会话层 | 建立/断开连接(Modbus无会话概念) |
| 4 | 传输层 | TCP/UDP端口(Modbus TCP用502端口) |
| 3 | 网络层 | IP地址路由(RS485没有这层) |
| 2 | 数据链路层 | Modbus RTU帧、CRC校验 |
| 1 | 物理层 | RS485电平、双绞线、终端电阻 |
2.1.2 TCP/IP四层模型——工业界的「实战派」
TCP/IP四层模型就简单多了:应用层、传输层、网络层、网络接口层。
你想想看,Modbus TCP其实就是把Modbus RTU的帧,塞进TCP包里。应用层还是Modbus那一套,传输层用TCP,网络层用IP,网络接口层用以太网。
为什么暖通行业更喜欢Modbus RTU而不是TCP?
原因很简单:成本。RS485芯片几毛钱,以太网芯片几十块。而且很多老旧设备只有串口,你总不能为了通信把整个空调机组换了吧?
2.2 串行通信电气特性:RS485 vs RS232
好,现在我们把目光聚焦到物理层。这是最容易出问题的地方。
2.2.1 RS232——老前辈,但还在用
RS232是单端信号,一根信号线对地。电压范围:逻辑1是-3V到-15V,逻辑0是+3V到+15V。
缺点很明显:
- 传输距离短,最多15米左右
- 抗干扰差,共模噪声直接叠加在信号上
- 只能点对点,不能组网
我在项目中遇到过,有人用RS232去控制50米外的冷机,结果数据全是乱码。嗯,这其实不是协议的问题,是物理层选型就错了。
2.2.2 RS485——暖通行业的「主力军」
RS485是差分信号,用两根线(A和B)传输。电压差大于+200mV是逻辑1,小于-200mV是逻辑0。
为什么暖通行业偏爱RS485?
- 传输距离远:1200米没问题(加中继还能更远)
- 抗干扰强:差分信号,共模噪声被抵消
- 支持多节点:一条总线最多挂32个设备(标准负载)
2.3 Modbus RTU协议帧结构解析
终于到了重头戏。Modbus RTU是暖通行业的事实标准。几乎所有的冷机、水泵、风机盘管,都支持它。
2.3.1 帧结构概览
一个完整的Modbus RTU帧,长这样:
| 地址码(1字节) | 功能码(1字节) | 数据区(N字节) | CRC校验(2字节) |
就这么简单。但简单不代表容易。我见过有人把CRC算错,导致设备死活不响应。
2.3.2 各字段详解
地址码: 0x01到0xF7(1-247)。0x00是广播地址,所有设备都要响应,但不回复。
注意:同一个总线上,地址不能重复。我曾经遇到一个项目,两台冷机都设成了1号地址,结果一读数据就冲突。
功能码: 常用的就几个:
- 0x03:读保持寄存器(最常用)
- 0x06:写单个寄存器
- 0x10:写多个寄存器
- 0x01:读线圈
- 0x05:写单个线圈
数据区: 根据功能码不同,格式不同。以0x03为例:
请求帧:| 地址 | 0x03 | 起始地址高 | 起始地址低 | 寄存器数量高 | 寄存器数量低 | CRC低 | CRC高 |
响应帧:| 地址 | 0x03 | 字节数 | 数据1高 | 数据1低 | ... | CRC低 | CRC高 |
CRC校验: 这是最容易出错的地方。Modbus RTU使用CRC-16,多项式0x8005,初始值0xFFFF。
2.3.3 实战代码:CRC计算(C语言)
// CRC-16查表法,Modbus RTU专用
uint16_t crc16_modbus(uint8_t *data, uint16_t len)
{
uint16_t crc = 0xFFFF;
uint16_t i, j;
for (i = 0; i < len; i++)
{
crc ^= data[i];
for (j = 0; j < 8; j++)
{
if (crc & 0x0001)
crc = (crc >> 1) ^ 0xA001;
else
crc >>= 1;
}
}
// 注意:Modbus RTU的CRC是低字节在前
return crc;
}
这段代码我用了十年,从来没出过问题。你直接拿去用就行。
2.3.4 帧间隔时间——很多人忽略的细节
Modbus RTU要求帧与帧之间至少有3.5个字符的静默时间。如果小于这个时间,接收端会认为是一帧数据的一部分。
举个例子:波特率9600,一个字符约1ms,3.5个字符就是3.5ms。你发送完一帧后,必须等3.5ms才能发下一帧。
2.4 小结
今天的内容,说白了就是三件事:
- 分层模型帮你定位问题在哪一层
- RS485是暖通通信的物理层首选
- Modbus RTU帧结构简单,但CRC和时序不能马虎
下一讲,我们会深入Modbus功能码的细节,包括如何读写浮点数、如何处理异常响应。到时候我会分享一个我在项目里踩过的坑——读回来的温度数据全是负数,查了半天才发现是字节序搞反了。
好,今天就到这里。有问题随时交流。