4、功能码详解(上):01读线圈、02读离散输入、03读保持寄存器、04读输入寄存器
各位同行,咱们今天聊聊Modbus最基础、也最常用的四个功能码。说实话,搞楼宇自控这么多年,我打交道最多的就是这四位“老兄”。你想想看,现场那些传感器、执行器,说白了就是靠它们来“对话”的。
我个人习惯把这四个功能码分成两组:位操作和字操作。01和02是读“位”的,03和04是读“字”的。先搞清楚这个分类,后面就好办了。
4.1 功能码01:读线圈(Read Coils)
功能码01,用来读取从设备的线圈状态。线圈是什么?就是开关量输出。在楼宇里,最常见的线圈就是继电器、接触器、电磁阀这些。
报文格式
请求报文(主站→从站):
从站地址 功能码 起始地址高字节 起始地址低字节 数量高字节 数量低字节 CRC校验
01 01 00 00 00 0A CRC
响应报文(从站→主站):
从站地址 功能码 字节数 数据1 数据2 ... 数据N CRC校验
01 01 02 CD 6B CRC
实际应用场景
我在项目中遇到过这样一个情况:一个空调机组的送风机启停状态,就是通过线圈来反馈的。主站每隔1秒发一次01功能码,读取风机接触器的辅助触点状态。
关键点:线圈地址从0开始编号。比如你图纸上标的“DO-1”,在Modbus里可能就是地址0。这个坑我踩过,图纸和程序对不上,查了半天才发现是地址偏移的问题。
我的小技巧:读线圈时,一次不要读太多。我一般控制在200个以内。为什么?因为响应报文太长,容易出错。你想想看,一个报文里塞几百个位,万一中间丢一个,整个包就废了。
4.2 功能码02:读离散输入(Read Discrete Inputs)
功能码02,读取离散输入状态。离散输入就是开关量输入,比如按钮、限位开关、水流开关这些。它和线圈最大的区别是:只读不写。
报文格式
请求报文:
从站地址 功能码 起始地址高字节 起始地址低字节 数量高字节 数量低字节 CRC校验
01 02 00 00 00 05 CRC
响应报文:
从站地址 功能码 字节数 数据1 CRC校验
01 02 01 0A CRC
实际应用场景
我记得有个项目,冷机群控系统里,每台冷机的“手自动状态”就是通过离散输入上报的。主站用02功能码轮询,判断冷机是在本地控制还是远程控制。
注意:离散输入和线圈虽然都是位,但千万别搞混。我曾经见过有人用01功能码去读离散输入,结果读回来的数据全是乱的。为什么?因为01是读线圈的,02才是读离散输入的。协议规定死了,不能混用。
4.3 功能码03:读保持寄存器(Read Holding Registers)
功能码03,读取保持寄存器。这是Modbus里最常用的功能码,没有之一。保持寄存器是16位的,可读可写。在楼宇自控里,温度、湿度、压力、流量这些模拟量,基本都是通过保持寄存器来传输的。
报文格式
请求报文:
从站地址 功能码 起始地址高字节 起始地址低字节 数量高字节 数量低字节 CRC校验
01 03 00 01 00 02 CRC
响应报文:
从站地址 功能码 字节数 数据1高 数据1低 数据2高 数据2低 CRC校验
01 03 04 00 64 00 C8 CRC
实际应用场景
举个具体的例子。一个风管温度传感器,量程0~50℃,输出4~20mA,经过AI模块转换成数字量。这个数字量就存在保持寄存器里。主站用03功能码读回来,再根据公式换算成实际温度。
避坑指南:我曾经遇到过一个问题:读回来的温度值忽高忽低。排查了半天,发现是寄存器地址搞错了。图纸上写的是“40001”,但实际Modbus地址是0。记住:PLC地址和Modbus地址差1。40001对应Modbus地址0,40002对应地址1,以此类推。
我的习惯:读保持寄存器时,一次读多个连续的寄存器。比如读一个温度传感器,我通常会把温度、湿度、压力一起读回来。这样效率高,一个报文搞定三个数据。但注意,一次最多读125个寄存器(250字节),别超了。
4.4 功能码04:读输入寄存器(Read Input Registers)
功能码04,读取输入寄存器。输入寄存器和保持寄存器很像,都是16位的。唯一的区别是:输入寄存器只读不写。它通常用来读取传感器采集的原始数据。
报文格式
请求报文:
从站地址 功能码 起始地址高字节 起始地址低字节 数量高字节 数量低字节 CRC校验
01 04 00 00 00 03 CRC
响应报文:
从站地址 功能码 字节数 数据1高 数据1低 数据2高 数据2低 数据3高 数据3低 CRC校验
01 04 06 00 01 00 02 00 03 CRC
实际应用场景
我记得有个项目,用的是进口的温湿度变送器。它的温度值放在输入寄存器里,湿度值也放在输入寄存器里。主站用04功能码读回来,然后做数据处理。
重要提醒:03和04虽然都是读寄存器,但千万别混用。我见过有人用03去读输入寄存器,结果读回来的数据全是0。为什么?因为03是读保持寄存器的,04才是读输入寄存器的。协议规定死了,不能混用。
4.5 四个功能码的对比总结
| 功能码 | 名称 | 操作对象 | 读写属性 | 数据宽度 | 典型应用 |
|---|---|---|---|---|---|
| 01 | 读线圈 | 开关量输出 | 只读 | 1位 | 继电器状态、风机启停 |
| 02 | 读离散输入 | 开关量输入 | 只读 | 1位 | 按钮状态、限位开关 |
| 03 | 读保持寄存器 | 模拟量输出 | 可读可写 | 16位 | 温度、压力、设定值 |
| 04 | 读输入寄存器 | 模拟量输入 | 只读 | 16位 | 传感器原始数据 |
嗯,这四个功能码,说白了就是Modbus通信的“四把钥匙”。搞懂了它们,你就掌握了Modbus读操作的精髓。下一章咱们聊写操作——05写单线圈、06写单寄存器、15写多线圈、16写多寄存器。到时候你会发现,写操作比读操作更有意思。
一句话总结:01和02读位,03和04读字。位操作看开关,字操作看模拟量。记住这个,你就不会搞混了。