【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初始化
    启动串口接收功能
    使能定时器
  }
  状态设置为使能
}

未完待续

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: STM32是一种微控制器系列,而FreeModbus是一个开源的Modbus通信协议库。当我们需要在STM32微控制器上实现Modbus通信时,我们可以将FreeModbus库移植到STM32平台上。 要移植FreeModbus库到STM32平台上,我们需要以下步骤: 1. 确定STM32的硬件资源:首先,我们需要确定STM32微控制器的型号和硬件配置以及通信接口,如串口、CAN总线等。 2. 下载FreeModbus库:我们需要从FreeModbus的官方网站或其他开源代码托管平台上下载最新的FreeModbus库。 3. 配置STM32开发环境:我们需要配置适合STM32平台的开发环境,如Keil MDK或者STM32CubeIDE。 4. 移植FreeModbus库:根据STM32平台的硬件资源和通信接口,我们需要将FreeModbus库中的相关函数和配置进行适当修改和调整。 5. 编写应用程序:使用FreeModbus库提供的函数和接口,我们可以编写应用程序,实现相关的Modbus通信功能。 6. 测试与调试:在移植和编写完成后,我们需要对代码进行测试和调试,确保Modbus通信功能的正常运行。 通过以上步骤,我们就可以将FreeModbus库成功移植到STM32平台上,实现Modbus通信功能。当然,在整个移植过程中,我们需要根据具体的硬件资源和应用需求进行适当的调整和修改,以确保移植的顺利进行并达到我们的目标。 ### 回答2: STM32是一款广泛应用于嵌入式系统开发的微控制器系列。而FreeModbus是一个免费开源的用于通信领域的Modbus协议栈。因此,移植FreeModbusSTM32上可以使STM32能够通过Modbus协议与其他设备进行通信。 对于STM32上的FreeModbus移植,首先需要下载FreeModbus开源代码,并将其添加到STM32开发环境中。然后,根据STM32的芯片型号和外设特性,进行必要的配置和适配工作。这些配置可能包括UART和GPIO引脚设置、中断优先级配置等。 接下来,需要根据具体情况编写驱动程序,以实现STM32Modbus通信相关的功能。这些功能可能涉及到串口通信、数据传输、报文解析等。 在移植过程中,需要特别关注时序和时钟配置,确保通信的稳定性和可靠性。同时,由于Modbus协议在不同设备间通信时需要配置不同的参数,如通信地址、寄存器地址等,需要根据具体需求进行设置。 移植完成后,可以使用STM32开发环境进行编译、烧录和调试。在调试过程中,可以使用串口调试工具等辅助工具来验证通信的正确性和稳定性。 总之,将FreeModbus移植到STM32上需要对两者进行适配和配置,并编写相应的驱动程序。通过这样的移植,可以使STM32具备Modbus通信功能,从而实现与其他设备的数据交换和通信。移植的过程需要细致入微的配置和调试,才能确保通信的稳定和可靠。 ### 回答3: STM32是STMicroelectronics推出的一款基于ARM Cortex-M系列内核的32位微控制器产品系列。FreeModbus是一个开源的Modbus通信协议栈,用于实现主从站的通信。将FreeModbus移植到STM32上,可以实现STM32与其他设备之间的Modbus通信。 首先,在STM32上移植FreeModbus需要将FreeModbus的源代码添加到STM32的工程中。首先,我们需要将FreeModbus的源文件包括进STM32的工程,并确保工程正确依赖了这些源文件。 其次,根据我们的需求,我们可以修改FreeModbus的配置文件来适配STM32的硬件资源和通信方式。例如,我们可以配置串口的引脚和波特率,以及设置Modbus的地址等参数。 然后,在STM32的主函数中初始化FreeModbus,并通过编写相关的回调函数来处理Modbus通信的事件。回调函数包括处理收到数据的事件、发送数据的事件和处理错误的事件等。我们需要根据具体的应用场景和需求,编写相应的回调函数。 最后,在主函数中通过调用FreeModbus的主函数来运行Modbus通信。这将使STM32成为一个Modbus从站,并能够进行与其他Modbus设备的通信。 综上所述,将FreeModbus移植到STM32上需要将FreeModbus的源代码添加到STM32的工程中,并根据需求修改配置文件和编写相应的回调函数。通过这些步骤,我们可以实现STM32与其他设备之间的Modbus通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值