FreeModbus源码详解

本篇按照FreeModbus协议栈的工作流程,对源代码进行总结解析;FreeModbus协议栈作为从机,等待主机传送的数据,当从机接收到一帧完整的报文后,对报文进行解析,然后响应主机,发送报文给主机,实现主机和从机之间的通信;

1:demo.c中三个函数,完成协议栈的准备工作;

eMBInit()函数:(mb.c)

/*函数功能:
*1:实现RTU模式和ASCALL模式的协议栈初始化;
*2:完成协议栈核心函数指针的赋值,包括Modbus协议栈的使能和禁止、报文的接收和响应、3.5T定时器中断回调函数、串口发送和接收中断回调函数;
*3:eMBRTUInit完成RTU模式下串口和3.5T定时器的初始化,需用户自己移植;
*4:设置Modbus协议栈的模式eMBCurrentMode为MB_RTU,设置Modbus协议栈状态eMBState为STATE_DISABLED;
*/
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;      /*使能modbus协议栈*/
            pvMBFrameStopCur = eMBRTUStop;        /*禁用modbus协议栈*/
            peMBFrameSendCur = eMBRTUSend;        /*modbus从机响应函数*/
            peMBFrameReceiveCur = eMBRTUReceive;  /*modbus报文接收函数*/
            pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
            //接收状态机
            pxMBFrameCBByteReceived =     xMBRTUReceiveFSM;   /*串口接收中断最终调用此函数接收数据*/
            //发送状态机
            pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;  /*串口发送中断最终调用此函数发送数据*/
            //报文到达间隔检查
            pxMBPortCBTimerExpired =      xMBRTUTimerT35Expired; /*定时器中断函数最终调用次函数完成定时器中断*/
            //初始化RTU
            eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
            break;
#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;
        }

        //
        if( eStatus == MB_ENOERR )
        {
            if( !xMBPortEventInit() )
            {
                /* port dependent event module initalization failed. */
                eStatus = MB_EPORTERR;
            }
            else
            {
                //设定当前状态
                eMBCurrentMode = eMode;       //设定RTU模式
                eMBState = STATE_DISABLED;    //modbus协议栈初始化状态,在此初始化为禁止
            }
        }
    }
    return eStatus;
}
eMBEnable()函数:(mb.c)

/*函数功能
*1:设置Modbus协议栈工作状态eMBState为STATE_ENABLED;
*2:调用pvMBFrameStartCur()函数激活协议栈
*/
eMBErrorCode
eMBEnable( void )
{
    eMBErrorCode    eStatus = MB_ENOERR;

    if( eMBState == STATE_DISABLED )
    {
        /* Activate the protocol stack. */
        pvMBFrameStartCur(  );  /*pvMBFrameStartCur = eMBRTUStart;调用eMBRTUStart函数*/          
        eMBState = STATE_ENABLED;
    }
    else
    {
        eStatus = MB_EILLSTATE;
    }
    return eStatus;
}
eMBRTUStart()函数:(mbrtu.c)

/*函数功能
*1:设置接收状态机eRcvState为STATE_RX_INIT;
*2:使能串口接收,禁止串口发送,作为从机,等待主机传送的数据;
*3:开启定时器,3.5T时间后定时器发生第一次中断,此时eRcvState为STATE_RX_INIT,上报初始化完成事件,然后设置eRcvState为空闲STATE_RX_IDLE;
*4:每次进入3.5T定时器中断,定时器被禁止,等待串口有字节接收后,才使能定时器;
*/
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( );
}
eMBPoll()函数:(mb.c)

/*函数功能:
*1:检查协议栈状态是否使能,eMBState初值为STATE_NOT_INITIALIZED,在eMBInit()函数中被赋值为STATE_DISABLED,在eMBEnable函数中被赋值为STATE_ENABLE;
*2:轮询EV_FRAME_RECEIVED事件发生,若EV_FRAME_RECEIVED事件发生,接收一帧报文数据,上报EV_EXECUTE事件,解析一帧报文,响应(发送)一帧数据给主机;
*/
eMBErrorCode
eMBPoll( void )
{
    static UCHAR   *ucMBFrame;           //接收和发送报文数据缓存区
    static UCHAR    ucRcvAddress;        //modbus从机地址
    static UCHAR    ucFunctionCode;      //功能码
    static USHORT   usLength;            //报文长度
    static eMBException eException;      //错误码响应枚举

    int             i;
    eMBErrorCode    eStatus = MB_ENOERR;         //modbus协议栈错误码
    eMBEventType    eEvent;                      //事件标志枚举

    /* Check if the protocol stack is ready. */
    if( eMBState != STATE_ENABLED )              //检查协议栈是否使能
    {
        return MB_EILLSTATE;                     //协议栈未使能,返回协议栈无效错误码
    }

    /* Check if there is a event av
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值