首页 > 其他分享 >FreeModbus学习——eMBPoll轮询

FreeModbus学习——eMBPoll轮询

时间:2024-07-24 18:24:33浏览次数:14  
标签:EV MB 轮询 状态机 定时器 FreeModbus ucMBFrame 接收 eMBPoll

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轮询完成。

标签:EV,MB,轮询,状态机,定时器,FreeModbus,ucMBFrame,接收,eMBPoll
From: https://blog.csdn.net/rerrick_rose/article/details/140642478

相关文章

  • zabbix agent 日志文件轮询分析
    1、zabbixagent日志文件轮询分析的初衷zabbixagent的日志文件默认在/var/log/zabbix目录下面。默认/目录只有20G或者40G,随着运行时间越来越长日志文件也会变大,会占用磁盘空间 2、zabbixagent文件为什么会过大是由于加了一些自定义监控项,这些监控项在执行的时候会记录......
  • FreeRTOS 简单内核实现8 时间片轮询
    0、思考与回答0.1、思考一为什么要增加时间片轮询?目前的RTOS内核已经支持抢占优先级,即高优先级的任务会抢占低优先级的任务得到执行,但是对于同等优先级的任务,如果不支持时间片轮询,则只能有一个任务运行,并且由于优先级相同所以除延时阻塞到期外也不会发生任务调度,因此需要增加......
  • 使用Modbus转Profinet网关无需编写Modbus轮询程序,实现PLC和电表通信
    一、无需编写Modbus轮询程序实现PLC与电表通信的方法在工业自动化领域,PLC(可编程逻辑控制器)与电表之间的通信是非常常见的需求。传统上,为了让PLC与电表进行通信,通常需要编写Modbus轮询程序来实现数据的读取和控制。然而,近年来出现了一种新的方法,即通过使用Modbus转Profinet网关,可......
  • 基于启发式蝙蝠算法、粒子群算法、花轮询算法和布谷鸟搜索算法的换热器PI控制器优化(Ma
    ......
  • Modbus转Profinet网关不限制plc插槽modbus指令轮询
    通过Modbus转Profinet(XD-MDPN100)网关的应用,不仅可以实现Modbus设备与Profinet网络的平滑对接,还能有效解决PLC插槽限制和Modbus指令轮询等问题,Modbus转Profinet网关(XD-MDPN100)在解决PLC插槽限制以及Modbus指令轮询问题方面,具有显著的优势。以下是对其如何不限制PLC插槽Modbus指令......
  • TCP长连接/HTTP长连接/HTTP长(短)轮询
     TCP长连接/HTTP长连接/HTTP长轮询TCP长连接VSHTTP长连接TCP长连接和HTTP长连接是两个相关但概念上有所区别的技术。TCP长连接TCP(TransmissionControlProtocol)是互联网传输层的一个面向连接的协议,它提供可靠的数据传输服务。在TCP连接中,长连接是指客户端和服务器建立连......
  • stm32f103c8t6的freemodbus移植
    注意:demo.c不要加入到程序中来。1在main.h文件中加入#include"stm32f1xx_hal.h"文件也可以不加a:每次重新生成程序时在主程序main.c中注释掉//MX_USART2_UART_Init();函数,因为在freemodbus中已经调用了该函......
  • 2024新版彩虹易支付系统源码/USDT源码/当面付/通道轮询/44支付插件/免签约支付系统
    ❖ 演示站点                                                                         ☰前台演示:  https://pa......
  • 基于STM32的ModBus实现(二)移植FreeMODBUS TCP
    一、ModBusTCPModbusTCP是一种基于TCP/IP协议的Modbus通信协议的变种。它允许Modbus协议在以太网上进行通信,提供了一种简单而有效的方式来连接不同类型的设备,如传感器、执行器、PLC等。ModbusTCP使用标准的TCP/IP协议栈,因此可以在现有的以太网基础设施上运行,而无需额外的硬......
  • 基于STM32的ModBus实现(一)移植FreeMODBUS RTU
    一、FreeMODBUSFreeModbus是一个开源的Modbus通信协议栈实现。它允许开发者在各种平台上轻松地实现Modbus通信功能,包括串口和以太网。FreeMODBUS提供了用于从设备和主站通信的功能,支持ModbusRTU和ModbusTCP协议。在工业控制和自动化领域广泛应用。FreeModBus可通过官......