网络编程(Modbus进阶)

思维导图

Modbus RTU(先学一点理论)

概念

Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包括RS232/485等工业总线协议。

与Modbus TCP区别

与modbus TCP不同的是RTU没有报文头MBAP字段,但是在尾部增加了两个CRC检验字节(CRC16),因为网络协议中自带校验,所以在TCP协议中不需要使用CRC校验码。

RTU和TCP的总体使用方法基本一致,只是在创建modbus对象时有所不同,TCP需要传入网络socket信息;而RTU需要传入串口相关信息。

特点

1.遵循主从问答的通信方式

2.采用串口的方式进行通信

设置串口参数时要求:(了解,后续还会用)

波特率为9600(波特率是指每秒钟传输的比特数)

8位数据位 (数据位是指每个字符中包含的比特数)

1位停止位 (停止位是指在每个字符传输结束后添加的比特数)

无流控 (流控是指在数据传输过程中控制数据流量的一种机制,无流控表示在该设置下没有额外的控制机制来控制数据流量)

modbus rtu协议格式

地址码 功能码 数据 校验码

地址码(1字节):从机ID

功能码(1字节):和modbus tcp一样(01 02 03 04 05 06 0f 10H)

数据:起始地址、地址、数量、数据、字节计数;和modbus tcp一样。

校验码(2字节):对地址码、功能码、数据进行校验,由函数生成,循环冗余校验 (低字节在前)

其实modbus rtu协议的格式和modbus tcp是很像,就是把tcp的MBAP报文头去掉,只保留了一个字节的主机ID,最后结尾加上了两个字节的校验码。(校验码没有实际意义,是函数生成的不用管

 以01发送的数据格式为例,可以看到数据位是一样的,上图就是tcp和rtu协议格式的区别。数据接收也是和tcp一样的,所以就不再讲了。

modbus 库

官方文档:libmodbus

1库的安装

第一步和第二步都要运行,第一步是为了安装配置,第二步是为了让你使用这个库更方便,把它放在你的C语言库里。​​​​​

1.1库的安装配置(共四步)

通过网盘分享的文件:sqlite-autoconf-3460000.tar.gz
链接: https://pan.baidu.com/s/1ro8-xbsFitDSEEK6mSYzwQ?pwd=3521 提取码: 3521

直接复制命令,别手打,按顺序

1. (先下载压缩包,CtrlC+V复制到虚拟机任意路径下)在linux中解压压缩包

tar -xvf libmodbus-3.1.7.tar.gz

2. 进入源码目录

cd libmodbus-3.1.7

3.创建文件夹(存放头文件、库文件)

mkdir install

4.执行脚本configure,进行安装配置(指定安装目录)

./configure --prefix=$PWD/install

5. 执行make

make                        //编译

6.执行make install

make install                //安装

执行完成后会在install文件夹下生产对应的头文件、库文件件夹install,用于存放产生的头文件、库文件等

1.2.库的使用

要想编译方便,可以将头文件和库文件放到系统路径下(直接复制命令,别手打,按顺序

sudo cp include/modbus/*.h /usr/include

sudo cp lib/* -r /lib -d

后期编译时,可以直接gcc xx.c -lmodbus(和编译有关线程代码一样)

头文件默认搜索路径:/usr/include/usr/local/include(之前文章库里的内容

库文件默认搜索路径:/lib/usr/lib

2.函数接口

在上面的官方文档里包含所有的函数接口,以下是常用的modbus tcp函数接口,上个文章尝试自己写函数,这里就是使用这些别人写好的库函数(更方便)。

modbus_t* modbus_new_tcp(const char *ip, int port)

功能:以TCP方式创建Modbus实例,并初始化

参数:ip :ip地址

           port:端口号

返回值:成功:Modbus实例

失败:NULL

int modbus_set_slave(modbus_t *ctx, int slave)

功能:设置从机ID

参数:ctx :Modbus实例

           slave:从机ID

返回值:成功:0

               失败:-1

int modbus_connect(modbus_t *ctx)

功能:和从机(slave)建立连接

参数:ctx:Modbus实例

返回值:成功:0

               失败:-1

void modbus_free(modbus_t *ctx)

功能:释放Modbus实例

参数:ctx:Modbus实例

void modbus_close(modbus_t *ctx)

功能:关闭套接字

参数:ctx:Modbus实例

int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

功能:读取线圈状态,可读取多个连续线圈的状态(对应功能码为0x01

参数:ctx :Modbus实例

           addr :寄存器起始地址

           nb :寄存器个数

           dest :得到的状态值

返回值:成功:读到的数量

               失败:-1

int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

功能:读取输入状态,可读取多个连续输入的状态(对应功能码为0x02

参数:ctx :Modbus实例

           addr :寄存器起始地址

           nb :寄存器个数

           dest :得到的状态值

返回值:成功:返回nb的值

               失败:-1

int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

功能:读取保持寄存器的值,可读取多个连续保持寄存器的值(对应功能码为0x03

参数:ctx :Modbus实例

           addr :寄存器起始地址

           nb :寄存器个数

           dest :得到的寄存器的值

返回值:成功:读到寄存器的个数

               失败:-1

int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

功能:读输入寄存器的值,可读取多个连续输入寄存器的值(对应功能码为0x04

参数:ctx :Modbus实例

           addr :寄存器起始地址

           nb :寄存器个数

           dest :得到的寄存器的值

返回值:成功:读到寄存器的个数

               失败:-1

int modbus_write_bit(modbus_t *ctx, int addr, int status);

功能:写入单个线圈的状态(对应功能码为0x05

参数:ctx :Modbus实例

           addr :线圈地址

           status:线圈状态

返回值:成功:1

               失败:-1

int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);

功能:写入多个连续线圈的状态(对应功能码为15

参数:ctx :Modbus实例

           addr :线圈地址

           nb :线圈个数

           src :多个线圈状态

返回值:成功:写入的数量

               失败:-1

int modbus_write_register(modbus_t *ctx, int addr, int value);

功能: 写入单个寄存器(对应功能码为0x06

参数: ctx :Modbus实例

            addr :寄存器地址

            value :寄存器的值

返回值:成功:1

               失败:-1

int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);

功能:写入多个连续寄存器(对应功能码为16

参数:ctx :Modbus实例

           addr :寄存器地址

           nb :寄存器的个数

           src :多个寄存器的值

返回值:成功:写入的数量

               失败:-1

有关读取浮点的就不全举例了,感兴趣可以去查看官方文档

float modbus_get_float_dcba(const uint16_t *src)

功能:读取浮点类型的数据

参数:src:读到数据的存放数组

返回值:转换后的浮点类型

编程

从上往下写就可以连接到Modbus Slave,ip要写主机的IP地址,不要写成虚拟机的IP地址。,你要是在虚拟机运行的Modbus Slave,那就可以写虚拟机地址。

编程步骤

1.创建实例

2.设置从机ID

3.建立连接

4.寄存器操作(按需选择)

5.关闭套接字

6.释放实例

编程实现

1.基础步骤实现:
#include <modbus.h>
#include <stdio.h>int main(int argc, char const *argv[])
{char ip[128] = {"192.168.50.224"};         //IPint port = 502;                            //端口号int slave = 1;                             //从机地址int addr = 0x0000;                         //寄存器地址int nb = 0x0002;                           //寄存器数uint16_t dest[12] = {0};                   //接收数组// 创建实例// IP与端口号可作为命令行传参modbus_t *modbus = modbus_new_tcp(ip, port);if (modbus == NULL){perror("err\n");return -1;}//设置从机IDmodbus_set_slave(modbus, slave);   //建立连接int con = modbus_connect(modbus);if (con == -1){perror("con:\n");return -1;}//寄存器操作int read = modbus_read_registers(modbus, addr, nb, dest);if (read == -1){perror("read:\n");return -1;}for (int i = 0; i < read; i++){printf("%d ", dest[i]);}putchar(10);//关闭套接字modbus_close(modbus);//释放实例modbus_free(modbus);return 0;
}
2.数据采集小项目:

编程实现采集传感器数据和控制硬件设备(传感器和硬件通过slave模拟)

传感器:2个,光线传感器、加速度传感器(x\y\z)

硬件设备:2个,led灯、蜂鸣器

要求:

1.多任务编程:建议多线程

2.循环1s采集一次数据,并将数据打印至终端

3.同时从终端输入指令控制硬件设备

        0 1:led灯打开

        0 0:led灯关闭

        1 1:蜂鸣器开

        1 0:蜂鸣器关

#include <stdio.h>
#include <modbus.h>
#include <unistd.h>
#include <pthread.h>void *handler1(void *arg){            //内不含阻塞,相当于后台运行uint8_t dest1[32] = {0};uint16_t dest2[32] = {0};modbus_t *modbusid = (modbus_t *)arg;int size = 0;while(1){								//读取线圈状态size = modbus_read_bits(modbusid,0,2,dest1);if(size == -1){					//容错判断perror("modbus_read_registers err");break;}printf("LED:%02x 蜂鸣器:%02x\n",dest1[0],dest1[1]);//查询寄存器数值size = modbus_read_registers(modbusid,0,2,dest2);if(size == -1){					//容错判断perror("modbus_read_registers err");break;}printf("温度传感器:%02x 加速度传感器:%02x\n",dest2[0],dest2[1]);sleep(5);                        //5秒打印一次}
}void *handler2(void *arg){                    //用于执行写操作,需要输入指令modbus_t *modbusid = (modbus_t *)arg;int addr,nb,status;int a = 0;				        //标志操作05,06while(1){scanf("%d",&a);				//选择操作if(a == 5){					//操作单个线圈scanf("%d %d",&addr,&status);modbus_write_bit(modbusid,addr,status);}else if(a == 6){			//操作单个寄存器scanf("%d %d",&addr,&nb);modbus_write_register(modbusid,addr,nb);}if(a == -1)break;}
}int main(int argc, const char *argv[])
{//创建实例modbus_t *modbusid = modbus_new_tcp("192.168.43.148",502);if(modbusid == NULL){perror("modbus_new_tcp err");return -1;}//设置从机IDint slave = 1;if(modbus_set_slave(modbusid,slave) == -1){perror("modbus_set_slave err");return -1;}//建立连接if(modbus_connect(modbusid) == -1){perror("modbus_connect err");return -1;}//寄存器操作pthread_t ptid1;pthread_create(&ptid1,NULL,handler1,modbusid);        //创建第一个线程pthread_detach(ptid1);pthread_t ptid2;pthread_create(&ptid2,NULL,handler2,modbusid);        //创建第二个线程pthread_join(ptid2,NULL);//关闭套接字modbus_close(modbusid);//释放实例modbus_free(modbusid);return 0;
}

五秒打印一次,终端还可以输入命令取改变寄存器和线圈值

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84289.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R语言速释制剂QBD解决方案之二

影响含量均一性的显著因子&#xff08;%RSD&#xff09; 数据分析表明含量均一性的弯曲性不显著。如半正态图&#xff08;图12&#xff09;所示&#xff0c;影响含量均一性的显著因子为A&#xff08;原料药粒径&#xff09;和C&#xff08;MCC/Lactose&#xff09;。 mod2 <…

大模型原理、架构与落地

近年来&#xff0c;大模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;在人工智能领域迅猛发展&#xff0c;从GPT-3到GPT-4、Claude、Gemini、文心一言、GLM等模型相继发布&#xff0c;大模型已逐渐走出实验室&#xff0c;迈向产业落地。本文将从技术原理、…

WWDC 2025 macOS 26有哪些更新点

在2025年6月10日凌晨结束的WWDC 2025发布会中&#xff0c;苹果正式发布了全新的macOS 26&#xff0c;并给其命名为Tahoe。 以下为macOS相关的主要内容&#xff1a; 命名方式改变 苹果正式将各大系统的版本号改为对应年份&#xff0c;让命名方式更直观好记&#xff0c;macOS 2…

AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月10日第104弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀4-5个和值&#xff0c;可以做到100-300注左右。 (1)定…

.NET 8集成阿里云短信服务完全指南【短信接口】

文章目录 前言一、准备工作1.1 阿里云账号准备1.2 .NET 8项目创建 二、集成阿里云短信SDK2.1 安装NuGet包2.2 配置阿里云短信参数2.3 创建配置类 三、实现短信发送服务3.1 创建短信服务接口3.2 实现短信服务3.3 注册服务 四、创建控制器五、测试与优化5.1 单元测试5.2 性能优化…

解决HuggingFace不能git clone的问题

今天在从HuggingFace上clone项目的时候&#xff0c;一直出现超时问题&#xff0c;查了很多资料没有解决&#xff0c;后来向mentor请教了一下&#xff0c;可以通过镜像的方法解决这个问题&#xff0c;所以把方法放上来&#xff0c;希望对大家有帮助。 HuggingFace的服务器在国外…

Zookeeper 集群部署与故障转移

Zookeeper 介绍 Zookeeper 是一个开源的分布式协调服务&#xff0c;由Apache基金会维护&#xff0c;专为分布式应用提供高可用、强一致性的核心基础能力。它通过简单的树形命名空间&#xff08;称为ZNode树&#xff09;存储数据节点&#xff08;ZNode&#xff09;&#xff0c;…

简单聊下阿里云DNS劫持事件

阿里云域名被DNS劫持事件 事件总结 根据ICANN规则&#xff0c;域名注册商&#xff08;Verisign&#xff09;认定aliyuncs.com域名下的部分网站被用于非法活动&#xff08;如传播恶意软件&#xff09;&#xff1b;顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…

服务器出现故障怎么办?快速排查与解决方法

服务器故障的常见原因分析 硬件故障&#xff1a;内存、硬盘、网络设备故障。 软件故障&#xff1a;操作系统、应用程序、数据库异常。 网络攻击&#xff08;如DDoS攻击&#xff09;造成资源耗尽。 快速排查故障的步骤 检查监控系统报警日志。 查看系统资源使用情况&#x…

Claude vs ChatGPT vs Gemini:功能对比、使用体验、适合人群

随着AI应用全面进入生产力场景&#xff0c;市面上的主流AI对话工具也进入“三国杀”时代&#xff1a; Claude&#xff08;Anthropic&#xff09;&#xff1a;新锐崛起&#xff0c;语言逻辑惊艳&#xff0c;Opus 模型被称为 GPT-4 杀手ChatGPT&#xff08;OpenAI&#xff09;&a…

Git 使用大全:从入门到精通

Git 是目前最流行的分布式版本控制系统&#xff0c;被广泛应用于软件开发中。本文将全面介绍 Git 的各种功能和使用方法&#xff0c;包含大量代码示例和实践建议。 文章目录 Git 基础概念版本控制系统Git 的特点Git 的三个区域Git 文件状态 Git 安装与配置安装 GitLinuxmacOSWi…

SpringBoot 框架第 1 次接口调用慢

文章目录 背景分析思路 1:DeepSeek 分析思路 2:日志分析思路 3:Arthas 分析下载 Arthas启动 Arthastrace 调用耗时分析Controller 调用耗时Service 调用分析ServiceImpl 耗时分析IService 耗时分析BaseMapper 耗时分析debug 执行链路MyBatisMapperProxy 解读解决思路 1:预热…

数据分析Agent构建

数据分析agent构建 代码资料来源于 Streamline-Analyst&#xff0c;旨在通过该仓库上的代码了解如何使用大语言模型构建数据分析工具&#xff1b; 个人仓库&#xff1a;Data-Analysis-Agent-Tutorial 不同的在于 Data-Analysis-Agent-Tutorial 是在 Streamline-Analyst 基础…

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …

Python爬虫(三):BeautifulSoup库

1. BeautifulSoup是什么&#xff1f; BeautifulSoup 是一个 Python 库&#xff0c;专门用来解析 HTML 或 XML 文件&#xff0c;方便我们提取数据。它能把网页源代码转换成树形结构&#xff0c;让我们可以轻松查找、修改内容&#xff0c;并自动处理编码问题&#xff08;如 Unic…

AI电销机器人智能的发展趋势是什么?

AI电销机器人智能的发展趋势是什么&#xff1f;电销机器人智能的发展前景怎么样&#xff1f;随着互联网技术的不断发展&#xff0c;AI电销机器人智能已经成为了许多企业实现销售数字化转型的重要工具&#xff0c;我们一起来看看。 AI电销机器人正突破传统语音机械应答的边界&a…

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…

C++_哈希表

本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、基础概念 1. 哈希核心思想&#xff1a; 哈希函数的作用&#xff1a;通过此函数建立一个Key与存储位置之间的映射关系。理想目标&#xff1a;实现…