Date | Author | Version | Note |
---|---|---|---|
2022.07.19 | Dog Tao | V1.0 | 1. 完成了文档的撰写。 |
2023.08.04 | Dog Tao | V1.2 | 1. 修订文档,增加了Modbus协议简介小节。 |
本文档提供ModbusPoll调试软件与官方部署文档合辑资源(CSDN平台)。
文章目录
-
- Modbus协议简介
- 基本规范与功能码
-
- Modbus寄存器地址规则
- [Modbus RTU报文基本格式](#Modbus RTU报文基本格式)
- 功能码01:读线圈寄存器(开关量输出)
- 功能码02:读离散寄存器(开关量输入)
- 功能码03:读保持寄存器(模拟量输出)
- 功能码04:读输入寄存器(模拟量输入)
- 功能码05:写单线圈(开关量输出)
- 功能码06:写单保持寄存器(模拟量输出)
- [功能码15 (0x0F):写多线圈(开关量输出)](#功能码15 (0x0F):写多线圈(开关量输出))
- [功能码16 (0x10):写多保持寄存器(模拟量输出)](#功能码16 (0x10):写多保持寄存器(模拟量输出))
- 读寄存器测试指令
Modbus协议简介
发展历史
Modbus是一种通信协议,广泛用于工业控制系统之间的通信。它由Modicon(现在的施耐德电气)于1979年开发,用于与其PLC(可编程逻辑控制器)进行通信。Modbus协议主要有两个版本:Modbus RTU和Modbus TCP/IP。
-
Modbus RTU:Modbus RTU是一种串行通信协议,通常在RS-485串行接口上运行。它是二进制协议,数据在总线上以连续字节的形式传输。每条消息都以设备地址开始,由功能代码(指示操作类型)和数据字节(包含操作数据)组成,并以两字节的循环冗余校验(CRC)结束,用于检测消息传输中的错误。
-
Modbus TCP/IP:Modbus TCP/IP是基于以太网的Modbus协议版本。它在Modbus RTU的基础上增加了MBAP(Modbus Application Protocol)头部,以在TCP/IP网络上提供设备寻址和错误检测。Modbus TCP/IP通常在502端口上运行。
主要技术说明
-
寻址:在Modbus协议中,每个设备都有一个唯一的地址。在RS-485网络中,地址范围是0-247。地址0是广播地址,发送到此地址的消息将被网络上的所有设备接收。
-
寄存器:Modbus设备包含四种类型的寄存器:离散输入(只读)、线圈(可读写)、输入寄存器(只读)和保持寄存器(可读写)。每个寄存器都有一个唯一的地址,用于从设备读取或向设备写入数据。
-
功能代码:Modbus协议定义了一组功能代码,用于指示要执行的操作,如读取寄存器(功能代码03或04)或写入寄存器(功能代码06或16)。如果设备不能执行请求的操作,它将返回一个异常响应,包含一个错误码。
-
消息格式:Modbus消息由地址、功能码、数据和错误检查部分组成。在Modbus RTU中,错误检查通过CRC实现,而在Modbus TCP/IP中,通过MBAP头部的协议标识符和长度字段实现。
Modbus协议是一种简单、开放的协议,广泛用于工业自动化和嵌入式系统应用。尽管它已经存在了几十年,但由于其稳定性和易用性,它仍然是工业通信的主要标准之一。
基本规范与功能码
Modbus寄存器地址规则
Modbus协议定义的寄存器地址是5位十进制地址,即:
- 线圈寄存器(Coils Register)地址:00001~09999
- 离散寄存器(Discrete Register)地址:10001~19999
- 输入寄存器(Input Register)地址:30001~39999
- 保持寄存器(Holding Register)地址:40001~49999
由于上述各类地址是唯一对应的,因此有些资料就以其第一个数字区分各类地址 ,即:++0x代表线圈寄存器(CR)类地址,1x代表离散寄存器(DR)类地址、 3x代表输入寄存器(IR)类地址、4x代表保持寄存器(HR)类地址++。
在实际编程中,由于前缀的区分作用,所以只需说明后4位数,而且需转换为4位十六进制地址。
Modbus RTU报文基本格式
间隔 | 目标站号 | 功能码 | 数据 | CRC16校验 |
---|---|---|---|---|
起始应有不小于3.5个字符的报文间隔 | 1字节 | 1字节 | n字节 | 2字节 |
下面对于各请求命令的"应答格式"的描述是指命令被正确执行时的应答格式。若CPU接收到错误的命令或者命令被执行错误,则返回的应答帧中"功能码"部分变为如下数据:功能码的最高位置1后得到的数据。比如功能码为01,若响应错误,则返回的功能码为0x81。
功能码01:读线圈寄存器(开关量输出)
- 请求格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址 低字节 | 读取个数 高字节 | 读取个数 低字节 | CRC |
---|---|---|---|---|---|---|
1字节 | 01 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
- 正确应答格式:
站号 | 功能码 | 返回数据字节数 | 返回数据字节1 | 返回数据字节2 | ... | CRC |
---|---|---|---|---|---|---|
1字节 | 01 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
功能码02:读离散寄存器(开关量输入)
- 请求格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址 低字节 | 读取个数 高字节 | 读取个数 低字节 | CRC |
---|---|---|---|---|---|---|
1字节 | 02 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
- 正确应答格式:
站号 | 功能码 | 返回数据字节数 | 返回数据字节1 | 返回数据字节2 | ... | CRC |
---|---|---|---|---|---|---|
1字节 | 02 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
功能码03:读保持寄存器(模拟量输出)
- 请求格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址 低字节 | 读取个数 高字节 | 读取个数 低字节 | CRC |
---|---|---|---|---|---|---|
1字节 | 03 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
- 正确应答格式:
站号 | 功能码 | 返回数据字节数 | 寄存器1高字节 | 寄存器1低字节 | ... | CRC |
---|---|---|---|---|---|---|
1字节 | 03 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
功能码04:读输入寄存器(模拟量输入)
- 请求格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址 低字节 | 读取个数 高字节 | 读取个数 低字节 | CRC |
---|---|---|---|---|---|---|
1字节 | 04 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
- 正确应答格式:
站号 | 功能码 | 返回数据字节数 | 寄存器1高字节 | 寄存器1低字节 | ... | CRC |
---|---|---|---|---|---|---|
1字节 | 04 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
功能码05:写单线圈(开关量输出)
- 请求格式:
目标站号 | 功能码 | 线圈地址 高字节 | 线圈地址 低字节 | 强制值 高字节 | 强制值 低字节 | CRC校验码 |
---|---|---|---|---|---|---|
1字节 | 05 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
注:强制值= 0xFF00,则置线圈为ON;强制值=0x0000,则置线圈为OFF。
- 应答格式:若设置成功,原文返回
功能码06:写单保持寄存器(模拟量输出)
- 请求格式:
目标站号 | 功能码 | 寄存器地址 高字节 | 寄存器地址 低字节 | 强制值 高字节 | 强制值 低字节 | CRC校验码 |
---|---|---|---|---|---|---|
1字节 | 06 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
- 应答格式:若设置成功,原文返回
功能码15 (0x0F):写多线圈(开关量输出)
- 请求格式:
目标 站号 | 功能码 | 起始地址 高字节 | 起始地址低字节 | 数量 高字节 | 数量 低字节 | 强制值字节数 | 强制值 第1字节 | ... | CRC |
---|---|---|---|---|---|---|---|---|---|
1字节 | 15 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
- 正确应答格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址低字节 | 数量 高字节 | 数量 低字节 | CRC校验码 |
---|---|---|---|---|---|---|
1字节 | 15 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
功能码16 (0x10):写多保持寄存器(模拟量输出)
- 请求格式:
目标 站号 | 功能码 | 起始地址 高字节 | 起始地址低字节 | 数量 高字节 | 数量 低字节 | 强制值字节数 | 强制值1 高字节 | 强制值1 低字节 | ... | CRC |
---|---|---|---|---|---|---|---|---|---|---|
1字节 | 16 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | ... | 2字节 |
- 正确应答格式:
目标站号 | 功能码 | 起始地址 高字节 | 起始地址低字节 | 数量 高字节 | 数量 低字节 | CRC 校验码 |
---|---|---|---|---|---|---|
1字节 | 16 | 1字节 | 1字节 | 1字节 | 1字节 | 2字节 |
读寄存器测试指令
线圈寄存器-读命令(0x01)
从机地址 | 寄存器地址 | 寄存器数量 | 网络指令 | modbus指令 | 说明 | 参考回复 |
---|---|---|---|---|---|---|
0x01 | 0x999 | 0x02 | 00 32 17 | 01 01 03 E7 00 01 4D B9 | 读取输入寄存器第一个位值 | 01 01 01 00 51 88 |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 01 03 E7 00 02 0D B8 | 读取输入寄存器前二个位值 | |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 01 03 E7 00 04 8D BA | 读取输入寄存器前四个位值 | |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 01 03 E7 00 08 8D BF | 读取输入寄存器前八个位值 |
离散寄存器-读命令(0x02)
从机地址 | 寄存器地址 | 寄存器数量 | 网络指令 | modbus指令 | 说明 |
---|---|---|---|---|---|
0x01 | 0x999 | 0x02 | 00 32 17 | 01 02 03 E7 00 01 09 B9 | 读取输入寄存器第一个位值 |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 02 03 E7 00 02 49 B8 | 读取输入寄存器前二个位值 |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 02 03 E7 00 04 C9 BA | 读取输入寄存器前四个位值 |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 02 03 E7 00 08 C9 BF | 读取输入寄存器前八个位值 |
保持寄存器-读命令(0x03)
从机地址 | 寄存器地址 | 寄存器数量 | 网络指令 | modbus指令 | 说明 |
---|---|---|---|---|---|
0x01 | 0x999 | 0x02 | 00 32 17 | 01 03 03 E7 00 02 74 78 | 读取输入寄存器第一个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 03 03 E7 00 04 F4 7A | 读取输入寄存器前二个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 03 03 E7 00 08 F4 7F | 读取输入寄存器前四个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 03 03 E7 00 10 F4 75 | 读取输入寄存器前八个32位数值(浮点数) |
输入寄存器-读命令(0x04)
从机地址 | 寄存器地址 | 寄存器数量 | 网络指令 | modbus指令 | 说明 |
---|---|---|---|---|---|
0x01 | 0x999 | 0x02 | 00 32 17 | 01 04 03 E7 00 02 C1 B8 | 读取输入寄存器第一个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 04 03 E7 00 04 41 BA | 读取输入寄存器前二个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 04 03 E7 00 08 41 BF | 读取输入寄存器前四个32位数值(浮点数) |
0x01 | 0x999 | 0x02 | 00 32 17 | 01 04 03 E7 00 10 41 B5 | 读取输入寄存器前八个32位数值(浮点数) |