linux|libmodbus使用

libmodbus是一个基于C语言实现的modbus驱动库,支持LinuxMac OS XWin32等操作系统。
支持如下功能:
  • 支持Modbus-RTU
  • 支持Modbus-TCP
  • 支持常用功能码(01/02/03/04/05/06/07/0F/10/11/16/17)。
  • 支持线圈类型读写、寄存器读写、离散量读取等。
  • 支持广播地址0,从机地址1-247
  • 支持浮点数和整型数据转换,大小端等多种模式。
1 获取源代码
官网最新版本:libmodbus-3.1.7.tar.gz
开源仓库地址:https://github.com/stephane/libmodbus/
2 生成config.h配置文件
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}/includecompiler:gcc cflags:-g -O2 ldflags:documentation:no tests:yes

3 使用
3.1 Modbus主站 3.1.1 Poll-Modbus-TCP 使用Modbus Slave模拟从站设备,libmodbus作为主站读写从站保持寄存器。
(1)Modbus Slave连接配置
【linux|libmodbus使用】点击Connection,选择Connect,弹出Connection Setup对话框,Connection选择Modbus TCP/IP,IP Address填写为192.168.3.100(电脑本机地址),Port填写为502
linux|libmodbus使用
文章图片

(2)Modbus Slave从机配置
点击Setup,选择Slave Definition,Slave ID填写为1,Function选择为03 Holding Register(4x),Address填写为0,Quantity填写为10
linux|libmodbus使用
文章图片

(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 #include #include #include "modbus.h"#define MODBUS_TCP_SERVER_IP"192.168.3.100"// TCP IP地址 #define MODBUS_TCP_SERVER_PORT502// TCP 端口号#define REG_ADDR_START0// 寄存器起始地址 #define REG_ADDR_END9// 寄存器结束地址 #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

linux|libmodbus使用
文章图片

(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
3.2 Modbus从站 3.2.1 Slave-Modbus-TCP 使用Modbus Poll模拟主站设备,libmodbus作为从站。
(1)Modbus Poll连接配置
点击Connection,选择Connect,弹出Connection Setup对话框,Connection选择Modbus TCP/IP,IP Address填写为192.168.3.102(Ubuntu从机地址),Port填写为1502
linux|libmodbus使用
文章图片

(2)Modbus Slave主机配置
点击Setup,选择Read/Write Definition,Slave ID填写为1,Function选择为03 Holding Register(4x),Address填写为0,Quantity填写为10
linux|libmodbus使用
文章图片

(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 #include #include #include #include "modbus.h"#define MODBUS_SLAVE_TCP_SERVER_IP"192.168.3.102" #define MODBUS_SLAVE_TCP_SERVER_PORT1502 #define MAPPING_SIZE10 #define MODBUS_POLL_CONNECT_MAX1int 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; }

linux|libmodbus使用
文章图片

linux|libmodbus使用
文章图片

    推荐阅读