【STM32】Freemodbus流程解析函数解析详细

 此篇博客将按照Freemodbus的运行流程,对各个函数进行解析(无主机RTU模式),

我将尽我所能解释的尽量清楚,如有错误或者语义模糊处还请在评论区指出,谢谢。

运行流程:freemodbus流程解析(原创)【百度文库】

1、eMBInit(…)

首先我们来看mb.h里的说明注释

eMBErrorCode   
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );

/* ----------------------- 函数原型------------------------------*/

  • \简要说明:初始化modbus协议栈

  • 该函数初始化ASCII或RTU模块,

  • 并调用porting layer的init函数来配置硬件部分。

  • 请注意,直到eMBEnable()被调用之前,

  • Receiver一直是禁用的,没有Modbus帧被处理。

  • \参数1:eMode      选择 ASCII or RTU 模式.

  • \参数2:ucSlaveAddress  从机地址

  • \参数3:ucPort       端口。例如windows上的COM1。这个值跟平台有关系,一些端口干脆忽略它。(我也忽略了,直接填0)

  • \参数4:ulBaudRate     波特率

  • \参数5:eParity       校验方式

  • \返回值:没错返回 MB_ENOERR.

  • 没错然后,该协议处于禁用状态,并准备通过调用eMBEnable()激活。

  • Otherwise one of the following error codes

  • is returned:

    • eMBErrorCode::MB_EINVAL 从机地址无效,有效的地址范围1 - 247
    • eMBErrorCode::MB_EPORTERR porting layer返回错误

小结:从上面可以看出eMBInit(…)函数就是做一些初始化的

eMBErrorCode点击跳转定义
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{
eMBErrorCode eStatus = MB_ENOERR;
if( ( ucSlaveAddress = = MB_ADDRESS_BROADCAST ) ||
( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) )
{
eStatus = MB_EINVAL;
}
else
{
ucMBAddress = ucSlaveAddress;首先判断从机地址对不对
switch ( eMode )
{这里给函数指针赋值 ,根据不同的帧格式来执行不同的操作
#if MB_RTU_ENABLED > 0
case MB_RTU:点击跳转函数指针定义
pvMBFrameStartCur = eMBRTUStart;
pvMBFrameStopCur = eMBRTUStop;
peMBFrameSendCur = eMBRTUSend;
peMBFrameReceiveCur = eMBRTUReceive;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
点击跳转eMBRTUInit函数
#endif
#if MB_ASCII_ENABLED > 0
case MB_ASCII:
pvMBFrameStartCur = eMBASCIIStart;
pvMBFrameStopCur = eMBASCIIStop;
peMBFrameSendCur = eMBASCIISend;
peMBFrameReceiveCur = eMBASCIIReceive;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
#endif
default:
eStatus = MB_EINVAL;
}
/* port dependent event module initalization failed. */
if( eStatus == MB_ENOERR ) 如果前面的初始化没错,进行接下来的任务
{
if( !xMBPortEventInit( ) ) 注意,这里是!点击跳转xMBPortEventInit函数
{
eStatus = MB_EPORTERR; 端口事件模块初始化失败。
}
else
{
eMBCurrentMode = eMode;
eMBState = STATE_DISABLED;一切正常就会来到这里
}
}
}
return eStatus;
}

1.1 定义函数返回值类型eMBErrorCode

/*! \ingroup modbus
 * \brief Errorcodes used by all function in the protocol stack.
 */
typedef enum
{
    MB_ENOERR,                  /*!< no error. */
    MB_ENOREG,                  /*!< illegal register address. */
    MB_EINVAL,                  /*!< illegal argument. */
    MB_EPORTERR,                /*!< porting layer error. */
    MB_ENORES,                  /*!< insufficient resources. */
    MB_EIO,                     /*!< I/O error. */
    MB_EILLSTATE,               /*!< protocol stack in illegal state. */
    MB_ETIMEDOUT                /*!< timeout error occurred. */
} eMBErrorCode;

1.2 函数指针的定义

//eMBInit( )要初始化的函数指针. 根据模式(RTU or ASCII)来赋予不同的函数地址 定义在里面
 
static peMBFrameSend peMBFrameSendCur;
static pvMBFrameStart pvMBFrameStartCur;
static pvMBFrameStop pvMBFrameStopCur;
static peMBFrameReceive peMBFrameReceiveCur;
static pvMBFrameClose pvMBFrameCloseCur;

/* Callback functions required by the porting layer. They are called when
 * an external event has happend which includes a timeout or the reception
 * or transmission of a character.
 */
BOOL( *pxMBFrameCBByteReceived ) ( void );//函数指针
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );//函数指针
BOOL( *pxMBPortCBTimerExpired ) ( void );//函数指针

BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );//函数指针
BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );//函数指针

/*********************************mbframe.h*************************************/
//定义了函数指针
typedef void    ( *pvMBFrameStart ) ( void );

typedef void    ( *pvMBFrameStop ) ( void );

typedef eMBErrorCode( *peMBFrameReceive ) ( UCHAR * pucRcvAddress,
                                            UCHAR ** pucFrame,
                                            USHORT * pusLength );

typedef eMBErrorCode( *peMBFrameSend ) ( UCHAR slaveAddress,
                                         const UCHAR * pucFrame,
                                         USHORT usLength );

typedef void( *pvMBFrameClose ) ( void );

函数指针详情参考【】

1.3 eMBRTUInit(…)函数

在mbrtu.c中。此函数完成的时对于串口和传输数据要用的定时器的初始化,同时这下面调用的这两个函数也是在移植Freemodbus协议到不同的板子的过程中必须要进行修改的部分。

/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    ULONG           usTimerT35_50us;

    ( void )ucSlaveAddress;
    ENTER_CRITICAL_SECTION(  );

    /* Modbus RTU uses 8 Databits. */
    if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
    {
        eStatus = MB_EPORTERR;
    }
    else
    {
        /* If baudrate > 19200 then we should use the fixed timer values
         * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
         */
        if( ulBaudRate > 19200 )
        {
            usTimerT35_50us = 35;       /* 1800us. */
        }
        else
        {
            /* The timer reload value for a character is given by:
             *
             * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
             *             = 11 * Ticks_per_1s / Baudrate
             *             = 220000 / Baudrate
             * The reload for t3.5 is 1.5 times this value and similary
             * for t3.5.
             */
            usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
        }
        if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
        {
            eStatus = MB_EPORTERR;
        }
    }
    EXIT_CRITICAL_SECTION(  );

    return eStatus;
}

1.3.1 xMBPortSerialInit(…)

1.3.1 xMBPortTimersInit(…)

这关这两个函数的详细介绍请看【】
关于modbus协议数据传输间隔3.5T的详细解释请看【】

1.4 xMBPortEventInit( )函数

BOOL
xMBPortEventInit( void )
{
    xEventInQueue = FALSE;
    return TRUE;
}

1.5 小结

做为在main()调用的第一个初始化函数,具体功能可总结为如下

eMBInit(RTU,从机地址,端口,波特率,校验方式)
{
  验证从机地址是否正确
  设置RTU模式并对函数指针进行映射
  调用eMBRTUInit( 从机地址, 端口, 波特率, 校验)
  {
     初始化串口xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity )
     初始化定时器xMBPortTimersInit( ( USHORT ) usTimerT35_50us )
  }
  初始化事件函数xMBPortEventInit( )
}


2. eMBEnable()

首先我们来看mb.h里的说明注释

eMBErrorCode    eMBEnable( void );
  • 简要说明:使能Modbus协议栈.
  • 此函数启动处理消息帧
  • 只有协议栈在disabled状态下才可以enable
  • 返回值:如果协议栈现在处于enabled状态,则返回 MB_ENOERR.
  •     如果不在 disabled state 则返回 MB_EILLSTATE.
    */

eMBErrorCode
eMBEnable( void )
{
    eMBErrorCode    eStatus = MB_ENOERR;

    if( eMBState == STATE_DISABLED ) //先前一定要是 Disbaled状态
    {
        /* Activate the protocol stack. */
        pvMBFrameStartCur(  );//  pvMBFrameStartCur = eMBRTUStart;函数指针 ,不太懂
        eMBState = STATE_ENABLED;
    }
    else
    {
        eStatus = MB_EILLSTATE;
    }
    return eStatus;
}

函数指针赋值过了,直接调用

2.1 eMBRTUStart()函数

void
eMBRTUStart( void )
{
    ENTER_CRITICAL_SECTION(  );
    /* Initially the receiver is in the state STATE_RX_INIT. we start
     * the timer and if no character is received within t3.5 we change
     * to STATE_RX_IDLE. This makes sure that we delay startup of the
     * modbus protocol stack until the bus is free.
     */
    eRcvState = STATE_RX_INIT;
    vMBPortSerialEnable( TRUE, FALSE );
    vMBPortTimersEnable(  );

    EXIT_CRITICAL_SECTION(  );
}

2.1.1 vMBPortSerialEnable

详情请看【】

2.1.2 vMBPortTimersEnable( );

详情请看【】

2.2 小结

eMBErrorCode
eMBEnable( void )
{

  判断状态为进制,则调用eMBRTUStart()
  {
    状态设为RX初始化
    启动串口接收功能
    使能定时器
  }
  状态设置为使能
}

未完待续

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页