赞
踩
libmodbus是一个基于C语言实现的modbus驱动库,支持
Linux
、Mac OS X
、Win32
等操作系统。支持如下功能:
- 支持
Modbus-RTU
。- 支持
Modbus-TCP
。- 支持常用功能码(01/02/03/04/05/06/07/0F/10/11/16/17)。
- 支持线圈类型读写、寄存器读写、离散量读取等。
- 支持广播地址
0
,从机地址1-247
。- 支持浮点数和整型数据转换,大小端等多种模式。
官网最新版本:libmodbus-3.1.7.tar.gz
开源仓库地址:https://github.com/stephane/libmodbus/
Linux终端下执行如下命令完成解压:
sudo tar zxvf libmodbus-3.1.7.tar.gz
解压后的libmodbus-3.1.7目录结构如下:
. ├── acinclude.m4 ├── aclocal.m4 ├── AUTHORS ├── build-aux/ ├── config.h.in ├── configure* ├── configure.ac ├── COPYING.LESSER ├── doc/ ├── libmodbus.pc.in ├── m4/ ├── Makefile.am ├── Makefile.in ├── MIGRATION ├── NEWS ├── README.md ├── src/ └── tests/
Linux终端下执行如下命令生成config.h配置文件:
./configure
生成后提示如下:
libmodbus 3.1.7
===============
prefix: /usr/local
sysconfdir: ${prefix}/etc
libdir: ${exec_prefix}/lib
includedir: ${prefix}/include
compiler: gcc
cflags: -g -O2
ldflags:
documentation: no
tests: yes
使用Modbus Slave模拟从站设备,libmodbus作为主站读写从站保持寄存器。
(1)Modbus Slave连接配置
点击Connection,选择Connect,弹出Connection Setup对话框,Connection选择Modbus TCP/IP
,IP Address填写为192.168.3.100
(电脑本机地址),Port填写为502
。
(2)Modbus Slave从机配置
点击Setup,选择Slave Definition,Slave ID填写为1
,Function选择为03 Holding Register(4x)
,Address填写为0
,Quantity填写为10
。
(3)poll_wr_regs_demo读写例程
/** * @file poll_wr_regs_demo.c * @author 李云亮 (1144626145@qq.com) * @brief modbus主站读写多个保持寄存器 * @version 1.0.0 * @date 2022-08-19 * * @copyright Copyright (c) 2022 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "modbus.h" #define MODBUS_TCP_SERVER_IP "192.168.3.100" // TCP IP地址 #define MODBUS_TCP_SERVER_PORT 502 // TCP 端口号 #define REG_ADDR_START 0 // 寄存器起始地址 #define REG_ADDR_END 9 // 寄存器结束地址 #define REG_NUM ((REG_ADDR_END) - (REG_ADDR_START) + 1) // 寄存器个数 int main(int argc, char const *argv[]) { /* code */ int i = 0; int ret = 0; modbus_t* ctx = NULL; uint16_t* sendBuf = NULL; uint16_t* recvBuf = NULL; // 1.创建TCP ctx = modbus_new_tcp(MODBUS_TCP_SERVER_IP, MODBUS_TCP_SERVER_PORT); if (NULL == ctx) { printf("Set modbus TCP failed!\n"); return -1; } // 2.设置调试模式 ret = modbus_set_debug(ctx, TRUE); if (-1 == ret) { printf("Set modbus debug mode failed!\n"); } // 3.连接Server ret = modbus_connect(ctx); if (-1 == ret) { printf("Connect modbus server failed!\n"); modbus_free(ctx); return -1; } // 4.设置从机地址 ret = modbus_set_slave(ctx, 1); // 5.申请内存 sendBuf = (uint16_t*)malloc(REG_NUM * (sizeof(uint16_t))); if (NULL == sendBuf) { printf("modbus sendBuf malloc failed!\n"); free(sendBuf); return -1; } recvBuf = (uint16_t*)malloc(REG_NUM * (sizeof(uint16_t))); if (NULL == recvBuf) { printf("modbus recvBuf malloc failed!\n"); free(recvBuf); return -1; } memset(sendBuf, 0, REG_NUM); memset(recvBuf, 0, REG_NUM); // 6.写入多个保持寄存器 for (i = 0; i < REG_NUM; i++) { sendBuf[i] = i; } ret = modbus_write_registers(ctx, REG_ADDR_START, REG_NUM, sendBuf); if (REG_NUM != ret) { printf("modbus write regs failed!\n"); return -1; } else { // 7.读多个保持寄存器 ret = modbus_read_registers(ctx, REG_ADDR_START, REG_NUM, recvBuf); if (REG_NUM != ret) { printf("modbus read regs failed!\n"); return -1; } else { printf("result data:\n"); for (i = 0; i < REG_NUM; i++) { printf("%d ", recvBuf[i]); } printf("\n"); } } // 8.释放内存 free(sendBuf); free(recvBuf); // 9.断开连接 modbus_close(ctx); modbus_free(ctx); return 0; }
(4)编译与执行
lyl@ubuntu18:~/Desktop/gitee/libmodbus-demo/libmodbusUse$ make
+ Linking output/demo/poll_wr_regs_demo ...
lyl@ubuntu18:~/Desktop/gitee/libmodbus-demo/libmodbusUse$ ./output/demo/poll_wr_regs_demo
Connecting to 192.168.3.100:502
[00][01][00][00][00][1B][01][10][00][00][00][0A][14][00][00][00][01][00][02][00][03][00][04][00][05][00][06][00][07][00][08][00][09]
Waiting for a confirmation...
<00><01><00><00><00><06><01><10><00><00><00><0A>
[00][02][00][00][00][06][01][03][00][00][00][0A]
Waiting for a confirmation...
<00><02><00><00><00><17><01><03><14><00><00><00><01><00><02><00><03><00><04><00><05><00><06><00><07><00><08><00><09>
result data:
0 1 2 3 4 5 6 7 8 9
(5)数据帧分析
主站写寄存器分析
# 主站写多个寄存器
[00][01][00][00][00][1B][01][10][00][00][00][0A][14][00][00][00][01][00][02][00][03][00][04][00][05][00][06][00][07][00][08][00][09]
通信标识符 | 协议标识符 | 数据长度 | 从机地址 | 功能码 | 起始地址 | 寄存器数量 | 数据长度 | 数据 |
---|---|---|---|---|---|---|---|---|
00 01 | 00 00 | 00 1B | 01 | 0x10(16) | 00 00 | 00 0A(10) | 0x14(20) | 0-9 |
# 从站返回写结果
<00><01><00><00><00><06><01><10><00><00><00><0A>
通信标识符 | 协议标识符 | 数据长度 | 从机地址 | 功能码 | 起始地址 | 寄存器数量 |
---|---|---|---|---|---|---|
00 01 | 00 00 | 00 06 | 01 | 0x10(16) | 00 00 | 00 0A(10) |
主站读寄存器分析
# 主站读多个寄存器
[00][02][00][00][00][06][01][03][00][00][00][0A]
通信标识符 | 协议标识符 | 数据长度 | 从机地址 | 功能码 | 起始地址 | 寄存器数量 |
---|---|---|---|---|---|---|
00 02 | 00 00 | 00 06 | 01 | 03 | 00 00 | 00 0A(10) |
# 从站返回读结果
<00><02><00><00><00><17><01><03><14><00><00><00><01><00><02><00><03><00><04><00><05><00><06><00><07><00><08><00><09>
通信标识符 | 协议标识符 | 数据长度 | 从机地址 | 功能码 | 数据长度 | 数据 |
---|---|---|---|---|---|---|
00 02 | 00 00 | 00 17(23) | 01 | 03 | 0x14(20) | 0-9 |
使用Modbus Poll模拟主站设备,libmodbus作为从站。
(1)Modbus Poll连接配置
点击Connection,选择Connect,弹出Connection Setup对话框,Connection选择Modbus TCP/IP
,IP Address填写为192.168.3.102
(Ubuntu从机地址),Port填写为1502
。
(2)Modbus Slave主机配置
点击Setup,选择Read/Write Definition,Slave ID填写为1
,Function选择为03 Holding Register(4x)
,Address填写为0
,Quantity填写为10
。
(3)slave_wr_regs_demo读写例程
/** * @file slave_wr_regs_demo.c * @author 李云亮 (1144626145@qq.com) * @brief modbus从站读写例程 * @version 1.0.0 * @date 2022-08-25 * * @copyright Copyright (c) 2022 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "modbus.h" #define MODBUS_SLAVE_TCP_SERVER_IP "192.168.3.102" #define MODBUS_SLAVE_TCP_SERVER_PORT 1502 #define MAPPING_SIZE 10 #define MODBUS_POLL_CONNECT_MAX 1 int main(int argc, char const *argv[]) { /* code */ int socket = -1; modbus_t *ctx; modbus_mapping_t *mb_mapping; uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH] = {0}; int rc = 0; int i = 0; // 1.创建从机TCP ctx = modbus_new_tcp(MODBUS_SLAVE_TCP_SERVER_IP, MODBUS_SLAVE_TCP_SERVER_PORT); //开发板ip自行修改 if (NULL == ctx) { printf("Set modbus TCP failed!\n"); return -1; } // 2.设置调试模式 modbus_set_debug(ctx, TRUE); // 3.初始化寄存器 mb_mapping = modbus_mapping_new(MAPPING_SIZE, MAPPING_SIZE, MAPPING_SIZE, MAPPING_SIZE); if (mb_mapping == NULL) { printf("Failed to allocate the mapping!\n"); modbus_free(ctx); return -1; } for (i = 0; i < MAPPING_SIZE; i++) { mb_mapping->tab_registers[i] = i; } // 4.侦听主站连接 socket = modbus_tcp_listen(ctx, MODBUS_POLL_CONNECT_MAX); if (-1 == socket) { printf("Unable to listen TCP!\n"); modbus_free(ctx); return -1; } // 5.创建连接 modbus_tcp_accept(ctx, &socket); while (1) { // 6.接收请求 rc = modbus_receive(ctx, query); if (rc > 1) { // 7.发送响应 modbus_reply(ctx, query, rc, mb_mapping); printf("In the loop \n"); } else { // Connection closed by the client or error modbus_mapping_free(mb_mapping); modbus_close(ctx); modbus_free(ctx); modbus_tcp_accept(ctx, &socket); break; } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。