Modbus协议
PicoXTools 是懂 Modbus的

Modbus是一种用于工业自动化领域的通信协议,它被广泛应用于监控、控制和数据采集等方面。它的历史可以追溯到上个世纪70年代,当时由Modicon公司1979年开发,最初是为了满足PLC(可编程逻辑控制器)与其他设备之间的通信需求而设计的。
Modbus协议简单易懂,易于实现,是一种开放的通信标准,因此在工业自动化领域得到了广泛的应用和认可。它采用了客户/服务器模型,通常基于串行通信(如RS-232、RS-485)或TCP/IP网络进行数据传输。
Modbus协议包含了几种不同的传输方式,包括Modbus RTU(基于串行通信的二进制传输方式)、Modbus ASCII(基于ASCII码的文本传输方式)和Modbus TCP(基于TCP/IP网络的传输方式),每种传输方式都有其适用的场景和优势,其中Modbus TCP是在施耐德收购Modicon后1997年发布的。
在实际应用中,Modbus协议被广泛应用于各种工业设备之间的通信,例如传感器、执行器、PLC、人机界面(HMI)等。通过Modbus协议,这些设备可以方便地进行数据交换和控制命令传输,从而实现工业生产过程的自动化和智能化。
值得一提的是,Modbus协议不仅在工业自动化领域有着重要的地位,在能源管理、楼宇自动化、环境监测等领域也有着广泛的应用。它的简单性和可靠性使得它成为了许多系统集成和解决方案中不可或缺的一部分
以下是Modbus协议的一些关键特点和组成部分:
通信方式:Modbus协议支持主从架构的通信模式。通常情况下,一个主站(主控制器)通过Modbus协议与多个从站(被控制器)通信。
传输方式:Modbus协议可以通过串行通信(如RS-232、RS-485)或基于TCP/IP的以太网通信进行数据传输。
数据格式:Modbus协议使用简单的帧结构,包括地址字段、功能码、数据字段和校验字段。通常情况下,一个Modbus帧的结构如下:
- 地址字段:用于标识通信的设备地址。
- 功能码:用于指示通信操作的类型,如读取寄存器、写入寄存器等。
- 数据字段:用于传输实际的数据。
- 校验字段:用于检测数据传输的准确性。
功能码:Modbus协议定义了一系列功能码,用于执行不同的操作,例如读取/写入寄存器、读取输入状态等。
寄存器:Modbus协议中的数据通常存储在寄存器中,这些寄存器可以是输入寄存器、保持寄存器、输入状态或线圈。不同类型的寄存器用于存储不同类型的数据。
数据类型:Modbus支持不同的数据类型,包括整数、浮点数、位(布尔值)等。
错误处理:Modbus协议包含了一些错误处理机制,如校验和、超时处理等,以确保数据传输的可靠性和完整性。
总的来说,Modbus协议是一种简单、易于实现和使用的工业通信协议,因此在工业自动化领域得到了广泛的应用。它的开放性和通用性使得不同厂商的设备可以方便地实现互联互通。
功能码
Modbus协议定义了一系列功能码,用于执行不同的操作。以下是常用的功能码及其对应的操作:
| 代码 | 中文名称 | 寄存器PLC地址 | 位操作/字操作 | 操作数量 |
|---|---|---|---|---|
| 01 | 读线圈状态 | 00001-09999 | 位操作 | 单个或多个 |
| 02 | 读离散输入状态 | 10001-19999 | 位操作 | 单个或多个 |
| 03 | 读保持寄存器 | 40001-49999 | 字操作 | 单个或多个 |
| 04 | 读输入寄存器 | 30001-39999 | 字操作 | 单个或多个 |
| 05 | 写单个线圈 | 00001-09999 | 位操作 | 单个 |
| 06 | 写单个保持寄存器 | 40001-49999 | 字操作 | 单个 |
| 15 | 写多个线圈 | 00001-09999 | 位操作 | 多个 |
| 16 | 写多个保持寄存器 | 40001-49999 | 字操作 | 多个 |
MODBUS寄存器地址分配
| 寄存器PLC地址 | 寄存器协议地址 | 适用功能 | 寄存器种类 | 读写状态 |
|---|---|---|---|---|
| 00001-09999 | 0000H-FFFFH | 01H 05H 0FH | 线圈状态 | 可读可写 |
| 10001-19999 | 0000H-FFFFH | 02H | 离散输入状态 | 可读 |
| 30001-39999 | 0000H-FFFFH | 04H | 输入寄存器 | 可读 |
| 40001-49999 | 0000H-FFFFH | 03H 06H 0FH | 保持寄存器 | 可读可写 |
与 PLC 比较
| 寄存器种类 | 说明 | PLC类比 | 举例说明 |
|---|---|---|---|
| 线圈 | 状态 | DO | 电磁阀输出,MOSFET输出,LED显示等。 |
| 离散 | 输入状态 | DI | 拨码开关,接近开关等。 |
| 保持 | 寄存器 | AO | 模拟量输出设定值,PID运行参数,变量阀输出大小,传感器报警上限下限。 |
| 输入 | 寄存器 | AI | 模拟量输入 |
这将生成一个完整的表格,包含所有的信息。
读取操作:
- 读取线圈状态:功能码 01(0x01)
- 读取离散输入状态:功能码 02(0x02)
- 读取保持寄存器:功能码 03(0x03)
- 读取输入寄存器:功能码 04(0x04)
写入操作:
- 写单个线圈:功能码 05(0x05)
- 写单个寄存器:功能码 06(0x06)
- 写多个线圈:功能码 15(0x0F)
- 写多个寄存器:功能码 16(0x10)
诊断操作:
- 读取通信事件计数:功能码 11(0x0B)
- 读取通信事件日志:功能码 12(0x0C)
其他操作:
- 屏蔽写寄存器:功能码 22(0x16)
- 读取设备标识:功能码 43(0x2B)
这些功能码覆盖了常见的读写操作,可以满足大多数工业自动化应用的通信需求。
写多个线圈 功能码 15(0x0F)
写多个线圈的数据格式如下:
功能码:写多个线圈的功能码是 15(0x0F)。
起始地址:指定要写入的线圈的起始地址。通常是一个16位的整数,表示线圈的地址。例如,如果要写入的线圈起始地址是 0001,那么在Modbus帧中,这个字段的值就是 0001。
线圈数量:指定要写入的线圈的数量。通常是一个16位的整数,表示要写入的线圈的个数。
字节数:指定要写入的线圈状态所需的字节数。这个字节数通常是线圈数量的整数部分除以8,如果有余数,则需要进一取整。例如,如果要写入的线圈数量是9个,那么字节数就是 2,因为9÷8=1余1,需要2个字节来存储线圈的状态。
线圈状态:指定要写入的线圈的状态。这些状态通常是按位组织的,每个位代表一个线圈的状态(开启或关闭)。在Modbus帧中,这些状态以位的形式进行组织,将每个线圈的状态依次排列。例如,如果要写入的线圈数量是9个,那么需要2个字节(16位)来表示线圈的状态,其中第一个字节的高位表示第1个线圈的状态,第一个字节的低位表示第8个线圈的状态,第二个字节的高位表示第9个线圈的状态。
校验码:用于检验数据传输的准确性。
因此,写多个线圈的Modbus帧的格式如下:
| 起始地址高字节 | 起始地址低字节 | 线圈数量高字节 | 线圈数量低字节 | 字节数 | 线圈状态(字节1) | 线圈状态(字节2) | 校验码 |
|---|---|---|---|---|---|---|---|
| Address Hi | Address Lo | Quantity Hi | Quantity Lo | Byte | Coil Status | Coil Status | CRC |
其中,CRC 是校验码,
写多个寄存器:功能码 16
写多个寄存器的数据格式如下:
功能码:写多个寄存器的功能码是 16(0x10)。
起始地址:指定要写入的寄存器的起始地址。通常是一个16位的整数,表示寄存器的地址。例如,如果要写入的寄存器起始地址是 0001,那么在Modbus帧中,这个字段的值就是 0001。
寄存器数量:指定要写入的寄存器的数量。通常是一个16位的整数,表示要写入的寄存器的个数。
字节数:指定要写入的寄存器值所需的字节数。通常是寄存器数量的整数部分乘以2,因为每个寄存器通常是一个16位的值,即2个字节。
寄存器值:指定要写入的寄存器的值。这些值按照寄存器的地址顺序排列,并且每个寄存器的值由2个字节组成。在Modbus帧中,这些值以字节的形式进行组织,将每个寄存器的值按照地址顺序依次排列。例如,如果要写入的寄存器数量是3个,那么需要6个字节(2个字节 * 3个寄存器)来表示这些寄存器的值。
校验码:用于检验数据传输的准确性。
因此,写多个寄存器的Modbus帧的格式如下:
| 起始地址高字节 | 起始地址低字节 | 寄存器数量高字节 | 寄存器数量低字节 | 字节数 | 寄存器值1(高字节) | 寄存器值1(低字节) | 寄存器值2(高字节) | 寄存器值2(低字节) | ... | 校验码 |
|---|---|---|---|---|---|---|---|---|---|---|
| Address Hi | Address Lo | Quantity Hi | Quantity Lo | Byte | Register1 Hi | Register1 Lo | Register2 Hi | Register2 Lo | ... | CRC |
其中,CRC 是校验码,可以是CRC-16或CRC-32等校验算法的结果。
写单个寄存器06
写单个寄存器的数据格式如下:
功能码:写单个寄存器的功能码是 06(0x06)。
寄存器地址:指定要写入的寄存器的地址。通常是一个16位的整数,表示寄存器的地址。例如,如果要写入的寄存器地址是 0001,那么在 Modbus 帧中,这个字段的值就是 0001。
寄存器值:指定要写入的寄存器的值。通常是一个16位的整数,表示要写入的寄存器的新值。
校验码:用于检验数据传输的准确性。
因此,写单个寄存器的 Modbus 帧的格式如下:
| 寄存器地址高字节 | 寄存器地址低字节 | 寄存器值高字节 | 寄存器值低字节 | 校验码 |
|---|---|---|---|---|
| Address Hi | Address Lo | Value Hi | Value Lo | CRC |
其中,CRC 是校验码,可以是 CRC-16 或 CRC-32 等校验算法的结果。
写单个线圈 功能码05(0x05
写单个线圈的数据格式如下:
功能码:写单个线圈的功能码是 05(0x05)。
线圈地址:指定要写入的线圈的地址。通常是一个16位的整数,表示线圈的地址。例如,如果要写入的线圈地址是 0001,那么在 Modbus 帧中,这个字段的值就是 0001。
线圈状态:指定要写入的线圈的状态。通常是一个16位的整数,其中只有低位有效,表示要写入的线圈的新状态(开启或关闭)。
- 如果要将线圈置为“开启”,则线圈状态值通常是 0xFF00。
- 如果要将线圈置为“关闭”,则线圈状态值通常是 0x0000。
校验码:用于检验数据传输的准确性。
因此,写单个线圈的 Modbus 帧的格式如下:
| 线圈地址高字节 | 线圈地址低字节 | 线圈状态高字节 | 线圈状态低字节 | 校验码 |
|---|---|---|---|---|
| Coil Hi | Coil Lo | State Hi | State Lo | CRC |
其中,CRC 是校验码,可以是 CRC-16 或 CRC-32 等校验算法的结果。
错误码
在Modbus协议中,异常响应码(异常功能码)用于标识通信中的错误情况。以下是一些常见的Modbus异常响应码及其含义:
错误码 1: Illegal Function (功能码错误):指示请求中包含了Modbus规范中未定义或不支持的功能码。
错误码 2: Illegal Data Address (数据地址错误):指示请求中包含了无效的数据地址,超出了设备支持的范围。
错误码 3: Illegal Data Value (数据值错误):指示请求中包含了无效的数据值,超出了设备所能处理的范围。
错误码 4: Server Device Failure (设备故障):指示设备在处理请求时发生了故障,如内部错误、通信错误等。
错误码 5: Acknowledge (确认帧):指示设备已收到请求,但需要更长的时间来完成操作,通常用于长时间操作的通知。
错误码 6: Gateway Target Device Failed to Respond (网关目标设备未响应):指示网关设备未能获得所需的响应,可能是由于通信中断或目标设备故障。
这些异常响应码用于在Modbus通信过程中标识错误情况,当接收到异常响应码时,客户端应根据具体的响应码进行相应的处理,例如重新发送请求、调整请求参数或向系统管理员报告问题等。
异常响应包格式
在Modbus协议中,异常响应码(异常功能码)用于标识通信中的错误情况。以下是一些常见的Modbus异常响应码及其含义:
错误码 1: Illegal Function (功能码错误):指示请求中包含了Modbus规范中未定义或不支持的功能码。
错误码 2: Illegal Data Address (数据地址错误):指示请求中包含了无效的数据地址,超出了设备支持的范围。
错误码 3: Illegal Data Value (数据值错误):指示请求中包含了无效的数据值,超出了设备所能处理的范围。
错误码 4: Server Device Failure (设备故障):指示设备在处理请求时发生了故障,如内部错误、通信错误等。
错误码 5: Acknowledge (确认帧):指示设备已收到请求,但需要更长的时间来完成操作,通常用于长时间操作的通知。
错误码 6: Gateway Target Device Failed to Respond (网关目标设备未响应):指示网关设备未能获得所需的响应,可能是由于通信中断或目标设备故障。
这些异常响应码用于在Modbus通信过程中标识错误情况,当接收到异常响应码时,客户端应根据具体的响应码进行相应的处理,例如重新发送请求、调整请求参数。