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个设备(标准负载)
避坑指南: 我曾经在一个大型冷站项目中,发现通信时好时坏。查了两天,最后发现是A/B线接反了。记住:A接A,B接B,不要想当然。另外,终端电阻一定要加,120欧姆,只在总线两端加。

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。

核心要点: CRC计算时,低字节在前,高字节在后。很多新手搞反了顺序,导致校验失败。我建议你直接用现成的查表法,别自己手算,容易出错。

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才能发下一帧。

我的习惯: 我一般把帧间隔设成5ms,留点余量。有些国产设备对时序要求比较苛刻,间隔太短会丢帧。宁可慢一点,也要稳一点。

2.4 小结

今天的内容,说白了就是三件事:

  • 分层模型帮你定位问题在哪一层
  • RS485是暖通通信的物理层首选
  • Modbus RTU帧结构简单,但CRC和时序不能马虎

下一讲,我们会深入Modbus功能码的细节,包括如何读写浮点数、如何处理异常响应。到时候我会分享一个我在项目里踩过的坑——读回来的温度数据全是负数,查了半天才发现是字节序搞反了。

好,今天就到这里。有问题随时交流。