ModBus TCP 概述
ModBus TCP 是 ModBus 协议基于 TCP/IP 网络的实现,用于工业自动化设备之间的通信。它在传统 ModBus RTU(串行通信)的基础上,通过 TCP/IP 协议栈实现数据传输,具有更高的兼容性和扩展性。
协议特点
- 基于标准 TCP/IP:使用端口 502(默认),支持以太网通信。
- 简单高效:沿用 ModBus 的请求-响应模型,数据帧结构清晰。
- 跨平台兼容:支持多种设备(PLC、传感器、HMI 等)互联。
- 无加密:协议本身未加密,需依赖网络安全措施(如 VPN、防火墙)。
数据帧结构
ModBus TCP 数据帧由以下部分组成:
- MBAP 头(ModBus Application Protocol Header):7 字节,包含事务标识符、协议标识符、长度和单元标识符。
- PDU(Protocol Data Unit):功能码 + 数据,与 ModBus RTU 相同。
示例帧(十六进制):
00 01 00 00 00 06 01 03 00 6B 00 03
- 00 01:事务标识符(由客户端生成,响应时原样返回)。
- 00 00:协议标识符(0 表示 ModBus)。
- 00 06:后续字节长度(从单元标识符开始计算)。
- 01:单元标识符(设备地址)。
- 03:功能码(读取保持寄存器)。
- 00 6B 00 03:起始地址 + 寄存器数量。
功能码(常用)
- 01 (0x01):读取线圈状态。
- 02 (0x02):读取离散输入。
- 03 (0x03):读取保持寄存器。
- 04 (0x04):读取输入寄存器。
- 05 (0x05):写单个线圈。
- 06 (0x06):写单个寄存器。
- 16 (0x10):写多个寄存器。
实现示例(Python)
使用 pymodbus 库实现客户端请求:
from pymodbus.client import ModbusTcpClient
# 连接 ModBus TCP 服务器
client = ModbusTcpClient('192.168.1.1', port=502)
client.connect()
# 读取保持寄存器(地址 0,数量 10)
result = client.read_holding_registers(address=0, count=10, slave=1)
if not result.isError():
print("Registers:", result.registers)
else:
print("Error:", result)
client.close()
常见问题与解决
- 连接超时:检查网络连通性、防火墙设置及目标设备是否在线。
- 无效响应:确认功能码、地址和长度是否符合设备文档要求。
- 数据错误:检查字节序(大端/小端)是否与设备匹配。
应用场景
- 工业控制系统(SCADA、PLC 通信)。
- 能源监控(电表、传感器数据采集)。
- 楼宇自动化(HVAC、照明控制)。
ModBus TCP 因其简单性和广泛支持,成为工业通信的重要标准,但需注意其缺乏安全机制,需结合网络层防护措施使用。
Modbus TCP 常用场景
Modbus TCP 是一种基于以太网的工业通信协议,广泛应用于工业自动化领域。以下是其典型的应用场景:
工业控制系统(ICS)
Modbus TCP 常用于连接 PLC、DCS 和 SCADA 系统,实现设备间的数据交换。例如,工厂自动化中的生产线控制、数据采集和监控。
楼宇自动化
在智能楼宇中,Modbus TCP 用于集成 HVAC(暖通空调)、照明、安防等子系统,实现集中管理和控制。
能源管理
电力监控系统(如智能电网)使用 Modbus TCP 采集电表、逆变器、电池储能设备的数据,用于能耗分析和优化。
远程监控与维护
通过 Modbus TCP,工程师可以远程访问设备状态和参数,进行故障诊断或配置调整,减少现场维护成本。
物联网(IoT)集成
Modbus TCP 作为传统工业设备与 IoT 平台的桥梁,将传感器和执行器的数据上传至云端,支持大数据分析和预测性维护。
Modbus TCP 的优势
- 兼容性:与 Modbus RTU 协议兼容,便于旧系统升级。
- 开放性:协议标准公开,无需额外授权费用。
- 简单性:基于 TCP/IP 实现,易于开发和部署。
典型设备支持
- PLC:如西门子、施耐德、罗克韦尔等品牌。
- HMI:人机界面设备通过 Modbus TCP 与控制器通信。
- 智能仪表:电表、流量计、温度传感器等。
Modbus TCP 範例 (C語言)
以下是一個簡單的 Modbus TCP 客戶端程式範例,使用 C 語言實現。該程式會向 Modbus TCP 伺服器發送讀取保持寄存器(Function Code 0x03)的請求,並解析伺服器的回應。
程式範例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MODBUS_PORT 502
#define MODBUS_HEADER_SIZE 7
#define MODBUS_READ_HOLDING_REGISTERS 0x03
// Modbus TCP 請求封包結構
typedef struct {
uint16_t transaction_id;
uint16_t protocol_id;
uint16_t length;
uint8_t unit_id;
uint8_t function_code;
uint16_t starting_address;
uint16_t quantity;
} modbus_tcp_request;
// Modbus TCP 回應封包結構
typedef struct {
uint16_t transaction_id;
uint16_t protocol_id;
uint16_t length;
uint8_t unit_id;
uint8_t function_code;
uint8_t byte_count;
uint16_t *register_values;
} modbus_tcp_response;
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("Usage: %s <server_ip> <starting_address> <quantity>\n", argv[0]);
return 1;
}
char *server_ip = argv[1];
uint16_t starting_address = atoi(argv[2]);
uint16_t quantity = atoi(argv[3]);
// 建立 socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("Socket creation failed");
return 1;
}
// 設定伺服器地址
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(MODBUS_PORT);
if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) {
perror("Invalid address");
close(sock);
return 1;
}
// 連線到伺服器
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
close(sock);
return 1;
}
// 準備 Modbus TCP 請求封包
modbus_tcp_request request;
request.transaction_id = htons(1); // 交易 ID,可隨機生成
request.protocol_id = htons(0); // Modbus 協議 ID
request.length = htons(6); // 後續字節數
request.unit_id = 1; // 設備 ID
request.function_code = MODBUS_READ_HOLDING_REGISTERS;
request.starting_address = htons(starting_address);
request.quantity = htons(quantity);
// 發送請求
if (send(sock, &request, sizeof(request), 0) < 0) {
perror("Send failed");
close(sock);
return 1;
}
// 接收回應
uint8_t response_buffer[1024];
int bytes_received = recv(sock, response_buffer, sizeof(response_buffer), 0);
if (bytes_received < 0) {
perror("Receive failed");
close(sock);
return 1;
}
// 解析回應
modbus_tcp_response response;
memcpy(&response.transaction_id, response_buffer, 2);
memcpy(&response.protocol_id, response_buffer + 2, 2);
memcpy(&response.length, response_buffer + 4, 2);
response.unit_id = response_buffer[6];
response.function_code = response_buffer[7];
response.byte_count = response_buffer[8];
response.register_values = (uint16_t *)malloc(response.byte_count);
for (int i = 0; i < response.byte_count / 2; i++) {
uint16_t value;
memcpy(&value, response_buffer + 9 + i * 2, 2);
response.register_values[i] = ntohs(value);
printf("Register %d: %d\n", starting_address + i, response.register_values[i]);
}
free(response.register_values);
close(sock);
return 0;
}
程式說明
-
建立 Socket
使用socket()函數建立一個 TCP socket。 -
設定伺服器地址
設定 Modbus TCP 伺服器的 IP 地址和端口(默認為 502)。 -
連線到伺服器
使用connect()函數連線到 Modbus TCP 伺服器。 -
準備 Modbus TCP 請求封包
填充 Modbus TCP 請求封包的結構,包括交易 ID、協議 ID、功能碼(0x03 表示讀取保持寄存器)、起始地址和寄存器數量。 -
發送請求
使用send()函數將請求封包發送到伺服器。 -
接收回應
使用recv()函數接收伺服器的回應。 -
解析回應
解析回應封包,提取寄存器值並打印。
編譯與執行
-
編譯程式
使用以下命令編譯程式:gcc modbus_tcp_client.c -o modbus_tcp_client -
執行程式
執行編譯後的程式,並提供伺服器 IP、起始地址和寄存器數量作為參數:./modbus_tcp_client <server_ip> <starting_address> <quantity>
注意事項
-
錯誤處理
程式中的錯誤處理較為簡單,實際應用中應根據需求進一步完善。 -
字節順序
Modbus TCP 使用大端字節序(Big-Endian),因此在發送和接收數據時需使用htons()和ntohs()函數進行轉換。 -
寄存器數量
請求的寄存器數量不能超過 Modbus 協議的限制(通常為 125 個寄存器)。
ModBus TCP vs. T1S: 关键区别与应用场景
协议基础与通信方式
ModBus TCP 是基于 TCP/IP 的工业通信协议,运行于以太网(如 IEEE 802.3),默认端口为 502。数据以明文传输,采用请求-响应模型,支持多设备通信,适用于局域网或互联网环境。
T1S(通常指 Telemetry 1.0 Standard)是一种轻量级遥测协议,专为低带宽、高延迟网络设计(如蜂窝网络或卫星通信)。数据通常以二进制格式压缩传输,支持双向通信,但需依赖特定硬件(如调制解调器)。
性能与延迟
ModBus TCP 的延迟取决于网络负载,典型响应时间在毫秒级,适合实时控制场景(如 PLC 控制)。
T1S 的延迟较高(秒级),但优化了带宽利用率,适合远程监控(如油气田、风电场的传感器数据回传)。
数据格式与扩展性
ModBus TCP 使用固定格式帧(如功能码+寄存器地址),扩展需自定义功能码或映射到其他协议(如 OPC UA)。
T1S 支持动态数据包结构,可灵活添加字段,适合异构设备集成(如混合传感器网络)。
安全性与适用领域
ModBus TCP 无原生加密,需依赖外部措施(如 VPN 或 TLS 隧道),常见于工厂自动化、楼宇控制。
T1S 通常内置加密(如 AES-128),适用于对安全性要求较高的野外或军事应用。
典型应用示例
- ModBus TCP: 生产线机器人协同、智能电表数据采集。
- T1S: 偏远地区气象站数据传输、管道泄漏监测系统。
选择依据:需权衡实时性、带宽、部署成本及设备兼容性。
147

被折叠的 条评论
为什么被折叠?



