FreeModbus学习——读输入寄存器eMBFuncReadInputRegister

FreeModbus版本:1.6

当功能码为04时,也就是读输入寄存器MB_FUNC_READ_INPUT_REGISTER

看一下它是怎么调用读输入寄存器处理函数的

当功能码为04时,调用读输入寄存器处理函数
在这里插入图片描述
这个函数在数组xFuncHandlers中,也就是eMBFuncReadInputRegister这个函数
在这里插入图片描述

来看一下这个函数

eMBException
eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )//帧   长度
{USHORT          usRegAddress;//寄存器地址USHORT          usRegCount;//寄存器数量UCHAR          *pucFrameCur;//当前帧指针eMBException    eStatus = MB_EX_NONE;//函数返回状态eMBErrorCode    eRegStatus;//寄存器读取状态//检查帧长度if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )//2个地址+2个寄存器数量+1个功能码{//获取寄存器地址usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );//pucFrame[1]   0为功能码usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );//1为寄存器地址高字节  2为寄存器地址低字节usRegAddress++;//地址+1//获取寄存器数量usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );//pucFrame[3]usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );//3为寄存器数量高字节  4为寄存器数量低字节/* Check if the number of registers to read is valid. If not* return Modbus illegal data value exception. */if( ( usRegCount >= 1 )&& ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )//检查寄存器数量是否在有效范围内{/* Set the current PDU data pointer to the beginning. */pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];//将当前数据帧指针指向数据帧的起始位置,并重置数据帧长度*usLen = MB_PDU_FUNC_OFF;//MB_PDU_FUNC_OFF为功能码偏移  0/* First byte contains the function code. */*pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;//在响应帧中添加功能码,长度+1*usLen += 1;/* Second byte in the response contain the number of bytes. */*pucFrameCur++ = ( UCHAR )( usRegCount * 2 );//在响应帧中添加寄存器数量,长度+1。*usLen += 1;//一个寄存器为16位,所以需要乘以2个字节//调用回调函数读取寄存器数据eRegStatus =eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );/* If an error occured convert it into a Modbus exception. */if( eRegStatus != MB_ENOERR ){eStatus = prveMBError2Exception( eRegStatus );}else{   //调用回调函数读取寄存器数据成功*usLen += usRegCount * 2;//响应数据长度 + 寄存器数量*2个字节}}else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}}else{/* Can't be a valid read input register request because the length* is incorrect. */eStatus = MB_EX_ILLEGAL_DATA_VALUE;}return eStatus;
}

eMBFuncReadInputRegister这个函数用于打包帧
输入参数是两个指针:
UCHAR * pucFrame, 帧 Modbus PDU 不包括 从机地址 和 CRC
USHORT * usLen帧长度

也就是说经过eMBFuncReadInputRegister这个函数处理之后,打包好的帧已经放在了pucFrame,长度放在了usLen。然后打包好的帧,会在eMBPoll轮询中被发送函数调用。然后通过发送状态机发送给主机。

来看一下eMBFuncReadInputRegister是怎么把帧打包的

首先定义了一些变量
在这里插入图片描述
变量里重要的是这个 UCHAR *pucFrameCur;//当前帧指针
pucFrameCur是指向这一帧 的 指针 ,可能有点绕
就是说这个指针pucFrameCur刚开始指向pucFrame这一帧数据的起始位置,然后打包一个数据,pucFrameCur+一个。

pucFrame是不包括从机地址 和 CRC的,也就是它的长度为5个字节 ,如下
在这里插入图片描述
(图取自安富莱modbus教程,安富莱教程写的非常好)

先检查帧的长度,2个地址+2个寄存器数量+1个功能码
在这里插入图片描述
然后获取寄存器地址和寄存器数量
在这里插入图片描述

然后开始打包数据
在这里插入图片描述
先将当前数据帧指针指向数据帧的起始位置,并重置数据帧长度

先把功能码打包 长度 +1
在把寄存器数量打包 长度+1
在看一下下面该打包啥了
看一下响应帧组成
在这里插入图片描述
(图取自安富莱modbus教程,安富莱教程写的非常好)

读取数据寄存器嘛,下面该打包 读取 到的 数据了

调用回调函数eMBRegInputCB读取寄存器数据,eMBRegInputCB这个函数会把读到的数据继续存放在pucFrameCur 帧里。

如果读取成功 则 usLen += usRegCount * 2; 响应数据长度 + 寄存器数量*2个字节

至此打包完成 。

在回到轮询函数eMBPoll
在这里插入图片描述

打包完之后 响应帧就已经存在ucMBFrame这里面了。

如果打包过程顺利的话

下面会调用peMBFrameSendCur开始发送响应帧(并不是这个函数发送,这个函数补充打包了地址+CRC)

如果万一打包不顺利,发生了错误。

则会将功能码 + 0x80 ,
在加一个异常码,
长度变为2。
如下图所示
在这里插入图片描述
(图取自安富莱modbus教程,安富莱教程写的非常好)

打包数据过程中的 读寄存器数据 那个回调函数怎么实现的呢

继续看一下eMBRegInputCB

eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{eMBErrorCode    eStatus = MB_ENOERR;int             iRegIndex;//寄存器数组索引usAddress = usAddress - 1;//传进来的地址+1了,这里要减1//判断地址是否在输入寄存器范围内if( ( usAddress >= REG_INPUT_START ) && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ){iRegIndex = ( int )( usAddress - usRegInputStart );//地址 - 开始地址  =  索引while( usNRegs > 0 ){*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );//寄存器值高位*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );//寄存器值低位iRegIndex++;usNRegs--;}}else{eStatus = MB_ENOREG;}return eStatus;
}

输入参数:
pucRegBuffer: 读到的寄存器数据
usAddress: 寄存器地址
usNRegs: 要读取的寄存器个数

这个函数并不复杂
读寄存器数据,其实就是读数组嘛,寄存器是16位的,所以定义数组也是16位的SHORT型。

读数组自然得有数组索引

索引 = 参数地址 - 开始地址
iRegIndex = ( int )( usAddress - usRegInputStart );获取索引
然后将数组中的值赋值给 * pucRegBuffer就好了

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

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

相关文章

实战:MyBatis适配多种数据库:MySQL、Oracle、PostGresql等

概叙 很多时候&#xff0c;一套代码要适配多种数据库&#xff0c;主流的三种库&#xff1a;MySQL、Oracle、PostGresql&#xff0c;刚好mybatis支持这种扩展&#xff0c;如下图所示&#xff0c;在一个“namespace”&#xff0c;判断唯一的标志是iddatabaseId&#xff0c;刚好写…

mysql索引结构

多种数据结构 在数据库索引领域&#xff0c;特别是MySQL的InnoDB存储引擎中&#xff0c;聚簇索引&#xff08;Clustered Index&#xff09;和非聚簇索引&#xff08;也称为二级索引&#xff0c;Secondary Index&#xff09;是两种主要的索引类型。这些索引类型在数据结构的选择…

最优化原理(笔记)

内积是线性代数运算的一个结果&#xff0c;一行*一列。 内积的性质&#xff01; 什么是范数&#xff1f;&#xff1f;&#xff1f; 对称矩阵&#xff1a;关于主对角线对称&#xff01; 正定对称矩阵&#xff1a; 二阶导是正定的&#xff0c;f(x)就是严格的凸函数&#xff01;&a…

spring部分源码分析及Bean的生命周期理解

前言&#xff1a; 本文整体框架是通过refresh方法这个入口进入分析&#xff1a;分析IOC容器的创建及一些Bean的生命周期的知识点&#xff0c;写得确实一般般&#xff0c;感觉自己的有些前置知识并没有理解的很到位&#xff0c;所以&#xff0c;这篇文件先记录一下&#xff0c;…

推荐一款开箱即用、开源、免费的中后台管理系统模版

项目介绍 vue-pure-admin 是推荐一款开箱即用、开源&#xff08;遵循MIT License开源协议&#xff09;、免费的中后台管理系统模版&#xff0c;完全采用 ECMAScript 模块&#xff08;ESM&#xff09;规范来编写和组织代码&#xff0c;使用了最新的 Vue3、 Vite、Element-Plus、…

无人机图像目标检测技术详解

当前研究领域的热点之一。无人机搭载的高清摄像头能够实时捕获大量图像数据&#xff0c;对这些数据进行有效的目标检测对于军事侦察、环境监测、灾害救援等领域具有重要意义。本文将对无人机图像目标检测技术进行详解&#xff0c;包括图像处理技术、目标检测算法、关键技术应用…

pdf2docx - pdf 提取内容转 docx

文章目录 一、关于 pdf2docx主要功能限制 二、安装1、 PyPI2、从remote安装3、从源码安装4、卸载 三、转化 PDF例 1: convert all pages例 2: 转换指定页面例 3: multi-Processing例 4: 转换加密的pdf 四、提取表格五、命令行交互1、按页面范围2、按页码3、Multi-Processing 六…

gitee设置ssh公钥密码频繁密码验证

gitee中可以创建私有项目&#xff0c;但是在clone或者push都需要输入密码&#xff0c; 比较繁琐。 公钥则可以解决该问题&#xff0c;将私钥放在本地&#xff0c;公钥放在gitee上&#xff0c;当对项目进行操作时带有的私钥会在gitee和公钥进行验证&#xff0c;避免了手动输入密…

C语言数据结构课设:基于EasyX前端界面的飞机订票系统

数据结构课程设计说明书 学 院、系&#xff1a; 软件学院 专 业&#xff1a; 软件工程 班 级&#xff1a; 学 生 姓 名&#xff1a; 范 学 号&#xff1a; 设 计 题 目&#xff1a; 飞机订票系统 起 迄 日 期: 2024年6月18日~ 20…

【测试能力提升-AI】AI介绍

注释&#xff1a; 搞python的最终梦想&#xff0c;搞机器&#xff0c;玩深度&#xff0c;通网络&#xff0c;知模型&#xff0c;拿下AI技术&#xff0c;尽管只是测试&#xff0c;但是也是有梦想的 1. 目标 完成AI任务 ---- 掌握成熟、标准的任务解决方法掌握AI工具 ---- 完成…

2022 年中高职组“网络安全”赛项-海南省省竞赛任务书-1-B模块-B-4Web渗透测试

前言 本章节我将尝试操作B-4模块的渗透测试&#xff0c;搭建环境很难&#xff0c;还望大家点点赞多多支持&#xff01; 任务概览 最后4、5、6有一定的难度。 环境要求 kali Linux192.168.41.2Web服务器&#xff08;假设为PYsystem 2020 模拟平台&#xff09;192.168.41.7交换…

postman接口测试实战篇

击杀小游戏接口测试 接口测试简单介绍击杀小游戏代码下载单接口测试(postman)接口关联并参数化接口测试简单介绍 首先思考两个问题:1.接口是什么?2.接口测试是什么? 1.我们总是把接口想的很复杂,其实呢,它就是一个有特定输入和输出参数的交互逻辑处理单元,它不需要知…

【实战】Spring Cloud Stream3.0 整合RocketMq

文章目录 前言技术积累Spring Cloud Stream3.0新特性RocketMq简介 实战演示引入Maven依赖增加application配置消息生产者消息消费者 前言 相信很多同学用使用过rocketmq消息中间件&#xff0c;且大多情况下是使用原生的rocketmq-spring-boot-starter 进行集成然后创建一个rock…

Spring中Bean的循环依赖

目录 定义&#xff1a; 循环依赖的后果&#xff1a; 一&#xff1a;三级缓存 1、大概的思路&#xff1a; 注意&#xff1a; 2、执行过程&#xff1a; A半完成&#xff1a; B完成&#xff1a; A完成&#xff1a; 注&#xff1a; 二&#xff1a;Lazy 定义&#xff1a; …

入门C语言只需一个星期(星期三)

点击上方"蓝字"关注我们 01、基本数据类型 char 1 字节 −128 ~ 127 单个字符/字母/数字/ASCIIsigned char 1 字节 −128 ~ 127 -unsigned char 1 字节 0 ~ 255 -int…

【SpringCloud】微服务远程调用OpenFeign

工作原理流程图 上代码 common中添加依赖&#xff1a; <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency><groupId>org.spri…

CV13_混淆矩阵、F1分数和ROC曲线

1.1 混淆矩阵Confusion Matrix 混淆矩阵&#xff08;Confusion Matrix&#xff09;是机器学习和统计学中用于描述监督学习算法性能的特定表格布局。它是一种特定类型的误差矩阵&#xff0c;可以非常直观地表示分类模型在测试数据集上的预测结果与实际结果之间的对比。 混淆矩…

【数据结构】初识集合框架

&#x1f387;&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳&#xff0c;欢迎大佬指点&#xff01; 人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友…

Python爬虫(6) --深层爬取

深层爬取 在前面几篇的内容中&#xff0c;我们都是爬取网页表面的信息&#xff0c;这次我们通过表层内容&#xff0c;深度爬取内部数据。 接着按照之前的步骤&#xff0c;我们先访问表层页面&#xff1a; 指定url发送请求获取你想要的数据数据解析 我们试着将以下豆瓣读书页…

河南萌新联赛2024第(二)场:南阳理工学院

A 国际旅行Ⅰ D A*BBBB F 水灵灵的小学弟 H 狼狼的备忘录 I 重生之zbk要拿回属于他的一切 J 这是签到 ##A 国际旅行Ⅰ 链接&#xff1a;https://ac.nowcoder.com/acm/contest/87255/A 来源&#xff1a;牛客网 题目描述 很久很久以前&#xff0c;有 n n n 个国家&#xff0c;第…