从零搭建厂务数据采集:Modbus TCP与RTU通信调试 - 第2节
2. Modbus协议基础
Modbus协议由Modicon公司(现施耐德电气旗下)于1979年发明,最初用于可编程逻辑控制器(PLC)之间的通信。作为工业自动化领域最早开放的通信协议之一,Modbus经历了从串行总线到以太网的演进,至今仍是厂务数据采集系统中最广泛使用的协议。
2.1.1 关键发展里程碑
| 年份 | 事件 | 意义 |
|---|---|---|
| 1979 | Modicon发布Modbus串行协议 | 首个公开、免授权的工业通信协议 |
| 1990s | Modbus RTU/ASCII成为事实标准 | RS-232/RS-485物理层广泛部署 |
| 1999 | Modbus TCP/IP规范发布 | 基于以太网,端口502,与互联网技术融合 |
| 2004 | Modbus组织移交至Modbus-IDA | 标准化维护,推动互操作性认证 |
| 2007 | Modbus成为国家标准GB/T 19582 | 中国工业自动化领域强制推荐标准 |
课程提示: 理解Modbus的历史有助于判断现场设备的通信能力。1990年代前的设备通常只支持Modbus RTU,2000年后的新设备普遍同时支持RTU和TCP。
2.2 物理层与协议栈
Modbus协议栈采用分层设计,物理层决定了信号的传输介质和电气特性,数据链路层定义了帧格式和差错校验,应用层则规定了功能码和数据模型。不同物理层对应不同的通信变体。
2.2.1 物理层对比
| 特性 | Modbus RTU | Modbus ASCII | Modbus TCP |
|---|---|---|---|
| 物理介质 | RS-232 / RS-485 | RS-232 / RS-485 | 以太网(RJ45) |
| 最大距离 | RS-232: 15m / RS-485: 1200m | 同RTU | 100m(交换机级联可扩展) |
| 传输速率 | 9600~115200 bps | 同RTU(但效率低) | 10/100/1000 Mbps |
| 节点数量 | RS-485: 最多32节点(可中继扩展) | 同RTU | 理论上无限制(IP地址空间) |
| 帧格式 | 二进制(8位数据位) | ASCII字符(16进制可读) | TCP/IP报文封装 |
| 校验方式 | CRC-16(循环冗余校验) | LRC(纵向冗余校验) | TCP/IP协议栈校验 |
工程避坑: 在厂务数据采集项目中,Modbus RTU(RS-485)是最常见的物理层。注意RS-485总线必须使用双绞屏蔽线,并在两端加120Ω终端电阻,否则长距离通信会出现数据丢包或乱码。
2.2.2 协议栈分层模型
Modbus TCP/IP协议栈遵循OSI模型简化分层,Modbus RTU则直接映射到物理层和数据链路层。
协议栈对比:
- Modbus TCP: 应用层(Modbus)→ 传输层(TCP)→ 网络层(IP)→ 链路层(以太网)
- Modbus RTU: 应用层(Modbus)→ 数据链路层(RTU帧)→ 物理层(RS-485)
2.3 主从架构与通信模型
Modbus采用严格的主从(Master/Slave)通信架构,在Modbus TCP中称为客户端/服务器(Client/Server)。整个网络中只有一个主站(Master/Client),其余均为从站(Slave/Server)。主站发起所有通信请求,从站只能响应,不能主动发送数据。
2.3.1 主从架构核心规则
- 单主站原则: 同一时刻只能有一个主站设备,避免总线冲突。
- 轮询机制: 主站依次向每个从站发送请求帧,从站回复响应帧。
- 从站地址: 每个从站拥有唯一地址(1~247),地址0为广播地址。
- 超时处理: 主站发送请求后启动定时器,若超时未收到响应则重试或报错。
2.3.2 通信模型对比
| 特性 | Modbus RTU(串行) | Modbus TCP(以太网) |
|---|---|---|
| 主站角色 | Master(通常为PLC、上位机) | Client(通常为SCADA、边缘网关) |
| 从站角色 | Slave(传感器、执行器、仪表) | Server(支持TCP的智能设备) |
| 通信方式 | 半双工(RS-485)或全双工(RS-232) | 全双工(以太网) |
| 连接方式 | 总线型(所有设备挂接在同一对双绞线上) | 星型(通过交换机连接) |
| 地址标识 | 从站地址(1字节,1~247) | IP地址 + 端口号(默认502) |
| 并发能力 | 单线程轮询,一次只能与一个从站通信 | 多线程并发,可同时与多个服务器通信 |
2.3.3 通信流程示例
以下是一个典型的Modbus RTU读取保持寄存器的通信流程:
- 主站发送请求帧: 从站地址 + 功能码 + 起始地址 + 寄存器数量 + CRC校验
- 从站接收并解析: 校验地址匹配 → 校验CRC → 执行功能码操作
- 从站返回响应帧: 从站地址 + 功能码 + 数据字节数 + 数据 + CRC校验
- 主站校验响应: 校验CRC → 提取数据 → 更新数据库或界面
Python伪代码示例: 主站发送读取请求
import struct
# 构建Modbus RTU读取保持寄存器请求帧
slave_addr = 0x01 # 从站地址1
function_code = 0x03 # 读取保持寄存器
start_addr = 0x0064 # 起始地址100
quantity = 0x0002 # 读取2个寄存器
# 组装报文(不含CRC)
frame = struct.pack('>BBHH', slave_addr, function_code, start_addr, quantity)
# 计算CRC-16并追加
crc = calculate_crc16(frame)
frame += struct.pack('<H', crc)
# 通过串口发送
serial_port.write(frame)
2.3.4 数据模型与地址空间
Modbus协议定义了四种基本数据对象类型,每种类型对应不同的功能码和地址范围。理解数据模型是正确配置采集点的前提。
| 数据对象 | 访问类型 | 数据大小 | 地址范围(PLC习惯) | 常用功能码 |
|---|---|---|---|---|
| 线圈(Coil) | 读写 | 1位(0/1) | 00001~09999 | 01(读)、05(写单)、15(写多) |
| 离散输入(Discrete Input) | 只读 | 1位(0/1) | 10001~19999 | 02(读) |
| 输入寄存器(Input Register) | 只读 | 16位(0~65535) | 30001~39999 | 04(读) |
| 保持寄存器(Holding Register) | 读写 | 16位(0~65535) | 40001~49999 | 03(读)、06(写单)、16(写多) |
工程经验: 在厂务数据采集中,90%以上的数据点来自保持寄存器(Holding Register),例如温度、压力、流量、液位等模拟量。线圈(Coil)常用于控制阀门开关、电机启停等数字量输出。
2.3.5 功能码速查表
| 功能码 | 名称 | 操作对象 | 典型用途 |
|---|---|---|---|
| 01 (0x01) | 读取线圈 | 线圈 | 读取DO状态 |
| 02 (0x02) | 读取离散输入 | 离散输入 | 读取DI状态 |
| 03 (0x03) | 读取保持寄存器 | 保持寄存器 | 读取AI/参数 |
| 04 (0x04) | 读取输入寄存器 | 输入寄存器 | 读取AI |
| 05 (0x05) | 写单个线圈 | 线圈 | 控制DO |
| 06 (0x06) | 写单个寄存器 | 保持寄存器 | 设定参数 |
| 15 (0x0F) | 写多个线圈 | 线圈 | 批量控制DO |
| 16 (0x10) | 写多个寄存器 | 保持寄存器 | 批量设定参数 |
常见误区: 初学者容易混淆“输入寄存器”和“保持寄存器”。输入寄存器只能读取(如传感器实时值),保持寄存器可读可写(如设定值、累计量)。在Modbus TCP中,地址偏移量(如40001)仅用于PLC习惯标识,实际报文中的地址从0开始。
2.4 本章小结
- Modbus协议自1979年诞生,经历了从串行到以太网的演进,是厂务数据采集的基石。
- 物理层选择直接影响通信距离、速率和抗干扰能力:RS-485适合长距离多节点,以太网适合高速大容量。
- 主从架构是Modbus的核心通信模型,主站轮询、从站响应,地址唯一性至关重要。
- 四种数据对象(线圈、离散输入、输入寄存器、保持寄存器)覆盖了数字量和模拟量的读写需求。
- 功能码是操作指令,03/04读寄存器、06/16写寄存器是厂务采集最常用的功能码。