Modbus TCP 协议详解及C语言示例

微软技术分享
优质创作者: 编程框架技术领域
领域专家: 操作系统技术领域
2024-02-06 14:02:29

Modbus TCP 是一种应用于以太网的通讯协议,基于Modbus RTU协议。Modbus协议是一种应用于串行数据通信的协议,广泛应用于工业控制系统。Modbus TCP 将传统的 Modbus RTU 消息封装在 TCP/IP 报文中,使其能够在现代的以太网环境中进行通信。本文将详细介绍 Modbus TCP 协议的报文格式、各部分具体含义,并给出 C 语言的示例。

Modbus TCP 报文格式

Modbus TCP 报文主要包含以下部分:

  • 事务标识符(Transaction Identifier):2 字节
  • 协议标识符(Protocol Identifier):2 字节
  • 长度(Length):2 字节
  • 单元标识符(Unit Identifier):1 字节
  • 功能码(Function Code):1 字节
  • 数据(Data):n 字节

1. 事务标识符

事务标识符用于标识请求/响应报文对。客户端发起请求时生成一个唯一的事务标识符,服务器响应时使用相同的事务标识符。这使得客户端能够区分并正确处理并发请求。

2. 协议标识符

协议标识符用于区分不同的上层协议。对于 Modbus TCP 来说,协议标识符固定为 0x0000。

3. 长度

长度字段表示从单元标识符开始的报文总字节数。包括单元标识符、功能码和数据字段。

4. 单元标识符

单元标识符用于标识设备中的特定单元。在 Modbus TCP 中,单元标识符对应于 Modbus RTU 中的设备地址。

5. 功能码

功能码用于指示报文的操作类型。如读取保持寄存器、写入单个寄存器等。常见的功能码有:

  • 0x03:读取保持寄存器
  • 0x06:写入单个寄存器
  • 0x10:写入多个寄存器

6. 数据

数据字段的内容取决于功能码。例如,对于读取保持寄存器操作,数据字段包含起始寄存器地址和要读取的寄存器数量。

C 语言示例

以下是一个使用 C 语言实现的 Modbus TCP 客户端示例,用于读取保持寄存器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUFFER_SIZE 1024

int main() {
    int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (client_socket == -1) {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.100");
    server_addr.sin_port = htons(502);

    if (connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect");
        exit(1);
    }

    // 构建 Modbus TCP 读取保持寄存器请求报文
    unsigned char request[12] = {
        0x00, 0x01, // 事务标识符
        0x00, 0x00, // 协议标识符
        0x00, 0x06, // 长度
        0x01,       // 单元标识符
        0x03,       // 功能码:读取保持寄存器
        0x00, 0x00, // 起始寄存器地址
        0x00, 0x01  // 要读取的寄存器数量
    };

    // 发送请求报文
    if (write(client_socket, request, sizeof(request)) == -1) {
        perror("write");
        exit(1);
    }

    // 接收响应报文
    unsigned char response[BUFFER_SIZE];
    int response_length = read(client_socket, response, BUFFER_SIZE);
    if (response_length == -1) {
        perror("read");
        exit(1);
    }

    // 解析响应报文
    if (response[7] != 0x03) {
        printf("Error: Invalid function code in response.\n");
        exit(1);
    }
    if (response[8] != 0x02) {
        printf("Error: Invalid data length in response.\n");
        exit(1);
    }

    int register_value = (response[9] << 8) | response[10];
    printf("Register value: %d\n", register_value);

    close(client_socket);
    return 0;
}

以上示例创建一个 TCP 客户端,连接到 IP 地址为 “192.168.1.100”、端口号为 502 的 Modbus TCP 服务器。然后构造一个读取保持寄存器的请求报文,并发送到服务器。接收并解析服务器的响应报文,最后输出寄存器值。

请注意,此示例仅用于演示目的,实际应用可能需要考虑更多的错误处理和功能。在实际项目中,可以使用现有的 Modbus TCP 库,例如 libmodbus,以便更方便且安全地处理 Modbus TCP 通信


文章来源: https://blog.csdn.net/qq_33471732/article/details/131316853
版权声明: 本文为博主原创文章,遵循CC 4.0 BY-SA 知识共享协议,转载请附上原文出处链接和本声明。


...全文
535 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

6,744

社区成员

发帖
与我相关
我的任务
社区描述
微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。
windowsmicrosoft 企业社区
社区管理员
  • 微软技术分享
  • 郑子铭
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。

予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。

试试用AI创作助手写篇文章吧