libmodbus是一个基于C语言实现的modbus驱动库,支持1 获取源代码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/
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
。文章图片
(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
#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
文章图片
(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
(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
#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;
}
文章图片
文章图片
推荐阅读
- C++|C++——类和对象2|构造函数|析构函数|拷贝构造函数|运算符重载|赋值运算符重载|赋值运算符连续赋值
- 服务器|Springboot+redis+Vue在Linux服务器下进行部署
- 服务器|Springboot+redis+Vue在windows服务器下进行部署
- Linux|远程访问 Linux 服务器中的 redis 数据库(腾讯云服务器 CentOS 8.0)
- 服务器|nginx优化
- linux|CSDN IT冷知识(每日更新)
- c#|C# FileSystemWatcher 多文件夹、多文件类型文件监控增加、修改、重命名和删除实例
- php|商家入驻商城 多商户商城 宝塔安装搭建教程 说明 小程序、h5、pc端
- serverless|一文搞懂传统单节点网站的 Serverless 上云