FreeModbus--完全分析

更新时间:2023-11-09 21:09:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

FreeModbus--完全分析

说明:freemodbus-v1.5.0

主流程

[objc] view plaincopy

1. /* ----------------------- Start implementation -----------------------------*/ 2. int

3. main( void ) 4. {

5. eMBErrorCode eStatus; 6.

7. eStatus = eMBInit( MB_RTU, 0x0A, 0, 38400, MB_PAR_EVEN ); 8.

9. /* Enable the Modbus Protocol Stack. */ 10. eStatus = eMBEnable( ); 11.

12. for( ;; ) 13. {

14. ( void )eMBPoll( ); 15.

16. /* Here we simply count the number of poll cycles. */ 17. usRegInputBuf[0]++; 18. } 19. }

由上述主函数可知协议栈经eMBInit和eMBEnable初始化、使能后进入协议栈的循环eMBPoll中。

eMBInit分析

首先,使用eMBInit初始化协议栈,根据你使用的参数eMBMode eMode初始化相应的函数入口!

[objc] view plaincopy

1. #if MB_RTU_ENABLED > 0 2. case MB_RTU:

3. pvMBFrameStartCur = eMBRTUStart; 4. pvMBFrameStopCur = eMBRTUStop; 5. peMBFrameSendCur = eMBRTUSend; 6. peMBFrameReceiveCur = eMBRTUReceive;

7. pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL; 8. pxMBFrameCBByteReceived = xMBRTUReceiveFSM; 9. pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM; 10. pxMBPortCBTimerExpired = xMBRTUTimerT35Expired; 11.

12. eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity )

;

13. break; 14. #endif

15. #if MB_ASCII_ENABLED > 0 16. case MB_ASCII:

17. pvMBFrameStartCur = eMBASCIIStart; 18. pvMBFrameStopCur = eMBASCIIStop; 19. peMBFrameSendCur = eMBASCIISend; 20. peMBFrameReceiveCur = eMBASCIIReceive;

21. pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL; 22. pxMBFrameCBByteReceived = xMBASCIIReceiveFSM; 23. pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM; 24. pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired; 25.

26. eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity

);

27. break; 28. #endif

以上代码中pvMBFrameStartCur、pvMBFrameStopCur等即协议栈函数的接口,对于不同模式使用不同的函数进行赋值初始化!!此编写模式可以借鉴学习!!

其中eMBRTUInit函数对底层驱动(串口和定时器)进行了初始化。 在上述初始化完成并且成功后对事件功能也进了初始化,最后全局变量eMBState = STATE_DISABLED。 eMBEnable的分析

[objc] view plaincopy 1. eMBErrorCode 2. eMBEnable( void ) 3. {

4. eMBErrorCode eStatus = MB_ENOERR; 5.

6. if( eMBState == STATE_DISABLED ) 7. {

8. /* Activate the protocol stack. */ 9. pvMBFrameStartCur( ); 10. eMBState = STATE_ENABLED; 11. } 12. else 13. {

14. eStatus = MB_EILLSTATE; 15. }

16. return eStatus; 17. }

由第一节的分析,此时将启动协议栈pvMBFrameStartCur,查看程序该函数指针被分配到为eMBRTUStart。

该函数中将全局变量eRcvState = STATE_RX_INIT,并使能串口和定时器,注意此时的定时开始工作!!! 全局变量eMBState =STATE_ENABLED。

eMBPoll的分析

在此循环函数中xMBPortEventGet(&eEvent ) == TRUE先判断是否有事件,无事件发生则不进入状态机!

还记得第二节定时器开始工作了吗?我们先看看该定时器如果超时了会发生什么事件! 在超时中断中我们将会调用pxMBPortCBTimerExpired函数,其中有以下代码:

[objc] view plaincopy

1. BOOL

2. xMBRTUTimerT35Expired( void ) 3. {

4. BOOL xNeedPoll = FALSE; 5.

6. switch ( eRcvState ) 7. {

8. /* Timer t35 expired. Startup phase is finished. */ 9. case STATE_RX_INIT:

10. xNeedPoll = xMBPortEventPost( EV_READY ); 11. break; 12.

13. /* A frame was received and t35 expired. Notify the listener that 14. * a new frame was received. */ 15. case STATE_RX_RCV:

16. xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED ); 17. break; 18.

19. /* An error occured while receiving the frame. */ 20. case STATE_RX_ERROR: 21. break; 22.

23. /* Function called in an illegal state. */ 24. default:

25. assert( ( eRcvState == STATE_RX_INIT ) ||

26. ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERR

OR ) ); 27. } 28.

29. vMBPortTimersDisable( ); 30. eRcvState = STATE_RX_IDLE; 31.

32. return xNeedPoll; 33. }

上一节分析中全局变量eRcvState =STATE_RX_INIT,因此第二节所说的定时器第一次超时将会发送xNeedPoll =xMBPortEventPost( EV_READY )事件,

然后关闭定时器,全局变量eRcvState =STATE_RX_IDLE。此时,在主循环eMBPoll中将会执行一次EV_READY下的操作,

之后会一直执行eMBPoll,整个协议栈开始运行! 接收数据分析

由于FreeModbus只支持从机模式,因此我们分析一下其在接收到数据后的操作!!! 接收数据

在上三节的操作中,我们可以知道进入eMBPoll循环后,串口中断是开启的。因此在接收到数据的时候,首先响应的应该是串口中断程序。 接收中断中将会调用接收状态机:

[objc] view plaincopy

1. BOOL

2. xMBRTUReceiveFSM( void ) 3. {

4. BOOL xTaskNeedSwitch = FALSE; 5. UCHAR ucByte; 6.

7. assert( eSndState == STATE_TX_IDLE ); 8.

9. /* Always read the character. */

10. ( void )xMBPortSerialGetByte( ( CHARCHAR * ) & ucByte ); 11.

12. switch ( eRcvState ) 13. {

14. /* If we have received a character in the init state we have to 15. * wait until the frame is finished. 16. */

17. case STATE_RX_INIT:

18. vMBPortTimersEnable( ); 19. break; 20.

21. /* In the error state we wait until all characters in the 22. * damaged frame are transmitted. 23. */

24. case STATE_RX_ERROR:

25. vMBPortTimersEnable( ); 26. break; 27.

28. /* In the idle state we wait for a new character. If a character 29. * is received the t1.5 and t3.5 timers are started and the 30. * receiver is in the state STATE_RX_RECEIVCE. 31. */

32. case STATE_RX_IDLE: 33. usRcvBufferPos = 0;

34. ucRTUBuf[usRcvBufferPos++] = ucByte; 35. eRcvState = STATE_RX_RCV; 36.

37. /* Enable t3.5 timers. */ 38. vMBPortTimersEnable( ); 39. break; 40.

41. /* We are currently receiving a frame. Reset the timer after 42. * every character received. If more than the maximum possible 43. * number of bytes in a modbus frame is received the frame is 44. * ignored.

本文来源:https://www.bwwdw.com/article/vl9v.html

Top