MODBUS通讯协议
Modbus是一种广泛应用于工业自动化和控制系统的通信协议。 它由 Modicon(现为施耐德电气的一部分)于 1979 年开发。 Modbus 是一种开放标准,用于连接各种工业电子设备,例如可编程逻辑控制器 (PLC)、传感器和其他现场设备。
协议描述
Modbus协议支持多种物理层传输介质,包括串行通信(如RS-232、RS-485)和以太网通信(Modbus TCP/IP)。Modbus通信通常涉及一个主站(Master)和一个或多个从站(Slave)之间的通信,主站负责发起请求,而从站则负责响应请求。此外Modbus通信涉及到各种寄存器,包括输入寄存器、保持寄存器、输入状态和线圈。这些寄存器用于存储设备状态、配置信息和其他数据。
Modbus传输方式主要有:Modbus RTU(Remote Terminal Unit)、Modbus ASCII和Modbus TCP/IP。Modbus消息结构由功能码、寄存器地址、立即数或寄存器值等组成,其中功能码用于指定从站应执行的操作类型,寄存器地址、立即数或寄存器值为具体执行的内容。在Modbus网络结构种,每个设备都有唯一的地址,主站使用这个地址来指定它想要与哪个从站通信。
Modbus以其简单性而闻名,易于实施和排除故障。这种简单性促使其在工业应用中得到广泛采用。Modbus协议本身并没有提供加密或身份验证,因此在实施时需要注意安全性,可能需要使用额外的安全措施。这些特征使得Modbus协议在工业领域广泛应用,特别是在PLC(可编程逻辑控制器)和其他自动化设备之间的通信中。 Modbus协议的开放性和简单性为其在不同厂商和设备之间的互操作性提供了支持。
数据传输
Modbus传输方式主要有以下三种:
- Modbus RTU: 使用串行通信(通常是RS-232或RS-485),是一种二进制协议。
- Modbus ASCII: 一种基于ASCII编码的串行通信协议。
- Modbus TCP/IP: 使用以太网进行通信,支持更灵活的主从或客户端-服务器通信模型。
Modbus RTU
Modbus RTU(Remote Terminal Unit)是Modbus协议的一种变体,用于串行通信。它是在Modbus通信协议中常见的一种格式,特别适用于工业自动化和控制系统中的设备之间的通信。Modbus RTU通信采用主从结构。主站是控制设备的设备(通常为上位机或可编程逻辑控制器),而从站是执行实际操作的设备。主站发起请求,而从站响应请求。
Modbus RTU使用二进制格式传输数据。每个数据帧包含一个地址字段(表示从站地址)、功能码字段、数据字段和CRC(循环冗余校验,用于检测数据传输中的错误)字段。串行通信使用波特率来指定数据传输的速率。常见的波特率包括9600、19200、38400等。Modbus RTU相对简单,易于实施和维护。
Modbus ASCII
Modbus ASCII是Modbus通信协议的另一种变体,与Modbus RTU相比,它采用了一种不同的数据帧格式。与Modbus RTU使用二进制格式不同,Modbus ASCII使用可读的ASCII字符作为数据传输的基本单位。
Modbus ASCII使用可打印的ASCII字符表示二进制数据。每个字节被转换为两个ASCII字符(通常是十六进制表示)。数据帧以起始标志冒号“:”开始,以回车换行符“\r\n”结束。与Modbus RTU一样,Modbus ASCII支持输入寄存器和保持寄存器,用于存储各种数据。
尽管相对于Modbus RTU而言,Modbus ASCII的实现可能稍显复杂,但仍然是一种相对简单的协议。 Modbus ASCII不像Modbus RTU那样广泛使用,通常在特殊应用或早期Modbus实现中才会见到。Modbus ASCII的主要特点是其可读性,但由于其字符表示形式,相较于Modbus RTU,它在速度和效率上可能会有所降低。因此,除非特殊要求需要ASCII格式,否则在工业环境中,通常更常使用Modbus RTU或Modbus TCP/IP。
Modbus TCP/IP
Modbus TCP/IP是Modbus通信协议的另一种变体,它是为基于以太网的通信而设计的。相对于Modbus RTU和Modbus ASCII,Modbus TCP/IP使用TCP/IP协议栈进行通信,因此具有更高的灵活性和广泛的应用性。
Modbus TCP/IP支持更灵活的通信模型,可以采用传统的主从结构或更复杂的客户端-服务器结构。客户端可以发出请求,而服务器则响应请求。Modbus TCP/IP使用TCP作为传输协议,而数据帧则嵌套在TCP数据包中。因此,与Modbus RTU和Modbus ASCII相比,Modbus TCP/IP的数据帧不再受到物理层细节的限制。
与Modbus RTU和Modbus ASCII一样,Modbus TCP/IP支持输入寄存器和保持寄存器。Modbus TCP/IP使用与Modbus RTU和Modbus ASCII相同的功能码来指定从站执行的操作类型。Modbus TCP/IP使用设备的IP地址和端口号进行寻址,使得设备在网络中更容易地被定位。Modbus TCP/IP通信通过以太网进行,支持高速、大容量的数据传输。Modbus TCP/IP相对简单,易于实施和配置。它也更适用于现代以太网基础设施。
Modbus TCP/IP本身并不提供加密或身份验证,因此在实施时需要采取额外的安全措施。Modbus TCP/IP在现代工业自动化系统中广泛应用,特别是在需要高速数据传输和更复杂通信模型的环境中。Modbus TCP/IP的灵活性和能够在以太网上进行通信的能力使其成为工业自动化和控制系统中的首选协议之一。
功能码
Modbus功能码用于指定Modbus通信中从站应该执行的操作类型。功能码的值决定了数据传输的方向以及所执行的具体操作。以下是一些常用的Modbus功能码:
读操作
功能 | 功能码 | 描述 |
---|---|---|
读线圈状态(Read Coils) | 01 | 用于读取从站的数字输出线圈(Coils)的状态 |
读输入状态(Read Discrete Inputs) | 02 | 用于读取从站的数字输入状态 |
读保持寄存器(Read Holding Registers) | 03 | 用于读取从站的模拟输出保持寄存器(Registers)的内容 |
读输入寄存器(Read Input Registers) | 04 | 用于读取从站的模拟输入寄存器的内容 |
写操作
功能 | 功能码 | 描述 |
---|---|---|
写单个线圈(Write Single Coil) | 05 | 用于设置从站的一个数字输出线圈的状态 |
写单个保持寄存器(Write Single Register) | 06 | 用于设置从站的一个模拟输出保持寄存器的值 |
写多个线圈(Write Multiple Coils) | 15 | 用于设置从站的多个数字输出线圈的状态 |
写多个保持寄存器(Write Multiple Registers) | 16 | 用于设置从站的多个模拟输出保持寄存器的值 |
诊断和配置
功能 | 功能码 | 描述 |
---|---|---|
诊断(Diagnostics) | 08 | 用于执行从站的诊断或配置 |
设备识别(Device Identification) | 43 | 用于获取从站的设备识别信息 |
以上是一些常见的Modbus功能码示例。实际上Modbus协议支持多个不同的功能码,每个功能码执行不同的操作。在使用Modbus通信时,主站(或客户端)将向从站(或服务器)发送包含适当功能码的请求消息,然后从站将相应的响应消息返回给主站。功能码的选择取决于所需的操作类型,例如读取数据、写入数据或执行特定的控制命令。
示例
读取从11开始的连续10个寄存器的内容(从机地址为1)
读取从11开始的连续10个保持寄存器的内容(从机地址为1)
读取保存寄存器对应功能码03,保持寄存器对应的地址为11,且读取长度为10,则对应的二进制通讯格式为:
0000 0001 0000 0011 0000 0000 0000 1011 0000 0000 0000 1010(01 03 00 0B 00 0A)
代码实现(TCP模式)
modbus_t *client;
client = modbus_new_tcp("192.168.1.5", 502); //实例化modbus_t对象
modbus_set_slave(client, 1); //设置站号
if (modbus_connect(client) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(client);
return -1;
}
uint16_t *content;
content = (uint16_t *)malloc(10 * sizeof(uint16_t));
memset(content, 0, 10 * sizeof(uint16_t));
modbus_read_registers(client, 11, 10, content); //读取保持寄存器
free(content);
modbus_close(client);
modbus_free(client);
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
server = modbus_tcp.TcpMaster(host:"192.168.1.5", port:502)
# 实例化TcpMaster对象 host: ip地址 port: 端口
result = server.execute(1, cst.READ_HOLDING_REGISTERS, 11, 10)
# 读保持寄存器 03H 1站号 地址11 长度10