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端程序示例相关推荐

  1. 【嵌入式】Libmodbus之TCP模式Master端程序示例

    00. 目录 文章目录 00. 目录 01. TCP模式Master开发流程 02. 读写单个线圈程序示例 03. 读写多个线圈程序示例 04. 读写单个保持寄存器程序示例 05. 读写多个保持寄存器 ...

  2. 【嵌入式】Libmodbus之RTU模式Slave端程序示例

    00. 目录 文章目录 00. 目录 01. 开发RTU Slave端程序流程 02. RTU Slave端程序示例 03. RTU Slave端程序说明 04. 预留 05. 附录 01. 开发RT ...

  3. 【嵌入式】Libmodbus之TCP模式Slave端程序示例

    00. 目录 文章目录 00. 目录 01. 开发TCPSlave端程序流程 02. TCP Slave端程序示例 03. TCP Slave端程序说明 04. 预留 05. 附录 01. 开发TCP ...

  4. 关于winform串口程序(二)数据的发送(modbus协议RTU模式)

    串口项目使用的协议为Modbus,简介什么的我就不在网络上面班门弄斧了,下面就介绍一下Modbus发送指令的格式,以及我对数据的处理. 关于Modbus的数据传输如下: Modicon 控制器上的标准 ...

  5. 【技术分享】linux各种一句话反弹shell总结——攻击者指定服务端,受害者主机(无公网IP)主动连接攻击者的服务端程序(CC server),开启一个shell交互,就叫反弹shell。...

    反弹shell背景: 想要搞清楚这个问题,首先要搞清楚什么是反弹,为什么要反弹. 假设我们攻击了一台机器,打开了该机器的一个端口,攻击者在自己的机器去连接目标机器(目标ip:目标机器端口),这是比较常 ...

  6. 大端模式小端模式 主机序网络序

    1. 主机序 不同的CPU有不同的字节序类型这些字节序是指整数在内存中保存的顺序,这个叫做主机序.最常见的有两种: 1.         Little endian:将低序字节存储在起始地址. 即小端 ...

  7. 大端模式小端模式、主机序网络序、入栈地址高低问题

    一.大端模式&小端模式 所谓的"大端模式",是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把 ...

  8. 编写一个字节数的rtu C语言校验程序,Modbus通信协议中CRC校验的快速C语言算法

    Modbus通信协议中CRC校验的快速C语言算法 2004年第11期 福 建 电 脑 63 Modbus通信协议中CRC校验的快速C语言算法 孟开元 (西安石油大学计算机学院陕西西安710065) [ ...

  9. anybackup mysql_AnyBackup-Linux MySQL 云容灾失败,执行输出提示错误:Master 端未开启 MySQL BinLog,请开启 BinLog 后重新发起任务...

    关键字 MySQL BinLog 适用产品 AnyBackup 6.0.x 问题描述 执行 MySQL 云容灾失败,执行输出提示错误,点击查看详情显示下列错误信息: MySQL 容灾任务出现异常.(错 ...

最新文章

  1. 使用CSS更改HTML5输入的占位符颜色
  2. JSP学习02-config内置对象
  3. 深到骨子里的自律,是每周坚持刷几篇最新论文 | PaperDaily #10
  4. 10个超级好用的快捷键技巧,知道的都是大神!
  5. onhashchange
  6. java可视化压缩_WEB可视化技术发展
  7. Android获取所有Activity
  8. 2020-08-24 每日一句
  9. python适合做网站吗_python做网站吗
  10. TFN系列超声波探伤仪为什么在众多品牌竞争中脱颖而出
  11. 1436:数列分段II
  12. 【转载】OFFICE使用技巧FAQ宝典
  13. 如何锁定计算机硬盘,详细教您如何给硬盘加密
  14. 三点法求三维坐标精度误差评估实验
  15. 谷歌Chrome 操作系统基于浏览器的OS
  16. Revit开发之内建模型
  17. 简谈几种ddos防御方法
  18. 2022年上海落户全部方式!落户上海政策变化及条件汇总!
  19. LeetCode 岛屿的最大面积
  20. 何为非侵入式负荷分解

热门文章

  1. 【C#】【Thread】上下文同步域SynchronizationAttribute
  2. python字符编码使用_python – Numpy字符串编码
  3. Java黑皮书课后题第3章:*3.1(代数:解一元二次方程)可以使用下面的公式求一元二次方程ax2+bx+c=0,编写程序提示用户输入a b c的值,并显示基于判断式的结果
  4. 启动日志_Hybris服务器启动日志分析
  5. Token 认证的来龙去脉,DRF认证,DRF权限,DRF限制
  6. WCF 动态调用(1)
  7. 四条命令搞定mysql主从
  8. Win8装SQL2008需要离线安装 .Net3.5
  9. 我们都是和自己赛跑的人
  10. 网络营销常用工具与资源