FreeModbus学习——eMBPoll轮询

news2024/9/19 23:52:54

FreeModbus版本:1.6
eMBPoll在mb.c文件中

eMBPoll 函数是一个核心的 Modbus 协议栈事件处理函数,负责接收和发送帧,处理不同的事件,并根据需要返回错误码。

eMBErrorCode
eMBPoll( void )
{
    static UCHAR   *ucMBFrame;          //接收到的帧数据
    static UCHAR    ucRcvAddress;       //接收到的帧的地址
    static UCHAR    ucFunctionCode;     //接收到的帧的功能码
    static USHORT   usLength;           //接收到的帧的长度
    static eMBException eException;     //接收到的帧的异常码,用于发回去的错误帧

    int             i;                  //for循环变量
    eMBErrorCode    eStatus = MB_ENOERR;//函数返回值 错误码
    eMBEventType    eEvent;             //事件状态类型

    /* Check if the protocol stack is ready. */
    if( eMBState != STATE_ENABLED )     //协议栈使能后是STATE_ENABLED态。
    {
        return MB_EILLSTATE;
    }

    /* Check if there is a event available. If not return control to caller.
     * Otherwise we will handle the event. */
    if( xMBPortEventGet( &eEvent ) == TRUE )//如果有事件发生,则处理事件。
    {
        switch ( eEvent )
        {
        case EV_READY:      /*协议栈使能后,会将接收状态机赋值为初始化态,且定时器也使能,
                            * 定时器进入溢出中断,会将接收状态机由初始化态变为 空闲态
                            * 并且发布一个EV_READY事件*/
            break;

        case EV_FRAME_RECEIVED:/*接收状态机为空闲态时,接收到一个字符,会进入串口接收中断,
                             * 串口接收中断中会将接收到的字符保存作为帧首,并且把接收状态机变为STATE_RX_RCV。
                             * 也就是接收状态机为接收态,每接收到一个字符,会进入中断,然后把定时器清0。
                             * 直到距离下个字符超过定时器溢出时间,进入定时器中断,此时接受状态机为STATE_RX_RCV,这就意味着接受完成了一帧。
                             * 然后发布事件EV_FRAME_RECEIVED*/
            eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );//接收帧数据
            if( eStatus == MB_ENOERR )
            {
                /* Check if the frame is for us. If not ignore the frame. */
                if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
                {
                    /*检查地址是否匹配,如果是则发布事件EV_EXECUTE*/
                    ( void )xMBPortEventPost( EV_EXECUTE );
                }
            }
            break;

        case EV_EXECUTE://处理帧数据
            ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];//获取功能码
            eException = MB_EX_ILLEGAL_FUNCTION;        //异常码默认为非法功能码,如果处理成功则改为正常功能码
            for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
            {
                /* No more function handlers registered. Abort. */
                if( xFuncHandlers[i].ucFunctionCode == 0 )
                {
                    break;
                }
                else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )//找到功能码
                {
                    eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );//调用功能码对应的处理函数
                    break;
                }
            }

            /* If the request was not sent to the broadcast address we
             * return a reply. */
            if( ucRcvAddress != MB_ADDRESS_BROADCAST )
            {
                if( eException != MB_EX_NONE )      //如果处理过程中出现异常,则返回异常响应帧
                {
                    /* An exception occured. Build an error frame. */
                    usLength = 0;
                    ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
                    ucMBFrame[usLength++] = eException;
                }
                eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );//发送响应帧
            }
            break;

        case EV_FRAME_SENT:
            break;
        }
    }
    return MB_ENOERR;
}

注释已经写详细
在具体来看一下吧
首先定义变量,帧相关的变量都是静态的,循环进入的时候并不会被清0。
在这里插入图片描述
在调用协议栈使能函数之后,协议栈状态为使能态
在这里插入图片描述
获取事件,如果有事件发生xMBPortEventGet会返回TRUE,反之返回FALSE
在这里插入图片描述
然后根据获取到的时间进行分别处理
就是一个switch语句。
也就是说在while(1)大循环里调用eMBPoll ,就是在不停地读事件然后处理事件,每次只处理一个。
EV_READY
当就绪事件时啥也不做,就绪事件怎么来的呢。协议栈使能后,会将接收状态机赋值为初始化态,且定时器也使能,定时器进入溢出中断,会将接收状态机由初始化态变为空闲态,并且发布一个EV_READY事件。
在这里插入图片描述
在这里插入图片描述

也就是说,协议栈使能后,并不是立马开始工作的,万一这个时候串口接收寄存器已将有数据呢?并不能判断它是不是帧首,所以要等一个定时器溢出中断,发布一个就绪事件EV_READY,然后如果这时候在接收到数据才可以作为帧首。
妙啊,刚开始看别人讲一直没想明白,直到读源码才看明白。

EV_FRAME_RECEIVED
当一帧接收完成时,这个事件怎么来的呢。
接收状态机为空闲态时(每次定时器溢出中断会将接收机状态置为空闲态),接收到一个字符,会进入串口接收中断,串口接收中断中会将接收到的字符保存作为帧首,并且把接收状态机变为STATE_RX_RCV。也就是接收状态机为接收态,每接收到一个字符,会进入串口接收中断,然后把定时器计数清0。直到一帧结束,也就是距离下个字符超过定时器溢出时间,进入定时器中断,此时接收状态机还为STATE_RX_RCV,这就意味着接受完成了一帧。然后发布事件EV_FRAME_RECEIVED
在这里插入图片描述

通过函数eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );接收这一帧数据

检查帧地址是否匹配,发布事件EV_EXECUTE,这样下一次大循环进入eMBPoll就会处理EV_EXECUTE处理事件。

EV_EXECUTE
处理帧数据。
从一帧数据中,获取功能码。
异常码默认为非法功能码,如果处理成功则改为正常功能码。
遍历数组xFuncHandlers,这里面存放的是功能码以及对应的处理函数。
找到数组中的功能码,然后调用对应的处理函数
在这里插入图片描述

在这里插入图片描述
蓝色框框出来的就是对应的处理函数。

继续往下

如果地址不是广播地址,则要进行响应。(可以修改一下,就算是广播地址也响应,把外面的if注释掉就行)
如果处理过程中出现异常,则返回异常响应帧
在这里插入图片描述
取值 : 功能码 | 0x80 + 异常码
调用peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );发送响应帧

peMBFrameSendCur 会调用 eMBRTUSend,此函数就是组合好响应帧,真发还是串口中断发。但是这个函数里好像没有调用发送函数?

eMBRTUSend会将发送状态机设为发送态STATE_TX_XMIT。

在发送完成中断里会调用这个函数xMBRTUTransmitFSM

如果发送状态机为发送态,并且把该发送的数量都发完了,会发布事件EV_FRAME_SENT

发送完成事件不做处理
在这里插入图片描述
至此eMBPoll轮询完成。

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

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

相关文章

zabbix添加钉钉告警机器人使用bash和python两种脚本

zabbix添加钉钉告警机器人使用bash和python两种脚本 查看脚本目录 vi /etc/zabbix/zabbix_server.conf# 脚本存放路径 AlertScriptsPath/usr/lib/zabbix/alertscripts编写脚本&#xff08;二选一&#xff09; bash脚本 编写脚本 cd /usr/lib/zabbix/alertscripts vi zabbi…

00 RabbitMQ:前言

00 RabbitMQ&#xff1a;前言 1. 前言1.1. 举个&#x1f330;&#xff1a;快递案例1.1.1. 过程对比1.1.2. 延伸到程序中 1.2. 举个&#x1f330;&#xff1a;订单案例1.2.1. 流程1.2.2. 耦合1.2.3. 响应时间1.2.4. 并发压力1.2.5. 系统结构弹性 1.3. 总结 1. 前言 1.1. 举个&a…

机器人开源调度系统OpenTCS-6最新版本地源码运行

OpenTCS 项目使用 Gradle 而不是 Maven&#xff0c;那么需要使用 Gradle 来导入和构建项目。在 IntelliJ IDEA 中导入和运行使用 Gradle 的项目&#xff0c;可以按照以下步骤进行操作&#xff1a; 克隆 OpenTCS 源码 首先&#xff0c;克隆 OpenTCS 的源码到本地。您可以使用以…

2. 深度学习的项目流程(批量化打包数据、构建模型、训练模型、波士顿房价预测、激活函数、多层感知机)

深度学习流程 1. 深度学习基本流程1.1 流程图1.2 代码实现1.3 基本概念 2. 深度学习项目流程2.1 批量化打包数据2.2 构建模型2.3 训练模型&#xff08;1&#xff09;筹备训练&#xff08;2&#xff09;开始训练 2.4 模型推理 3. 深度学习实现波士顿房价预测3.1 数据读取、切分、…

Visio绘制的Sigmoid激活函数结构图,可导出高清图片,可修改,无水印。

Visio绘制的Sigmoid激活函数结构图,可导出高清图片&#xff0c;可修改&#xff0c;无水印。 方便用于小论文写作&#xff0c;方便用于毕业设计。 Visio版本为2021版&#xff0c;可用更高版本打开。 下载地址&#xff1a;地址 图片展示&#xff1a;

对递归的一些理解。力扣206题:翻转链表

今天在刷力扣的时候&#xff0c;在写一道翻转链表的题目的过程中&#xff0c;在尝试使用递归解决该问题的时候&#xff0c;第一版代码却每次都返回的是null&#xff0c;这个错误让我尝试去debug了一下&#xff0c;最终找出了问题&#xff0c;并且让我对递归有了一些更深的理解&…

Windows下帆软BI(finebi)单机部署移植(Tomcat)攻略

一、基础环境 操作系统&#xff1a;Windows 10 64bit 帆软BI 版本&#xff1a;V9.0/V10.0 HTTP工具&#xff1a;Tomcat 外置数据库&#xff1a;Oracle 11g 实验内容&#xff1a;将已经部署好的帆软BI从一台电脑移植到另一台电脑 二、前期准备 1、做好外置数据库移植&…

STM32CUBEIDE FreeRTOS操作教程(一):LED闪灯

STM32CUBEIDE FreeRTOS操作教程&#xff08;一&#xff09;&#xff1a;LED闪灯 STM32CUBEIDE(不是STM32CUBEMX)开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件&#xff0c;不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F401RCT6开…

JCR一区级 | Matlab实现GA-Transformer-LSTM多变量回归预测

JCR一区级 | Matlab实现GA-Transformer-LSTM多变量回归预测 目录 JCR一区级 | Matlab实现GA-Transformer-LSTM多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【JCR一区级】Matlab实现GA-Transformer-LSTM多变量回归预测&#xff0c;遗传优化算法&#…

Vue3--

一、pinia &#xff08;集中式状态&#xff08;数据&#xff09;管理&#xff09; 1、准备一个效果 2、存储读取数据 3、修改数据三种方式 4、storeToRefs 5、getters 当state中的数据&#xff0c;需要经过处理后在使用时&#xff0c;可以使用getters配置 6、$subscribe的使用…

QT总结——图标显示坑

最近写代码遇到一个神仙大坑&#xff0c;我都怀疑我软件是不是坏了&#xff0c;这里记录一下。 写qt工程的时候我们一般会设置图标&#xff0c;这个图标是窗体的图标同时也是任务栏的图标&#xff0c;但是我发现生成的exe没有图标&#xff0c;这个时候就想着给他加一个图标&…

Linux(CentOS)的“应用商城” —— yum

Linux&#xff08;CentOS&#xff09;的“应用商城” —— yum 关于 yum 和软件包Linux 系统&#xff08;CentOS&#xff09;的生态yum 相关操作yum 本地配置yum 安装 lrzsz.x86_64 关于 yum 和软件包 首先 yum 是软件下载安装管理的客户端&#xff0c;类似各种手机里的“应用…

OpenAI发布GPT-4 Mini的深度分析及中国大模型的弯道超车机会

引言 在OpenAI封禁中国IP访问其API后&#xff0c;紧接着推出了GPT-4 Mini&#xff0c;这是一个引发广泛关注和讨论的新举措。此举不仅让人们质疑OpenAI的战略方向&#xff0c;更引发了对中国大模型是否能弯道超车的讨论。本文将详细分析GPT-4 Mini的特点、市场影响及中国大模型…

eclipse中的classbean导入外部class文件,clean项目后删除问题

最近被eclipse搞得头疼&#xff0c;下午终于解决 eclipse创建的java项目中&#xff0c;类的输出目录是classbean。由于项目需要&#xff0c;classbean目录下已经导入了外部的类&#xff0c;但每次clean项目时&#xff0c;会把class删掉。 广泛查询&#xff0c;eclipse不清空c…

jenkins删除历史构建记录

1、 登录jenkins&#xff0c;进入【Manage Jenkins】-【Script Console】&#xff0c;输入&#xff1a; def jobName "Test" //删除的项目名称 def maxNumber 60 // 保留的最小编号&#xff0c;意味着小于该编号的构建都将被删除 Jenkins.instance.getItemByFullN…

javascript鼠标跟随星星动画特效

鼠标跟随星星动画特效https://www.bootstrapmb.com/item/14781 创建一个鼠标跟随的星星动画特效在JavaScript中通常涉及到HTML、CSS和JavaScript的结合。以下是一个简单的步骤说明和示例代码&#xff0c;用于创建一个基本的鼠标跟随星星动画&#xff1a; HTML (index.html) ht…

从理论到实践:如何用 TDengine 打造完美数据模型​

在用 TDengine 进行数据建模之前&#xff0c;我们需要回答两个关键问题&#xff1a;建模的目标用户是谁&#xff1f;他们的具体需求是什么&#xff1f;在一个典型的时序数据管理方案中&#xff0c;数据采集和数据应用是两个主要环节。如下图所示&#xff1a; 对于数据采集工程师…

大数据-44 Redis 慢查询日志 监视器 慢查询测试学习

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

基于Java+SpringMvc+Vue技术的慈善捐赠平台设计与实现(源码+LW+部署讲解)

项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功以及课程答疑&#xff01; 软件开发环境及开发工具&#xff1a; 操作系统&#xff1a;Windows 10、Windows 7、Windows 8 开发语言&#xff1a;java 前端技术&#xff1a;JavaScript、VUE.j…

好玩新游:辛特堡传说中文免费下载,Dungeons of Hinterberg 游戏分享

在游戏中&#xff0c;你将扮演Luisa&#xff0c;一个被现实生活拖得疲惫不堪的法律实习生。她决定暂时远离快节奏的公司生活&#xff0c;踏上征服辛特堡地下城的旅程…她会在第一天就被击退&#xff0c;还是能成为顶级猎魔人呢&#xff1f;只有一个办法可以找到答案... 体验刺激…