【嵌入式】Libmodbus之RTU模式Master端程序示例
00. 目录
文章目录
- 00. 目录
- 01. 软件开发流程
- 02. 获取版本信息
- 03. 读写单个线圈程序示例
- 04. 读写多个线圈程序示例
- 05. 读写单个保持寄存器程序示例
- 06. 读写多个保持寄存器程序示例
- 07. 读写多个寄存器测试(功能码0X17)
- 08. 附录
01. 软件开发流程
Modbus结合libmodbus开发库可以自由开发主设备端或从设备端的应用程序,而且支持RTU和TCP两种常用的模式。
开发主设备端(Master或者Client)程序的基本流程如下图所示:
开发从设备端(Slave或者Server)程序的基本流程如下图所示:
02. 获取版本信息
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>//包含Modbus相关头文件
#include "modbus.h"int main(void)
{printf("hello world\n");//输出libmodbus版本信息printf("Compiled with libmodbus version: %s (%06X)\n", LIBMODBUS_VERSION_STRING, LIBMODBUS_VERSION_HEX);//判断当前版本是否大于或者等于3.1.5if (LIBMODBUS_VERSION_CHECK(3, 1, 5)){printf("The functions to read/write float values are available (2.1.0).\n");}//判断当前版本是否大于或者等于3.1.6if (LIBMODBUS_VERSION_CHECK(3, 1, 6)){printf("Oh gosh, brand new API(3.1.6)!\n");}return 0;
}
执行结果
03. 读写单个线圈程序示例
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>//包含Modbus相关头文件
#include "modbus.h"//相关参数设置
#define LOOP 1 //循环次数
#define SERVER_ID 17 //从设备地址
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 99 //测试寄存器结束地址int main(void)
{modbus_t* ctx = NULL;int ret = -1;int nums = 0;int addr = 0;int i = 0;int tmp = 0;uint8_t* tab_rq_bits = NULL;uint8_t* tab_rp_bits = NULL;//1. 创建一个RTU类型的变量//设置串口设备 波特率 奇偶校验 数据位 停止位ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);if (NULL == ctx){fprintf(stderr, "Error: %s\n", modbus_strerror(errno));return 1;}else{printf("设置串口信息成功\n");}//2. 设置从机地址ret = modbus_set_slave(ctx, SERVER_ID);if (-1 == ret){fprintf(stderr, "Error: 设置从机地址失败\n");modbus_free(ctx);return 1;}//3. 设置Debug模式ret = modbus_set_debug(ctx, TRUE);if (-1 == ret){fprintf(stderr, "Error: 设置Debug模式失败");modbus_free(ctx);return 1;}//4. 在RTU模式下打开串口ret = modbus_connect(ctx);if (-1 == ret){fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return 1;}//5. 计算需测试的寄存器个数nums = ADDRESS_END - ADDRESS_START;//6. 申请内存 保存发送和接收的数据tab_rq_bits = (uint8_t*)malloc(nums * sizeof(uint8_t));if (NULL == tab_rq_bits){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rq_bits, 0, nums * sizeof(uint8_t));}tab_rp_bits = (uint8_t*)malloc(nums * sizeof(uint8_t));if (NULL == tab_rp_bits){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rp_bits, 0, nums * sizeof(uint8_t));}//7. 写单个线圈addr = ADDRESS_START;tmp = rand() / 100;tab_rq_bits[0] = tmp % 2;ret = modbus_write_bit(ctx, addr, tab_rq_bits[0]);if (1 != ret){printf("Error modbus_write_bit: %d\n", ret);printf("Address: %d value: %d\n", addr, tab_rq_bits[0]);}else{//读取单个线圈ret = modbus_read_bits(ctx, addr, 1, tab_rp_bits);if (1 != ret){printf("Error modbus_read_bits: %d\n", ret);}else{printf("tab_rp_bits[0]: %d tab_rq_bits[0]: %d\n", tab_rp_bits[0], tab_rq_bits[0]);}}//8. 释放内存free(tab_rp_bits);free(tab_rq_bits);//9. 断开连接modbus_close(ctx);modbus_free(ctx);return 0;
}
执行结果
04. 读写多个线圈程序示例
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>//包含Modbus相关头文件
#include "modbus.h"//相关参数设置
#define LOOP 1 //循环次数
#define SERVER_ID 17 //从设备地址
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 99 //测试寄存器结束地址int main(void)
{modbus_t* ctx = NULL;int ret = -1;int nums = 0;int addr = 0;int i = 0;int tmp = 0;uint8_t* tab_rq_bits = NULL;uint8_t* tab_rp_bits = NULL;//设置随机种子srand((int)time(0));//1. 创建一个RTU类型的变量//设置串口设备 波特率 奇偶校验 数据位 停止位ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);if (NULL == ctx){fprintf(stderr, "Error: %s\n", modbus_strerror(errno));return 1;}else{printf("设置串口信息成功\n");}//2. 设置从机地址ret = modbus_set_slave(ctx, SERVER_ID);if (-1 == ret){fprintf(stderr, "Error: 设置从机地址失败\n");modbus_free(ctx);return 1;}//3. 设置Debug模式ret = modbus_set_debug(ctx, TRUE);if (-1 == ret){fprintf(stderr, "Error: 设置Debug模式失败");modbus_free(ctx);return 1;}//4. 在RTU模式下打开串口ret = modbus_connect(ctx);if (-1 == ret){fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return 1;}//5. 计算需测试的寄存器个数nums = ADDRESS_END - ADDRESS_START;//6. 申请内存 保存发送和接收的数据tab_rq_bits = (uint8_t*)malloc((nums + 1) * sizeof(uint8_t));if (NULL == tab_rq_bits){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rq_bits, 0, (nums + 1) * sizeof(uint8_t));}tab_rp_bits = (uint8_t*)malloc((nums + 1) * sizeof(uint8_t));if (NULL == tab_rp_bits){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rp_bits, 0, (nums + 1) * sizeof(uint8_t));}//7. 写多个线圈//随机数字for (i = 0; i < nums; i++){tmp = rand() % 100;tab_rq_bits[i] = tmp % 2; if (0 == i){printf("写入的值: ");}printf("%hd ", tab_rq_bits[i]);}//换行printf("\n");addr = ADDRESS_START;ret = modbus_write_bits(ctx, addr, nums + 1, tab_rq_bits);if (nums + 1 != ret){printf("Error modbus_write_bit: %d\n", ret);printf("Address: %d nums: %d\n", addr, nums);}else{//读取多个线圈ret = modbus_read_bits(ctx, addr, nums + 1, tab_rp_bits);if (nums + 1 != ret){printf("Error modbus_read_bits: %d\n", ret);}else{//输出for (i = 0; i < nums; i++){if (0 == i){printf("读取到的值: ");}printf("%hd ", tab_rp_bits[i]);}//换行printf("\n");}}//8. 释放内存free(tab_rp_bits);free(tab_rq_bits);//9. 断开连接modbus_close(ctx);modbus_free(ctx);return 0;
}
执行结果
05. 读写单个保持寄存器程序示例
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>//包含Modbus相关头文件
#include "modbus.h"//相关参数设置
#define LOOP 1 //循环次数
#define SERVER_ID 17 //从设备地址
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 99 //测试寄存器结束地址int main(void)
{modbus_t* ctx = NULL;int ret = -1;int nums = 0;int addr = 0;int i = 0;int tmp = 0;uint16_t* tab_rq_registers = NULL;uint16_t* tab_rp_registers = NULL;//设置随机种子srand((int)time(0));//1. 创建一个RTU类型的变量//设置串口设备 波特率 奇偶校验 数据位 停止位ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);if (NULL == ctx){fprintf(stderr, "Error: %s\n", modbus_strerror(errno));return 1;}else{printf("设置串口信息成功\n");}//2. 设置从机地址ret = modbus_set_slave(ctx, SERVER_ID);if (-1 == ret){fprintf(stderr, "Error: 设置从机地址失败\n");modbus_free(ctx);return 1;}//3. 设置Debug模式ret = modbus_set_debug(ctx, TRUE);if (-1 == ret){fprintf(stderr, "Error: 设置Debug模式失败");modbus_free(ctx);return 1;}//4. 在RTU模式下打开串口ret = modbus_connect(ctx);if (-1 == ret){fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return 1;}//5. 计算需测试的寄存器个数nums = ADDRESS_END - ADDRESS_START;//6. 申请内存 保存发送和接收的数据tab_rq_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rq_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rq_registers, 0, (nums + 1) * sizeof(uint16_t));}tab_rp_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rp_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rp_registers, 0, (nums + 1) * sizeof(uint16_t));}//7. 测试保持寄存器的单个读写//随机数字tab_rq_registers[0] = rand() % 100;printf("写入的值为: %hd\n", tab_rq_registers[0]);//换行printf("\n");addr = ADDRESS_START;ret = modbus_write_register(ctx, addr, tab_rq_registers[0]);if (1 != ret){printf("Error modbus_write_register: %d\n", ret);}else{//读取数据ret = modbus_read_registers(ctx, addr, 1, tab_rp_registers);if (1 != ret){printf("Error modbus_read_registers: %d\n", ret);}else{//输出printf("读取到的值为: %hd\n", tab_rp_registers[0]);}}//8. 释放内存free(tab_rp_registers);free(tab_rq_registers);//9. 断开连接modbus_close(ctx);modbus_free(ctx);return 0;
}
执行结果
06. 读写多个保持寄存器程序示例
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>//包含Modbus相关头文件
#include "modbus.h"//相关参数设置
#define LOOP 1 //循环次数
#define SERVER_ID 17 //从设备地址
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 99 //测试寄存器结束地址int main(void)
{modbus_t* ctx = NULL;int ret = -1;int nums = 0;int addr = 0;int i = 0;int tmp = 0;uint16_t* tab_rq_registers = NULL;uint16_t* tab_rp_registers = NULL;//设置随机种子srand((int)time(0));//1. 创建一个RTU类型的变量//设置串口设备 波特率 奇偶校验 数据位 停止位ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);if (NULL == ctx){fprintf(stderr, "Error: %s\n", modbus_strerror(errno));return 1;}else{printf("设置串口信息成功\n");}//2. 设置从机地址ret = modbus_set_slave(ctx, SERVER_ID);if (-1 == ret){fprintf(stderr, "Error: 设置从机地址失败\n");modbus_free(ctx);return 1;}//3. 设置Debug模式ret = modbus_set_debug(ctx, TRUE);if (-1 == ret){fprintf(stderr, "Error: 设置Debug模式失败");modbus_free(ctx);return 1;}//4. 在RTU模式下打开串口ret = modbus_connect(ctx);if (-1 == ret){fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return 1;}//5. 计算需测试的寄存器个数nums = ADDRESS_END - ADDRESS_START;//6. 申请内存 保存发送和接收的数据tab_rq_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rq_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rq_registers, 0, (nums + 1) * sizeof(uint16_t));}tab_rp_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rp_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rp_registers, 0, (nums + 1) * sizeof(uint16_t));}//7. 测试保持寄存器的单个读写
//随机数字for (i = 0; i < nums; i++){tmp = rand() % 100;tab_rq_registers[i] = tmp;if (0 == i){printf("写入的值: ");}printf("%hd ", tab_rq_registers[i]);}//换行printf("\n");addr = ADDRESS_START;ret = modbus_write_registers(ctx, addr, nums + 1, tab_rq_registers);if (nums + 1 != ret){printf("Error modbus_write_registers: %d\n", ret);printf("Address: %d nums: %d\n", addr, nums + 1);}else{//读取ret = modbus_read_registers(ctx, addr, nums + 1, tab_rp_registers);if (nums + 1 != ret){printf("Error modbus_read_registers: %d\n", ret);}else{//输出for (i = 0; i < nums; i++){if (0 == i){printf("读取到的值: ");}printf("%hd ", tab_rp_registers[i]);}//换行printf("\n");}}//8. 释放内存free(tab_rp_registers);free(tab_rq_registers);//9. 断开连接modbus_close(ctx);modbus_free(ctx);return 0;
}
执行结果
07. 读写多个寄存器测试(功能码0X17)
程序示例
#include <stdio.h>#ifndef _MSC_VER
#include <unistd.h>
#endif#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>//包含Modbus相关头文件
#include "modbus.h"//相关参数设置
#define LOOP 1 //循环次数
#define SERVER_ID 17 //从设备地址
#define ADDRESS_START 0 //测试寄存器起始地址
#define ADDRESS_END 99 //测试寄存器结束地址int main(void)
{modbus_t* ctx = NULL;int ret = -1;int nums = 0;int addr = 0;int i = 0;int tmp = 0;uint16_t* tab_rq_registers = NULL;uint16_t* tab_rp_registers = NULL;//设置随机种子srand((int)time(0));//1. 创建一个RTU类型的变量//设置串口设备 波特率 奇偶校验 数据位 停止位ctx = modbus_new_rtu("COM4", 9600, 'N', 8, 1);if (NULL == ctx){fprintf(stderr, "Error: %s\n", modbus_strerror(errno));return 1;}else{printf("设置串口信息成功\n");}//2. 设置从机地址ret = modbus_set_slave(ctx, SERVER_ID);if (-1 == ret){fprintf(stderr, "Error: 设置从机地址失败\n");modbus_free(ctx);return 1;}//3. 设置Debug模式ret = modbus_set_debug(ctx, TRUE);if (-1 == ret){fprintf(stderr, "Error: 设置Debug模式失败");modbus_free(ctx);return 1;}//4. 在RTU模式下打开串口ret = modbus_connect(ctx);if (-1 == ret){fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return 1;}//5. 计算需测试的寄存器个数nums = ADDRESS_END - ADDRESS_START;//6. 申请内存 保存发送和接收的数据tab_rq_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rq_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rq_registers, 0, (nums + 1) * sizeof(uint16_t));}tab_rp_registers = (uint16_t*)malloc((nums + 1) * sizeof(uint16_t));if (NULL == tab_rp_registers){fprintf(stderr, "malloc failed\n");modbus_free(ctx);return 1;}else{memset(tab_rp_registers, 0, (nums + 1) * sizeof(uint16_t));}//7. 测试保持寄存器的单个读写//随机数字for (i = 0; i < nums; i++){tmp = rand() % 100;tab_rq_registers[i] = tmp;if (0 == i){printf("写入的值: ");}printf("%hd ", tab_rq_registers[i]);}//换行printf("\n");addr = ADDRESS_START;//先写入,后读取该数据到指定的内存中ret = modbus_write_and_read_registers(ctx, addr, nums + 1, tab_rq_registers,addr, nums + 1, tab_rp_registers);if (nums + 1 != ret){printf("Error modbus_write_and_read_registers: %d\n", ret);printf("Address: %d nums: %d\n", addr, nums + 1);}else{//输出for (i = 0; i < nums; i++){if (0 == i){printf("读取到的值: ");}printf("%hd ", tab_rp_registers[i]);}//换行printf("\n");}//再次读取数据memset(tab_rp_registers, 0, (nums + 1) * sizeof(uint16_t));ret = modbus_read_registers(ctx, addr, nums + 1, tab_rp_registers);if (nums + 1 != ret){printf("Error modbus_read_registers: %d\n", ret);}else{//输出for (i = 0; i < nums; i++){if (0 == i){printf("读取到的值: ");}printf("%hd ", tab_rp_registers[i]);}//换行printf("\n");}//8. 释放内存free(tab_rp_registers);free(tab_rq_registers);//9. 断开连接modbus_close(ctx);modbus_free(ctx);return 0;
}
执行结果
08. 附录
源码下载:RTU模式Master端编程.rar
【嵌入式】Libmodbus之RTU模式Master端程序示例相关推荐
- 【嵌入式】Libmodbus之TCP模式Master端程序示例
00. 目录 文章目录 00. 目录 01. TCP模式Master开发流程 02. 读写单个线圈程序示例 03. 读写多个线圈程序示例 04. 读写单个保持寄存器程序示例 05. 读写多个保持寄存器 ...
- 【嵌入式】Libmodbus之RTU模式Slave端程序示例
00. 目录 文章目录 00. 目录 01. 开发RTU Slave端程序流程 02. RTU Slave端程序示例 03. RTU Slave端程序说明 04. 预留 05. 附录 01. 开发RT ...
- 【嵌入式】Libmodbus之TCP模式Slave端程序示例
00. 目录 文章目录 00. 目录 01. 开发TCPSlave端程序流程 02. TCP Slave端程序示例 03. TCP Slave端程序说明 04. 预留 05. 附录 01. 开发TCP ...
- 关于winform串口程序(二)数据的发送(modbus协议RTU模式)
串口项目使用的协议为Modbus,简介什么的我就不在网络上面班门弄斧了,下面就介绍一下Modbus发送指令的格式,以及我对数据的处理. 关于Modbus的数据传输如下: Modicon 控制器上的标准 ...
- 【技术分享】linux各种一句话反弹shell总结——攻击者指定服务端,受害者主机(无公网IP)主动连接攻击者的服务端程序(CC server),开启一个shell交互,就叫反弹shell。...
反弹shell背景: 想要搞清楚这个问题,首先要搞清楚什么是反弹,为什么要反弹. 假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常 ...
- 大端模式小端模式 主机序网络序
1. 主机序 不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序,这个叫做主机序.最常见的有两种: 1. Little endian:将低序字节存储在起始地址. 即小端 ...
- 大端模式小端模式、主机序网络序、入栈地址高低问题
一.大端模式&小端模式 所谓的"大端模式",是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把 ...
- 编写一个字节数的rtu C语言校验程序,Modbus通信协议中CRC校验的快速C语言算法
Modbus通信协议中CRC校验的快速C语言算法 2004年第11期 福 建 电 脑 63 Modbus通信协议中CRC校验的快速C语言算法 孟开元 (西安石油大学计算机学院陕西西安710065) [ ...
- anybackup mysql_AnyBackup-Linux MySQL 云容灾失败,执行输出提示错误:Master 端未开启 MySQL BinLog,请开启 BinLog 后重新发起任务...
关键字 MySQL BinLog 适用产品 AnyBackup 6.0.x 问题描述 执行 MySQL 云容灾失败,执行输出提示错误,点击查看详情显示下列错误信息: MySQL 容灾任务出现异常.(错 ...
最新文章
- 使用CSS更改HTML5输入的占位符颜色
- JSP学习02-config内置对象
- 深到骨子里的自律,是每周坚持刷几篇最新论文 | PaperDaily #10
- 10个超级好用的快捷键技巧,知道的都是大神!
- onhashchange
- java可视化压缩_WEB可视化技术发展
- Android获取所有Activity
- 2020-08-24 每日一句
- python适合做网站吗_python做网站吗
- TFN系列超声波探伤仪为什么在众多品牌竞争中脱颖而出
- 1436:数列分段II
- 【转载】OFFICE使用技巧FAQ宝典
- 如何锁定计算机硬盘,详细教您如何给硬盘加密
- 三点法求三维坐标精度误差评估实验
- 谷歌Chrome 操作系统基于浏览器的OS
- Revit开发之内建模型
- 简谈几种ddos防御方法
- 2022年上海落户全部方式!落户上海政策变化及条件汇总!
- LeetCode 岛屿的最大面积
- 何为非侵入式负荷分解
热门文章
- 【C#】【Thread】上下文同步域SynchronizationAttribute
- python字符编码使用_python – Numpy字符串编码
- Java黑皮书课后题第3章:*3.1(代数:解一元二次方程)可以使用下面的公式求一元二次方程ax2+bx+c=0,编写程序提示用户输入a b c的值,并显示基于判断式的结果
- 启动日志_Hybris服务器启动日志分析
- Token 认证的来龙去脉,DRF认证,DRF权限,DRF限制
- WCF 动态调用(1)
- 四条命令搞定mysql主从
- Win8装SQL2008需要离线安装 .Net3.5
- 我们都是和自己赛跑的人
- 网络营销常用工具与资源