Modbus
Modbus是一种用于工业自动化领域的通信协议,广泛应用于监控、控制和数据采集等领域。它是一种简单、开放、易于实现和部署的通信协议,由Modicon(现在的施耐德电气)于1979年创建,用于在PLC(可编程逻辑控制器)和其他电子设备之间进行通信。
Modbus协议通常在串口(例如RS-232、RS-485)或以太网等物理介质上进行通信。它采用了主从结构,其中一个设备(主站)向一个或多个设备(从站)发送请求,并从从站接收响应。
Modbus协议包括多个变体,其中最常见的是以下两种:
- Modbus RTU:RTU(Remote Terminal Unit)是一种二进制格式的Modbus协议,数据以二进制形式传输,通常在串口通信中使用,具有较高的抗干扰能力和较短的响应时间。
- Modbus TCP:TCP(Transmission Control Protocol)是一种基于TCP/IP网络的Modbus协议,数据以ASCII或二进制形式封装在TCP/IP数据包中传输,通常在以太网通信中使用,具有更高的速度和更广泛的应用范围。
Modbus RTU和Modbus TCP 数据格式
-
Modbus RTU 数据格式:
Modbus RTU使用二进制格式传输数据,通常在串口通信中使用。其数据帧格式如下:
起始位:一个起始位,通常为逻辑低电平。
地址字段:8位,用于指定从站地址。
功能码:8位,用于指定请求的功能。
数据字段:0至252字节的数据,包括数据和校验字段。
CRC校验:16位循环冗余校验,用于校验数据的完整性。
停止位:一个或两个停止位,通常为逻辑高电平。
Modbus RTU的数据传输速率通常在2400bps至115200bps之间,具体取决于通信的要求和设备的支持能力。 -
Modbus TCP 数据格式:
Modbus TCP是基于TCP/IP网络的Modbus协议,数据以ASCII或二进制形式封装在TCP/IP数据包中传输。其数据帧格式如下:
TCP报文头部:包含源IP地址、目标IP地址、源端口号和目标端口号等信息。
Modbus应用数据单元(ADU):包含Modbus功能码、数据字段和可选的错误检查字段。
协议标识符(Protocol Identifier):16位,指示Modbus协议版本。
数据长度字段:16位,指示ADU的长度。
单元标识符(Unit Identifier):8位,用于指定从站地址。
功能码:8位,用于指定请求的功能。
数据字段:根据功能码不同,可以是读请求、写请求等操作的参数。
CRC校验(对于Modbus RTU over TCP):16位循环冗余校验,用于校验ADU的完整性。
Modbus TCP使用标准的TCP/IP网络进行通信,因此可以利用现有的网络设备和基础设施,通常使用标准的以太网物理层和TCP/IP协议栈。
以下是一个简单的Modbus RTU和Modbus TCP的案例:
Modbus RTU 案例:
假设你有一个串口设备(例如串口转以太网适配器)连接到你的计算机,并且该设备支持Modbus RTU通信协议。你想通过串口与该设备通信,并读取其寄存器中的数据。
#include <iostream>
#include <modbus/modbus-rtu.h>
int main() {
modbus_t *ctx = modbus_new_rtu("/dev/ttyS0", 9600, 'N', 8, 1);
if (ctx == nullptr) {
std::cerr << "Unable to create Modbus RTU context" << std::endl;
return -1;
}
if (modbus_connect(ctx) == -1) {
std::cerr << "Connection failed: " << modbus_strerror(errno) << std::endl;
modbus_free(ctx);
return -1;
}
uint16_t data[32];
int rc = modbus_read_registers(ctx, 0, 10, data);
if (rc == -1) {
std::cerr << "Read failed: " << modbus_strerror(errno) << std::endl;
} else {
for (int i = 0; i < rc; ++i) {
std::cout << "Register " << i << ": " << data[i] << std::endl;
}
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
Modbus TCP 案例:
假设你有一个Modbus TCP从站设备连接到你的局域网,并且你知道它的IP地址和端口号。你想通过网络与该设备通信,并读取其寄存器中的数据。
#include <iostream>
#include <modbus/modbus-tcp.h>
int main() {
modbus_t *ctx = modbus_new_tcp("192.168.1.100", 502);
if (ctx == nullptr) {
std::cerr << "Unable to create Modbus TCP context" << std::endl;
return -1;
}
if (modbus_connect(ctx) == -1) {
std::cerr << "Connection failed: " << modbus_strerror(errno) << std::endl;
modbus_free(ctx);
return -1;
}
uint16_t data[32];
int rc = modbus_read_registers(ctx, 0, 10, data);
if (rc == -1) {
std::cerr << "Read failed: " << modbus_strerror(errno) << std::endl;
} else {
for (int i = 0; i < rc; ++i) {
std::cout << "Register " << i << ": " << data[i] << std::endl;
}
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
以上示例仅供参考,实际使用时需要根据你的设备和环境进行调整和修改。