鱼C论坛

 找回密码
 立即注册
查看: 174|回复: 9

实际应用modbus 通讯

[复制链接]
回帖奖励 30 鱼币 回复本帖可获得 5 鱼币奖励! 每人限 1 次
发表于 2026-1-21 08:28:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
现在想处理modbus tcp相关的事情,具体为TCP转RS485网关搭建这个平台,之前没了解过这里,想通过modbus tcp 客户端向服务器发送一组速度数据,现在在不确定是什么网关时候我怎么在看到网关后,将modbus tcp连接成功获取到服务器的报文?然后通过这个报文发送我想发送的数据?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2026-1-21 08:29:03 | 显示全部楼层
你好!作为FishC的计算机教育专家,我来为你解答Modbus TCP通讯的问题。

首先,让我们理清基本概念:
- Modbus TCP 是一种基于TCP/IP协议的Modbus变体,默认端口是502。
- TCP转RS485网关 是一种设备,它将Modbus TCP请求转换为RS485信号,从而连接Modbus RTU/ASCII设备。你需要知道网关的IP地址来连接。

现在,回答你的问题:如何连接网关并发送速度数据?

  • 确认网关信息:
       - 找到网关的IP地址(通常通过路由器DHCP或默认设置)。
       - 默认端口是502,如果不确定,检查网关手册。
  • 准备Modbus TCP客户端:
       - 你可以使用Python的pymodbus库,它简化了Modbus通讯。
       - 安装pymodbus:在命令行中运行 pip install pymodbus
  • 连接并发送数据:
       - Modbus TCP客户端连接网关(作为服务器),网关转发请求到RS485设备。
       - 发送速度数据通常使用“写保持寄存器”功能码(Modbus功能码6或16),因为速度值可能是16位或32位整数。
       - 接收到响应报文后,确认数据是否成功写入。


以下是一个Python代码示例,展示如何连接Modbus TCP服务器(即你的网关)并发送速度数据:


  1. from pymodbus.client import ModbusTcpClient

  2. # 设置网关的IP地址和端口
  3. gateway_ip = "192.168.1.100"  # 替换为你的网关IP
  4. port = 502

  5. # 创建Modbus TCP客户端
  6. client = ModbusTcpClient(gateway_ip, port)

  7. # 连接网关
  8. if client.connect():
  9.     print("连接成功!")
  10.    
  11.     # 假设速度数据存储在保持寄存器中,地址为0(根据设备手册调整)
  12.     # 速度值:例如1000 RPM,作为16位整数发送
  13.     speed_value = 1000
  14.     address = 0  # 寄存器起始地址
  15.     slave_id = 1  # 从站ID,通常为1,根据设备设置
  16.    
  17.     # 写单个寄存器(功能码6)
  18.     response = client.write_register(address, speed_value, slave=slave_id)
  19.    
  20.     if response.isError():
  21.         print("写入失败:", response)
  22.     else:
  23.         print("速度数据发送成功!")
  24.         # 获取响应报文:响应对象包含原始数据
  25.         print("响应报文:", response)
  26.    
  27.     # 关闭连接
  28.     client.close()
  29. else:
  30.     print("连接失败!")
复制代码


如何获取服务器的报文?
- 在上述代码中,response 对象包含服务器(网关)返回的报文。你可以打印它来查看原始数据。pymodbus会自动解析报文,但如果你需要原始字节,可以检查响应属性。

发送你想发送的数据:
- 确定速度数据在设备中的存储方式:通常是保持寄存器。参考设备手册,找到正确的寄存器地址和数据类型(例如,16位整数、32位浮点数等)。
- 如果需要发送多个寄存器,使用 write_registers 方法。

注意事项:
1. 网关设置:确保网关的IP地址与你的网络在同一子网。如果不确定,尝试使用默认IP(如192.168.1.100)或通过工具扫描。
2. 从站ID:RS485设备可能有不同的从站ID,在网关转发时需要指定。通常,网关透明传输,所以客户端直接指定从站ID。
3. 报文理解:Modbus TCP报文包括事务标识、协议标识、长度、单元标识(从站ID)和功能码+数据。但库会处理这些细节,你只需关注数据部分。

如果你没有具体网关型号,建议先测试连接:使用Modbus扫描工具或简单代码尝试连接,确认IP和端口。发送数据后,检查设备是否响应。

希望这能帮助你搭建平台!如有更多问题,欢迎继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2026-1-21 08:38:59 | 显示全部楼层
FishC 发表于 2026-1-21 08:29
你好!作为FishC的计算机教育专家,我来为你解答Modbus TCP通讯的问题。

首先,让我们理清基本概念:

如果是使用C语言呢,怎么进行处理因为我的系统是用C语言写的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-1-21 08:40:01 | 显示全部楼层
认真学习的jerry 发表于 2026-01-21 08:38
FishC 发表于 2026-1-21 08:29
你好!作为FishC的计 ...


你好!对于C语言实现Modbus TCP客户端,我为你提供一个简洁的解决方案。

在C语言中实现Modbus TCP客户端,通常使用socket编程。以下是详细步骤:

1. 建立TCP连接:使用标准的socket API连接网关。
2. 构造Modbus TCP报文:按照Modbus TCP协议格式构造请求帧。
3. 发送请求并接收响应。

下面是一个简单的C语言示例代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <arpa/inet.h>
  6. #include <sys/socket.h>

  7. #define PORT 502
  8. #define MBAP_HEADER_SIZE 7

  9. // 定义Modbus TCP报文结构(简化版)
  10. typedef struct {
  11.     uint16_t transaction_id;
  12.     uint16_t protocol_id;
  13.     uint16_t length;
  14.     uint8_t unit_id;
  15.     uint8_t function_code;
  16.     uint16_t starting_address;
  17.     uint16_t value;
  18. } modbus_write_single_register_t;

  19. int main() {
  20.     int sock = 0;
  21.     struct sockaddr_in serv_addr;
  22.    
  23.     // 创建socket
  24.     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  25.         printf("Socket创建失败\n");
  26.         return -1;
  27.     }
  28.    
  29.     serv_addr.sin_family = AF_INET;
  30.     serv_addr.sin_port = htons(PORT);
  31.    
  32.     // 设置网关IP地址(根据实际情况修改)
  33.     if (inet_pton(AF_INET, "192.168.1.100", &serv_addr.sin_addr) <= 0) {
  34.         printf("无效的地址\n");
  35.         return -1;
  36.     }
  37.    
  38.     // 连接网关
  39.     if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
  40.         printf("连接失败\n");
  41.         return -1;
  42.     }
  43.    
  44.     printf("连接成功!\n");
  45.    
  46.     // 准备写单个寄存器的请求(功能码6)
  47.     modbus_write_single_register_t request;
  48.    
  49.     // 设置MBAP头
  50.     request.transaction_id = htons(1);  // 事务ID
  51.     request.protocol_id = htons(0);     // 协议ID,Modbus TCP固定为0
  52.     request.length = htons(6);          // 后续字节数:单元ID1+功能码1+寄存器地址2+寄存器值2
  53.     request.unit_id = 1;                // 从站ID
  54.    
  55.     // 设置Modbus PDU
  56.     request.function_code = 0x06;       // 写单个寄存器
  57.     request.starting_address = htons(0); // 寄存器起始地址
  58.     request.value = htons(1000);        // 速度值,例如1000 RPM
  59.    
  60.     // 发送请求
  61.     int bytes_sent = send(sock, &request, sizeof(request), 0);
  62.     if (bytes_sent < 0) {
  63.         printf("发送失败\n");
  64.         close(sock);
  65.         return -1;
  66.     }
  67.    
  68.     printf("已发送%d字节数据\n", bytes_sent);
  69.    
  70.     // 接收响应
  71.     char buffer[256] = {0};
  72.     int bytes_received = recv(sock, buffer, sizeof(buffer), 0);
  73.     if (bytes_received < 0) {
  74.         printf("接收失败\n");
  75.     } else {
  76.         printf("收到响应:%d字节\n", bytes_received);
  77.         
  78.         // 打印响应报文(十六进制)
  79.         printf("响应报文(十六进制):");
  80.         for (int i = 0; i < bytes_received; i++) {
  81.             printf("%02X ", (unsigned char)buffer[i]);
  82.         }
  83.         printf("\n");
  84.         
  85.         // 解析响应
  86.         if (bytes_received >= 12) {
  87.             uint16_t received_value = (buffer[10] << 8) | buffer[11];
  88.             printf("写入的寄存器值:%d\n", ntohs(received_value));
  89.         }
  90.     }
  91.    
  92.     close(sock);
  93.     return 0;
  94. }
复制代码


对于你的具体需求,这里有一些关键点:

1. 确定网关信息:
   - 找到网关的IP地址(查看设备标签或使用网络扫描工具)
   - 确认Modbus TCP端口(默认502)

2. 理解Modbus TCP报文结构:
   - MBAP头(7字节):事务标识(2) + 协议标识(2) + 长度(2) + 单元标识(1)
   - PDU:功能码(1) + 数据(n字节)

3. 发送速度数据:
   - 通常使用功能码6(写单个寄存器)或功能码16(写多个寄存器)
   - 需要知道目标寄存器的地址(根据设备手册)
   - 速度数据可能需要转换为设备理解的格式(如16位整数、32位浮点数等)

4. 编译和运行:
   - 在Linux上使用gcc编译: gcc modbus_client.c -o modbus_client
   - 运行: ./modbus_client

5. 调试和测试:
   - 可以使用网络调试工具(如Wireshark)捕获和分析Modbus TCP报文
   - 先测试连接,再发送数据

如果你想使用更高级的C语言Modbus库,可以考虑:
- libmodbus(跨平台,功能完整)
- freemodbus(主要用于嵌入式系统)

如果你需要处理多个寄存器、读取数据或其他Modbus功能,代码结构类似,只需调整功能码和数据部分即可。

希望这个C语言示例能帮助你在你的系统中实现Modbus TCP通信!如果有更多问题,欢迎继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-1-21 09:04:14 | 显示全部楼层

回帖奖励 +5 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2026-1-30 14:40:47 | 显示全部楼层

回帖奖励 +5 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2026-1-30 20:51:38 | 显示全部楼层

回帖奖励 +5 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2026-1-31 10:49:24 | 显示全部楼层

回帖奖励 +5 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2026-1-31 10:54:23 | 显示全部楼层
不白拿,我来回复下。

TCP 转 RS485 的 Modbus 网关环境,无论你用什么品牌的 TCP 转 RS485 网关,Modbus TCP 通信都遵循固定标准,你可以按以下步骤先完成 “连接 - 获取报文 - 发送数据” 的核心逻辑:

1、确认网关基础信息:拿到网关后,先查网关的 IP 地址、Modbus TCP 端口(默认 502)、网关的 Modbus 从站地址(默认 1)、以及 RS485 侧设备的寄存器地址(比如速度数据存放在保持寄存器 40001)。
2、建立 TCP 连接:客户端(你的程序)主动连接网关的 IP:502 端口。
3、发送读寄存器指令:向网关发送 Modbus TCP 读指令,获取网关 / RS485 从站返回的报文(确认通信正常)。
4、解析返回报文:按 Modbus TCP 协议格式解析报文,确认数据格式。
5、发送自定义速度数据:按解析后的格式,构造写寄存器指令,将速度数据发送给网关。

C 语言实现完整代码:
推荐使用成熟的 libmodbus 库(工业级常用,避免重复造轮子),以下是可直接运行的代码,包含 “连接网关 - 读取报文 - 发送速度数据” 全流程:
1、环境准备:
# Ubuntu/Debian 系统
sudo apt-get install libmodbus-dev

# CentOS/RHEL 系统
sudo yum install libmodbus-devel

2、完整 C 语言代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <modbus/modbus.h>

  5. // 配置参数(根据你的网关实际信息修改)
  6. #define GATEWAY_IP      "192.168.1.100"  // 网关的IP地址
  7. #define GATEWAY_PORT    502             // Modbus TCP默认端口
  8. #define SLAVE_ID        1               // 网关/RS485从站地址
  9. #define SPEED_REG_ADDR  40001           // 速度数据对应的保持寄存器地址
  10. #define REG_NUM         1               // 读写的寄存器数量

  11. // 函数:建立Modbus TCP连接
  12. modbus_t* modbus_tcp_connect_gateway(const char* ip, int port) {
  13.     // 创建Modbus TCP上下文
  14.     modbus_t* ctx = modbus_new_tcp(ip, port);
  15.     if (ctx == NULL) {
  16.         fprintf(stderr, "创建Modbus TCP上下文失败:%s\n", modbus_strerror(errno));
  17.         return NULL;
  18.     }

  19.     // 设置从站地址
  20.     modbus_set_slave(ctx, SLAVE_ID);

  21.     // 建立TCP连接
  22.     if (modbus_connect(ctx) == -1) {
  23.         fprintf(stderr, "连接网关失败:%s\n", modbus_strerror(errno));
  24.         modbus_free(ctx);
  25.         return NULL;
  26.     }

  27.     printf("成功连接到Modbus TCP网关:%s:%d\n", ip, port);
  28.     return ctx;
  29. }

  30. // 函数:读取网关/从站的报文(读保持寄存器)
  31. int read_modbus_data(modbus_t* ctx, uint16_t reg_addr, uint16_t reg_num, uint16_t* data) {
  32.     // 转换Modbus寄存器地址(libmodbus使用0偏移,40001对应0)
  33.     uint16_t addr = reg_addr - 40001;

  34.     // 读取保持寄存器(核心:获取服务器/网关的报文)
  35.     int rc = modbus_read_holding_registers(ctx, addr, reg_num, data);
  36.     if (rc == -1) {
  37.         fprintf(stderr, "读取寄存器失败:%s\n", modbus_strerror(errno));
  38.         return -1;
  39.     }

  40.     // 打印读取到的报文数据(原始值)
  41.     printf("读取到网关返回的报文数据:寄存器[%d] = %d\n", reg_addr, data[0]);
  42.     return 0;
  43. }

  44. // 函数:发送自定义速度数据到网关(写保持寄存器)
  45. int send_speed_data(modbus_t* ctx, uint16_t reg_addr, uint16_t speed_value) {
  46.     // 转换Modbus寄存器地址(0偏移)
  47.     uint16_t addr = reg_addr - 40001;
  48.     uint16_t data[1] = {speed_value};

  49.     // 写入保持寄存器(发送自定义数据)
  50.     int rc = modbus_write_registers(ctx, addr, 1, data);
  51.     if (rc == -1) {
  52.         fprintf(stderr, "写入速度数据失败:%s\n", modbus_strerror(errno));
  53.         return -1;
  54.     }

  55.     printf("成功发送速度数据:%d 到寄存器[%d]\n", speed_value, reg_addr);
  56.     return 0;
  57. }

  58. int main() {
  59.     modbus_t* ctx = NULL;
  60.     uint16_t read_data[REG_NUM] = {0};
  61.     uint16_t target_speed = 1500;  // 你想发送的速度数据(示例:1500rpm)

  62.     // 1. 连接网关
  63.     ctx = modbus_tcp_connect_gateway(GATEWAY_IP, GATEWAY_PORT);
  64.     if (ctx == NULL) {
  65.         return -1;
  66.     }

  67.     // 2. 读取网关的报文(确认通信正常,获取当前数据)
  68.     if (read_modbus_data(ctx, SPEED_REG_ADDR, REG_NUM, read_data) == 0) {
  69.         // 3. 发送自定义速度数据
  70.         send_speed_data(ctx, SPEED_REG_ADDR, target_speed);

  71.         // 4. 验证:再次读取,确认数据已写入
  72.         printf("\n验证写入结果:\n");
  73.         read_modbus_data(ctx, SPEED_REG_ADDR, REG_NUM, read_data);
  74.     }

  75.     // 5. 关闭连接,释放资源
  76.     modbus_close(ctx);
  77.     modbus_free(ctx);

  78.     return 0;
  79. }
复制代码


3、编译和运营:
# 编译(链接libmodbus库)
gcc modbus_tcp_gateway.c -o modbus_gateway -lmodbus

# 运行
./modbus_gateway

Modbus 上下文创建:modbus_new_tcp() 创建 TCP 通信的上下文,是 libmodbus 的核心对象,封装了连接信息。
连接网关:modbus_connect() 建立 TCP 连接,失败时通过 modbus_strerror() 输出具体错误(如 IP 错误、端口不通、网关未上电)。
读取报文:modbus_read_holding_registers() 是获取网关报文的核心函数,它发送 Modbus 读指令,接收网关返回的报文并解析出寄存器值。
注意:Modbus 的 40001 寄存器在 libmodbus 中是 0 偏移(需减 40001),这是新手最容易踩的坑。
发送自定义数据:modbus_write_registers() 构造写指令报文,将速度数据写入网关指定寄存器,网关会自动通过 RS485 转发给从站设备。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2026-1-31 10:56:26 | 显示全部楼层
完全基于 Linux 系统的原生 socket 实现,不使用三方库的实现,包含 “连接网关→读寄存器(获取报文)→写寄存器(发送速度数据)” 全流程,注释详细,可直接编译运行:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <arpa/inet.h>
  7. #include <errno.h>

  8. // ===================== Modbus TCP 协议常量 =====================
  9. #define MODBUS_TCP_PORT       502        // Modbus TCP默认端口
  10. #define MODBUS_MBAP_HEADER_LEN 6         // MBAP头长度(字节)
  11. #define MODBUS_READ_HOLDING_REG_FUNC 0x03 // 读保持寄存器功能码
  12. #define MODBUS_WRITE_SINGLE_REG_FUNC 0x06 // 写单个寄存器功能码

  13. // ===================== 网关/设备配置(根据实际修改) =====================
  14. #define GATEWAY_IP       "192.168.1.100" // 网关IP
  15. #define SLAVE_ID         0x01            // 从站地址(网关/RS485设备)
  16. #define SPEED_REG_ADDR   40001           // 速度寄存器地址(保持寄存器)
  17. #define REG_NUM          1               // 读写寄存器数量

  18. // 函数:创建并连接TCP套接字
  19. int create_tcp_socket(const char* ip, int port) {
  20.     // 1. 创建TCP套接字
  21.     int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
  22.     if (sock_fd < 0) {
  23.         fprintf(stderr, "创建socket失败:%s\n", strerror(errno));
  24.         return -1;
  25.     }

  26.     // 2. 配置网关地址结构
  27.     struct sockaddr_in server_addr;
  28.     memset(&server_addr, 0, sizeof(server_addr));
  29.     server_addr.sin_family = AF_INET;
  30.     server_addr.sin_port = htons(port); // 转换为网络字节序(大端)
  31.    
  32.     // 转换IP字符串为网络字节序
  33.     if (inet_pton(AF_INET, ip, &server_addr.sin_addr) <= 0) {
  34.         fprintf(stderr, "IP地址无效:%s\n", ip);
  35.         close(sock_fd);
  36.         return -1;
  37.     }

  38.     // 3. 连接网关
  39.     if (connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
  40.         fprintf(stderr, "连接网关失败:%s\n", strerror(errno));
  41.         close(sock_fd);
  42.         return -1;
  43.     }

  44.     printf("成功连接到网关 %s:%d\n", ip, port);
  45.     return sock_fd;
  46. }

  47. // 函数:构造Modbus TCP读保持寄存器报文
  48. // 返回值:构造的报文长度
  49. int build_read_reg_packet(uint8_t* packet, uint16_t trans_id, uint16_t reg_addr, uint16_t reg_num) {
  50.     // 步骤1:转换寄存器地址(Modbus 40001 = 0x0000,需减40001)
  51.     uint16_t modbus_addr = reg_addr - 40001;

  52.     // 步骤2:构造MBAP头(6字节)
  53.     packet[0] = (trans_id >> 8) & 0xFF;       // 事务ID高字节
  54.     packet[1] = trans_id & 0xFF;              // 事务ID低字节
  55.     packet[2] = 0x00;                         // 协议ID高字节(固定0)
  56.     packet[3] = 0x00;                         // 协议ID低字节(固定0)
  57.     packet[4] = (0x06 >> 8) & 0xFF;           // 后续长度高字节(PDU长度=6)
  58.     packet[5] = 0x06 & 0xFF;                  // 后续长度低字节

  59.     // 步骤3:构造PDU(协议数据单元,6字节)
  60.     packet[6] = SLAVE_ID;                     // 从站地址
  61.     packet[7] = MODBUS_READ_HOLDING_REG_FUNC; // 功能码(0x03)
  62.     packet[8] = (modbus_addr >> 8) & 0xFF;    // 寄存器地址高字节
  63.     packet[9] = modbus_addr & 0xFF;           // 寄存器地址低字节
  64.     packet[10] = (reg_num >> 8) & 0xFF;       // 寄存器数量高字节
  65.     packet[11] = reg_num & 0xFF;              // 寄存器数量低字节

  66.     return MODBUS_MBAP_HEADER_LEN + 6; // 总报文长度:6+6=12字节
  67. }

  68. // 函数:构造Modbus TCP写单个寄存器报文
  69. int build_write_reg_packet(uint8_t* packet, uint16_t trans_id, uint16_t reg_addr, uint16_t value) {
  70.     // 转换寄存器地址
  71.     uint16_t modbus_addr = reg_addr - 40001;

  72.     // MBAP头(6字节)
  73.     packet[0] = (trans_id >> 8) & 0xFF;       // 事务ID高字节
  74.     packet[1] = trans_id & 0xFF;              // 事务ID低字节
  75.     packet[2] = 0x00;                         // 协议ID(固定0)
  76.     packet[3] = 0x00;
  77.     packet[4] = (0x06 >> 8) & 0xFF;           // PDU长度=6
  78.     packet[5] = 0x06 & 0xFF;

  79.     // PDU(6字节)
  80.     packet[6] = SLAVE_ID;                     // 从站地址
  81.     packet[7] = MODBUS_WRITE_SINGLE_REG_FUNC; // 功能码(0x06)
  82.     packet[8] = (modbus_addr >> 8) & 0xFF;    // 寄存器地址高字节
  83.     packet[9] = modbus_addr & 0xFF;           // 寄存器地址低字节
  84.     packet[10] = (value >> 8) & 0xFF;         // 写入值高字节
  85.     packet[11] = value & 0xFF;                // 写入值低字节

  86.     return MODBUS_MBAP_HEADER_LEN + 6; // 总长度12字节
  87. }

  88. // 函数:解析Modbus TCP读指令返回的报文
  89. // 返回值:解析出的寄存器值,失败返回-1
  90. int parse_read_response(uint8_t* response, int resp_len) {
  91.     // 校验响应长度(至少:MBAP头6 + 从站地址1 + 功能码1 + 字节数1 + 数据2 = 11字节)
  92.     if (resp_len < 11) {
  93.         fprintf(stderr, "响应报文长度异常:%d\n", resp_len);
  94.         return -1;
  95.     }

  96.     // 校验功能码(确认是读保持寄存器响应)
  97.     if (response[7] != MODBUS_READ_HOLDING_REG_FUNC) {
  98.         fprintf(stderr, "功能码不匹配:0x%02X\n", response[7]);
  99.         return -1;
  100.     }

  101.     // 提取寄存器数据(大端序转主机序)
  102.     uint16_t reg_value = (response[9] << 8) | response[10];
  103.     printf("解析网关返回报文成功:寄存器值 = %d\n", reg_value);
  104.     return reg_value;
  105. }

  106. // 函数:发送Modbus报文并接收响应
  107. int send_and_receive(int sock_fd, uint8_t* send_packet, int send_len, uint8_t* recv_buf, int recv_buf_len) {
  108.     // 1. 发送报文到网关
  109.     int send_bytes = write(sock_fd, send_packet, send_len);
  110.     if (send_bytes < 0) {
  111.         fprintf(stderr, "发送报文失败:%s\n", strerror(errno));
  112.         return -1;
  113.     }
  114.     printf("发送Modbus报文成功,长度:%d字节\n", send_bytes);

  115.     // 2. 接收网关响应(阻塞读取)
  116.     int recv_bytes = read(sock_fd, recv_buf, recv_buf_len);
  117.     if (recv_bytes < 0) {
  118.         fprintf(stderr, "接收响应失败:%s\n", strerror(errno));
  119.         return -1;
  120.     }
  121.     printf("接收网关响应报文,长度:%d字节\n", recv_bytes);

  122.     return recv_bytes;
  123. }

  124. int main() {
  125.     int sock_fd = -1;
  126.     uint8_t send_packet[256] = {0};  // 发送报文缓冲区
  127.     uint8_t recv_buf[256] = {0};     // 接收响应缓冲区
  128.     uint16_t trans_id = 0x0001;      // Modbus事务ID(自增,避免冲突)
  129.     int speed_value = 1500;          // 要发送的速度数据

  130.     // 1. 创建TCP连接
  131.     sock_fd = create_tcp_socket(GATEWAY_IP, MODBUS_TCP_PORT);
  132.     if (sock_fd < 0) {
  133.         return -1;
  134.     }

  135.     // 2. 构造并发送读寄存器报文(获取网关报文)
  136.     int send_len = build_read_reg_packet(send_packet, trans_id, SPEED_REG_ADDR, REG_NUM);
  137.     int recv_len = send_and_receive(sock_fd, send_packet, send_len, recv_buf, sizeof(recv_buf));
  138.     if (recv_len > 0) {
  139.         // 解析返回的报文,获取当前寄存器值
  140.         parse_read_response(recv_buf, recv_len);
  141.     }

  142.     // 3. 构造并发送写寄存器报文(发送速度数据)
  143.     trans_id++; // 事务ID自增
  144.     memset(send_packet, 0, sizeof(send_packet));
  145.     send_len = build_write_reg_packet(send_packet, trans_id, SPEED_REG_ADDR, speed_value);
  146.     recv_len = send_and_receive(sock_fd, send_packet, send_len, recv_buf, sizeof(recv_buf));
  147.     if (recv_len > 0) {
  148.         printf("速度数据 %d 已发送到网关\n", speed_value);
  149.     }

  150.     // 4. 关闭套接字
  151.     close(sock_fd);
  152.     return 0;
  153. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-2-11 21:00

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表