3. 工业设备通信基础

在工业设备应用开发中,上位机与 PLC、变频器、仪表、传感器之间的通信是数据采集与指令控制的基础。串口通信因其简单、稳定、实时性好,至今仍是工业现场最普遍的物理层通信方式之一。本节从串口通信的基本原理出发,梳理 RS232 与 RS485 的电气差异,讲解 Modbus 协议的数据组织方式,并给出 Qt 串口模块的使用方法。

一、串口通信的基本原理

串口通信(UART)是一种异步串行通信方式,数据按位依次在一根信号线上传输。通信双方不需要共享时钟线,而是依靠预先约定的波特率进行采样同步。一次完整的数据帧由起始位、数据位、校验位和停止位组成,常见的配置为 8 位数据位、无校验、1 位停止位,即常说的“8N1”。

关键参数包括:

  • 波特率:每秒传输的位数,如 9600、19200、115200,双方必须一致。
  • 数据位:通常为 7 或 8 位,表示单个字符的有效数据长度。
  • 校验位:无校验、奇校验、偶校验,用于简单检错。
  • 停止位:1 位或 2 位,标志一帧结束。

串口通信是“字节流”通信,没有天然的消息边界。因此在实际应用中,必须依靠协议(如 Modbus)或自定义帧头帧尾来划分数据包,否则会出现粘包、半包问题。

二、RS232 与 RS485 的电气差异

UART 只定义了数据格式,而 RS232 和 RS485 定义的是电气层的物理接口标准。RS232 采用单端信号,逻辑 1 为负电压、逻辑 0 为正电压,传输距离一般不超过 15 米,适合点对点通信,常见于老式仪表和调试口。RS485 采用差分信号,用两根线 A、B 的电压差表示逻辑,抗干扰能力强,传输距离可达 1200 米,支持多点总线,是工业现场的主流选择。

对比项 RS232 RS485
信号方式 单端对地 差分 A/B
传输距离 约 15 米 约 1200 米
拓扑结构 点对点 多点总线
抗干扰能力 较弱 较强
典型场景 调试口、短距设备 PLC、仪表总线
RS485 总线两端需接 120Ω 终端电阻,且所有从站必须共地,否则容易出现通信不稳定或随机丢包。

三、Modbus 协议原理

Modbus 是工业领域最广泛使用的应用层协议之一,采用主从(Master/Slave)模式。主站发起请求,从站响应,从站之间不会主动通信。Modbus 常见两种传输形式:Modbus RTU 运行在串口上,使用二进制编码和 CRC16 校验;Modbus TCP 运行在以太网上,使用 MBAP 报文头。

Modbus 的数据模型由四类寄存器组成:

  • 线圈(Coils):可读写开关量,地址 00001 起。
  • 离散输入(Discrete Inputs):只读开关量,地址 10001 起。
  • 保持寄存器(Holding Registers):可读写 16 位数据,地址 40001 起。
  • 输入寄存器(Input Registers):只读 16 位数据,地址 30001 起。

以读取保持寄存器为例,主站发送的 RTU 帧结构为:从站地址 + 功能码 0x03 + 起始地址 + 寄存器数量 + CRC16。从站返回:从站地址 + 功能码 + 字节数 + 数据 + CRC16。功能码 0x01 读线圈、0x05 写单线圈、0x06 写单寄存器、0x10 写多寄存器,是工程中最常用的几个。

请求:01 03 00 00 00 02 C4 0B
含义:从站 01,读保持寄存器,起始 0x0000,读 2 个
响应:01 03 04 00 64 00 C8 3A 5E
含义:返回 4 字节数据,寄存器 0 = 100,寄存器 1 = 200

四、Qt 串口模块的使用

Qt 从 5.1 开始提供 QtSerialPort 模块,核心类为 QSerialPort 和 QSerialPortInfo。使用前需在工程文件中加入 QT += serialport。QSerialPortInfo 用于枚举可用串口,QSerialPort 负责打开、配置和读写。

QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(QSerialPort::Baud9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);

if (!serial.open(QIODevice::ReadWrite)) {
    qDebug() << "打开失败:" << serial.errorString();
}

connect(&serial, &QSerialPort::readyRead, [&]() {
    QByteArray data = serial.readAll();
    // 解析 Modbus 响应帧
});

QByteArray cmd = QByteArray::fromHex("010300000002C40B");
serial.write(cmd);

在工业场景中,串口数据到达是异步的,必须使用 readyRead 信号驱动接收,不能阻塞等待。建议将接收缓冲区与协议解析分离:先累积字节,再按帧长或超时判断完整帧,最后交给 Modbus 解析函数处理。

常见误区:直接在 readyRead 中假设一次 readAll 就是完整帧。串口可能分多次到达,必须做粘包/半包处理,否则解析会随机失败。

五、典型场景与排障思路

假设上位机通过 RS485 读取一台温控仪表,波特率 9600、8N1、从站地址 1。若通信失败,可按以下顺序排查:

  1. 确认串口号、波特率、校验位与仪表一致。
  2. 用串口助手发送相同报文,验证硬件链路是否通。
  3. 检查 A/B 线是否接反,终端电阻是否匹配。
  4. 确认从站地址与功能码正确,寄存器地址是否偏移 1。
  5. 查看返回帧 CRC 是否正确,判断是否受干扰。

掌握串口通信、RS232/RS485 电气特性和 Modbus 协议后,再结合 QtSerialPort 的异步读写机制,就能构建稳定可靠的工业设备通信层。实际项目中,建议把协议解析封装为独立类,便于复用和单元测试。

工业串口通信链路与 Modbus 数据流 上位机 Qt 应用 QSerialPort readyRead 异步接收 Modbus 帧解析 物理层接口 RS232:单端 / 15m RS485:差分 A/B / 1200m 9600 · 8N1 工业从站设备 PLC / 变频器 / 温控仪表 从站地址 01 保持寄存器 40001 起 请求 RTU 帧 响应 数据 Modbus RTU 请求帧结构(读保持寄存器 0x03) 从站地址 01 功能码 03 起始地址 00 00 寄存器数量 00 02 CRC16 C4 0B → 校验通过后 从站返回数据帧 通信排障顺序 ① 串口号 / 波特率 / 校验位一致 ② 串口助手验证硬件链路 ③ A/B 线是否接反、终端电阻 ④ 从站地址与功能码正确 ⑤ 寄存器地址偏移 ⑥ CRC 校验与干扰排查