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

news2024/11/14 21:24:34

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.coloradmin.cn/o/1946025.html

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

相关文章

Mysql数据库第四次作业

mysql> create table student(sno int primary key auto_increment,sname varchar(30) not null unique,Ssex varchar(2) check (Ssex男 or Ssex女) not null,Sage int not null,Sdept varchar(10) default计算机 not null); mysql> create table Course(Con int primar…

【通信协议-RTCM】MSM语句(2) - RINEXMSM7语句总结(重要!自动化开发计算卫星状态常用)

注释&#xff1a; 在工作中主要负责的是RTCM-MSM7语句相关开发工作&#xff0c;所以主要介绍的就是MSM7语句相关内容 1. 相位校准参考信号 2. MSM1、MSM2、MSM3、MSM4、MSM5、MSM6和MSM7的消息头内容 DATA FIELDDF NUMBERDATA TYPENO. OF BITSNOTES Message Number - 消息编…

1. Docker的介绍和安装 (二)

5 Docker的原理 5.1 Namespace Namespace&#xff08;命名空间&#xff09;提供了一个独立的工作环境&#xff0c;Docker使用Namespace来隔离容器&#xff0c;使得每个容器都有自己独立的系统资源&#xff08;如进程ID、主机名、网络等&#xff09;。 PID Namespace&#xf…

SBTI科学碳目标认证是什么?SBTI科学碳目标的重要性

SBTI科学碳目标认证&#xff0c;作为企业在应对气候变化和追求可持续发展道路上的重要里程碑&#xff0c;其认证过程严谨而系统。以下是获得SBTI科学碳目标认证的详细步骤&#xff1a; 首先&#xff0c;企业需要在线注册并提交承诺书&#xff0c;郑重承诺在未来24个月内提交科学…

Linux网络-配置IP

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 本来IP配置应该放在Linux安装完成的就要配置的&#xff0c;但是由于那个时候对Linux不怎么熟悉&#xff0c;所以单独列了一个…

每日一题 LeetCode03 无重复字符的最长字串

1.题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长字串的长度。 2 思路 可以用两个指针, 滑动窗口的思想来做这道题,即定义两个指针.一个left和一个right 并且用一个set容器,一个length , 一个maxlength来记录, 让right往右走,并且用一个set容器来…

扫雷-C语言

一、前言&#xff1a; 众所周知&#xff0c;扫雷是一款大众类的益智小游戏&#xff0c;它的游戏目标是在最短的时间内根据点击格子出现的数字找出所有非雷格子&#xff0c;同时避免踩雷&#xff0c;踩到一个雷即全盘皆输。 今天&#xff0c;我们的目的就是通过C语言来实现一个简…

Open函数使用 Json与pickle Os模块

一. 文件操作与 open() 函数 Open函数是Python中用于打开文件的内置函数&#xff0c;其基本语法如下&#xff1a; open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 各参数说明&#xff1a; file&#xff1a; 要打开的文件…

34_YOLOv5网络详解

1.1 简介 YOLOV5是YOLO&#xff08;You Only Look Once&#xff09;系列目标检测模型的一个重要版本&#xff0c;由 Ultralytics 公司的Glenn Jocher开发并维护。YOLO系列以其快速、准确的目标检测能力而闻名&#xff0c;尤其适合实时应用。YOLOV5在保持高效的同时&#xff0c…

El-Table 表格的表头字段切换

最近写了一个小功能&#xff0c;比较有意思&#xff0c;特此博客记录。 提出需求&#xff1a;需要表头字段变化&#xff0c;但是我在官网上的表格相关上查找&#xff0c;没有发现便捷方法。 于是我有两个想法&#xff1a;1.做三个不同的表格。2.做一个表格使用不同的表头字段。…

2024.7.24 远程连接到另一设备(win)上的vrep时无响应(防火墙!)

Windows防火墙禁止了软件的端口的通信&#xff0c;打开即可 如何设置Windows 7 防火墙端口规则

字典集合案例

1.统计字符 统计字符串中每个字符出现的次数 s l like summer very much #去掉空格 s s.replace(" ","") d dict() for i in s:if i in d:d[i] 1else:d[i] 1 for i in d:print(i,d[i]) 2.求不重复的随机数 #导入随机数 import random a int(input(&q…

VMware 上安装 CentOS 7 教程 (包含网络设置)

**建议先看一些我安装VMware的教程&#xff0c;有些网络配置需要做一下 1.打开VMware&#xff0c;创建虚拟机 2.勾选自定义&#xff0c;点击下一步 3.点击下一步 4.勾选“稍后安装操作系统”&#xff0c;点击下一步 5.勾选linux&#xff0c;勾选centos7&#xff0c;点击下一步…

每日Attention学习12——Exterior Contextual-Relation Module

模块出处 [ISBI 22] [link] [code] Duplex Contextual Relation Network for Polyp Segmentation 模块名称 Exterior Contextual-Relation Module (ECRM) 模块作用 内存型特征增强模块 模块结构 模块思想 原文表述&#xff1a;在临床环境中&#xff0c;不同样本之间存在息肉…

Python算法基础:解锁冒泡排序与选择排序的奥秘

在数据处理和算法设计中&#xff0c;排序是一项基础且重要的操作。本文将介绍两种经典的排序算法&#xff1a;冒泡排序&#xff08;Bubble Sort&#xff09;和选择排序&#xff08;Selection Sort&#xff09;。我们将通过示例代码来演示这两种算法如何对列表进行升序排列。 一…

BGP选路之Local Preference

原理概述 当一台BGP路由器中存在多条去往同一目标网络的BGP路由时&#xff0c;BGP协议会对这些BGP路由的属性进行比较&#xff0c;以确定去往该目标网络的最优BGP路由。BGP首先比较的是路由信息的首选值&#xff08;PrefVal)&#xff0c;如果 PrefVal相同&#xff0c;就会比较本…

python-NLP:2词性标注与命名实体识别

文章目录 词性标注命名实体识别时间命名实体&#xff08;规则方法&#xff09;CRF 命名实体识别方法 词性标注 词性是词汇基本的语法属性&#xff0c;通常也称为词类。词性标注是在给定句子中判定每个词的语法范畴&#xff0c;确定其词性并加以标注的过程。例如&#xff0c;表示…

爱回收严选买的二手iPad Air 4已经使用一周啦!

有多少人是跟我一样&#xff0c;手里一旦有点小钱就留不住&#xff0c;只想花出去的&#xff1f; 本24届应届生目前刚开始实习工作&#xff0c;虽然工资低的可怜&#xff0c;但是比起大学时期还是宽裕了不少。 于是发完工资的我就非常想消费&#xff01;而我最近最想要的就是…

Fedora40安装telnet-server启用telnet服务

Fedora40安装telnet-server启用telnet服务 安装 telnet-server sudo yum install telnet-server或 sudo dnf install telnet-server启用服务 fedora40 或 CentosStream9 不能用 yum或dnf安装xinetd, telnet-server 的服务名为: telnet.socket 启用 telnet.socket.service …

Kithara和Halcon (二)

Kithara使用Halcon QT 进行二维码实时识别 目录 Kithara使用Halcon QT 进行二维码实时识别Halcon 简介以及二维码检测的简要说明Halcon 简介Halcon的二维码检测功能 Qt应用框架简介项目说明关键代码抖动测试测试平台&#xff1a;测试结果&#xff1a; 开源源码 Halcon 简介以…