Freemodbus完全分析

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

FreeModbus完全分析作者:rianboe版本:freemodbus-v1.5.0时间:2013年11月19日1eMBInit的分析intmain(void){eMBErrorCodeeStatus;eStatus=eMBInit(MB_RTU,0x0A,0,38400,MB_PAR_EVEN);/*EnabletheModbusProtocolStack.*/eStatus=eMBEnable();for(;;){(void)eMBPoll();/*Herewesimplycountthenumberofpollcycles.*/usRegInputBuf[0]++;}}首先,使用eMBInit初始化协议栈,根据你使用的eMBModeeMode初始化相应的函数入口!#ifMB_RTU_ENABLED0caseMB_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;#endif以上代码中pvMBFrameStartCur、pvMBFrameStopCur等即协议栈函数的接口,对于不同模式使用不同的函数进行赋值初始化!!此编写模式可以借鉴学习!!上述eMBRTUInit函数对底层驱动(串口和定时器)进行了初始化。之后在上述初始化完成并且成功后对事件也进了初始化,完成后全局变量eMBState=STATE_DISABLED。2eMBEnable的分析eMBErrorCodeeMBEnable(void){eMBErrorCodeeStatus=MB_ENOERR;if(eMBState==STATE_DISABLED){/*Activatetheprotocolstack.*/pvMBFrameStartCur();eMBState=STATE_ENABLED;}else{eStatus=MB_EILLSTATE;}returneStatus;}由第一节的分析,此时将启动协议栈pvMBFrameStartCur,查看程序该函数指针被分配到为eMBRTUStart。全局变量eRcvState=STATE_RX_INIT,并使能串口和定时器,注意此时的定时开始工作!!!全局变量eMBState=STATE_ENABLED。3eMBPoll的分析在此循环函数中xMBPortEventGet(&eEvent)==TRUE先判断是否有事件,无事件发生则不进入状态机!还记得第二节定时器开始工作了吗?我们先看看该定时器如果超时了会发生什么事件!在超时中断中我们将会调用pxMBPortCBTimerExpired函数,其中有以下代码:switch(eRcvState){/*Timert35expired.Startupphaseisfinished.*/caseSTATE_RX_INIT:xNeedPoll=xMBPortEventPost(EV_READY);break;/*Aframewasreceivedandt35expired.Notifythelistenerthat*anewframewasreceived.*/caseSTATE_RX_RCV:xNeedPoll=xMBPortEventPost(EV_FRAME_RECEIVED);break;/*Anerroroccuredwhilereceivingtheframe.*/caseSTATE_RX_ERROR:break;/*Functioncalledinanillegalstate.*/default:assert((eRcvState==STATE_RX_INIT)||(eRcvState==STATE_RX_RCV)||(eRcvState==STATE_RX_ERROR));}上一节分析中全局变量eRcvState=STATE_RX_INIT,因此第二节所说的定时器第一次超时将会发送xNeedPoll=xMBPortEventPost(EV_READY)事件,然后关闭定时器,全局变量eRcvState=STATE_RX_IDLE。此时,在主循环eMBPoll中将会执行一次EV_READY下的操作,之后会一直执行eMBPoll,整个协议栈开始运行!4接收数据分析由于FreeModbus只支持从机模式,因此我们分析一下其在接收到数据后的操作!!!4.1接收数据在上三节的操作中,我们可以知道进入eMBPoll循环后,串口中断是开启的。因此在接收到数据的时候,首先响应的应该是串口中断程序。接收中断中将会调用接收状态机:BOOLxMBRTUReceiveFSM(void){BOOLxTaskNeedSwitch=FALSE;UCHARucByte;assert(eSndState==STATE_TX_IDLE);/*Alwaysreadthecharacter.*/(void)xMBPortSerialGetByte((CHAR*)&ucByte);switch(eRcvState){/*Ifwehavereceivedacharacterintheinitstatewehaveto*waituntiltheframeisfinished.*/caseSTATE_RX_INIT:vMBPortTimersEnable();break;/*Intheerrorstatewewaituntilallcharactersinthe*damagedframearetransmitted.*/caseSTATE_RX_ERROR:vMBPortTimersEnable();break;/*Intheidlestatewewaitforanewcharacter.Ifacharacter*isreceivedthet1.5andt3.5timersarestartedandthe*receiverisinthestateSTATE_RX_RECEIVCE.*/caseSTATE_RX_IDLE:usRcvBufferPos=0;ucRTUBuf[usRcvBufferPos++]=ucByte;eRcvState=STATE_RX_RCV;/*Enablet3.5timers.*/vMBPortTimersEnable();break;/*Wearecurrentlyreceivingaframe.Resetthetimerafter*everycharacterreceived.Ifmorethanthemaximumpossible*numberofbytesinamodbusframeisreceivedtheframeis*ignored.*/caseSTATE_RX_RCV:if(usRcvBufferPosMB_SER_PDU_SIZE_MAX){ucRTUBuf[usRcvBufferPos++]=ucByte;}else{eRcvState=STATE_RX_ERROR;}vMBPortTimersEnable();break;}returnxTaskNeedSwitch;}经过第3节的分析,此时全局变量eRcvState=STATE_RX_IDLE。接收状态机开始后,读取UART串口缓存中的数据,并进入STATE_RX_IDLE分支中存储一次数据后开启超时定时器,进入STATE_RX_RCV分支继续接收后续的数据,直至定时器超时!为什么要等待超时才能停止接收呢!caseSTATE_RX_RCV:xNeedPoll=xMBPortEventPost(EV_FRAME_RECEIVED);break;可以发现接收数据时发生超时后,协议栈会发送EV_FRAME_RECEIVED接收完成这个信号。此时eMBPoll接收到此信号后会调用eMBRTUReceive函数。eMBErrorCodeeMBRTUReceive(UCHAR*pucRcvAddress,UCHAR**pucFrame,USHORT*pusLength){BOOLxFrameReceived=FALSE;eMBErrorCodeeStatus=MB_ENOERR;ENTER_CRITICAL_SECTION();assert(usRcvBufferPosMB_SER_PDU_SIZE_MAX);/*LengthandCRCcheck*/if((usRcvBufferPos=MB_SER_PDU_SIZE_MIN)&&(usMBCRC16((UCHAR*)ucRTUBuf,usRcvBufferPos)==0)){/*Savetheaddressfield.Allframesarepassedtotheupperlayed*andthedecisionifaframeisusedisdonethere.*/*pucRcvAddress=ucRTUBuf[MB_SER_PDU_ADDR_OFF];/*TotallengthofModbus-PDUisModbus-Serial-Line-PDUminus*sizeofaddressfieldandCRCchecksum.*/*pusLength=(USHORT)(usRcvBufferPos-MB_SER_PDU_PDU_OFF-MB_SER_PDU_SIZE_CRC);/*ReturnthestartoftheModbusPDUtothecaller.*/*pucFrame=(UCHAR*)&ucRTUBuf[MB_SER_PDU_PDU_OFF];xFrameReceived=TRUE;}else{eStatus=MB_EIO;}EXIT_CRITICAL_SECTION();returneStatus;}eMBRTUReceive函数完成了CRC校验、帧数据地址、长度的赋值,便于给上层进行处理!之后发送(void)xMBPortEventPost(EV_EXECUTE)事件。4.2数据的处理caseEV_EXECUTE:ucFunctionCode=ucMBFrame[MB_PDU_FUNC_OFF];eException=MB_EX_ILLEGAL_FUNCTION;for(i=0;iMB_FUNC_HANDLERS_MAX;i++){/*Nomorefunctionhandlersregistered.Abort.*/if(xFuncHandlers[i].ucFunctionCode==0){break;}elseif(xFuncHandlers[i].ucFunctionCode==ucFunctionCode){eException=xFuncHandlers[i].pxHandler(ucMBFrame,&usLength);break;}}/*Iftherequestwasnotsenttothebroadcastaddresswe*returnareply.*/if(ucRcvAddress!=MB_ADDRESS_BROADCAST){if(eException!=MB_EX_NONE){/*Anexceptionoccured.Buildanerrorframe.*/usLength=0;ucMBFrame[usLength

1 / 5
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功