基於RT-Thread移植FreeModbus

平臺:正點原子STM32F407探索者開發板 + FreeModbus V1.6 + RT-Thread函數

源碼連接:https://www.embedded-solutions.at/en/freemodbus-downloads/學習

源碼列表如圖所示,須要的文件包括modbus文件夾和demo文件夾內的port相關文件,port文件位置以下圖ui

在BASE文件夾內有一個port文件夾(內含須要的port相關文件)和一個demo文件,demo文件寫好了FreeModbus的啓動使用。spa

將這些文件載入到工程中,幷包含相關的頭文件線程

因爲第一次移植,沒敢亂動,直接所有移植進來只開啓了須要的功能。mb開頭的文件爲協議棧程序,暫時沒必要改動;port開頭文件是須要用戶進行相關配置的文件。其中 portevent.c 不用動,portserial.c 和 porttimer.c 內部實現串口功能和定時器功能,包括初始化配置以及啓動和關閉。3d

第一步:配置portserial.ccode

  源碼文件中portserial.c包含下面幾個函數,大致功能如註釋所述。blog

 1 void
 2 vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )//能夠根據輸入參數配置RS485收發器的收發模式
 3 {
 4     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
 5      * transmitter empty interrupts.
 6      */
7 } 8 9 BOOL 10 xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) 11 {
    //初始化串口 --> 查找串口設備,根據參數配置串口,打開串口設備,設置串口接收回調函數等
12 return FALSE;//添加代碼後須要修改成 TRUE 13 } 14 15 BOOL 16 xMBPortSerialPutByte( CHAR ucByte ) 17 { 18 /* Put a byte in the UARTs transmit buffer. This function is called 19 * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been 20 * called. */
    //發送一個字節數據,只須要調用發送接口便可
21 return TRUE; 22 } 23 24 BOOL 25 xMBPortSerialGetByte( CHAR * pucByte ) 26 { 27 /* Return the byte in the UARTs receive buffer. This function is called 28 * by the protocol stack after pxMBFrameCBByteReceived( ) has been called. 29 */
    //接收一個字節數據
30 return TRUE; 31 } 32 33 /* Create an interrupt handler for the transmit buffer empty interrupt 34 * (or an equivalent) for your target processor. This function should then 35 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that 36 * a new character can be sent. The protocol stack will then call 37 * xMBPortSerialPutByte( ) to send the character. 38 */ 39 static void prvvUARTTxReadyISR( void ) 40 {
    //協議棧的發送中斷函數,能夠在串口發送中斷裏面調用它
41 pxMBFrameCBTransmitterEmpty( ); 42 } 43 44 /* Create an interrupt handler for the receive interrupt for your target 45 * processor. This function should then call pxMBFrameCBByteReceived( ). The 46 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the 47 * character. 48 */ 49 static void prvvUARTRxISR( void ) 50 {
    //協議棧的接收中斷函數,能夠在串口接收中斷裏面調用它;放在回調函數便可
51 pxMBFrameCBByteReceived( ); 52 }

第二步:配置porttimer.c接口

  源碼文件與串口的形式相似,具體以下開發

 1 BOOL
 2 xMBPortTimersInit( USHORT usTim1Timerout50us )//定時器設備初始化,查找設備,打開設備,配置設備,根據參數設置超時時間
 3 {
 4     return FALSE;//添加代碼後須要改成 TRUE
 5 }
 6 
 7 
 8 inline void
 9 vMBPortTimersEnable(  )//此處理解爲定時器的啓動,調用該接口即開始定時
10 {
11     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
12 }
13 
14 inline void
15 vMBPortTimersDisable(  )//定時器的關閉,我我的使用的單次定時,因此就沒作處理。若是是循環的須要關閉定時器
16 {
17     /* Disable any pending timers. */
18 }
19 
20 static void prvvTIMERExpiredISR( void )//超時函數,能夠放到定時器超時回調函數中調用
21 {
22     ( void )pxMBPortCBTimerExpired(  );
23 }

第三步:配置demo.c文件

  該文件下有有一個main函數,其它函數爲不一樣功能的回調函數。官方下載的源碼中main函數和eMBRegInputCB已經實現,能夠參考使用。

 1 int
 2 main( void )
 3 {
 4     const UCHAR     ucSlaveID[] = { 0xAA, 0xBB, 0xCC };
 5     eMBErrorCode    eStatus;
 6 
 7     eStatus = eMBInit( MB_RTU, 0x0A, 0, 38400, MB_PAR_EVEN );
 8 
 9     eStatus = eMBSetSlaveID( 0x34, TRUE, ucSlaveID, 3 );
10     sei(  );
11 
12     /* Enable the Modbus Protocol Stack. */
13     eStatus = eMBEnable(  );
14 
15     for( ;; )
16     {
17         ( void )eMBPoll(  );
18 
19         /* Here we simply count the number of poll cycles. */
20         usRegInputBuf[0]++;
21     }
22 }

  main函數內容實現的是協議棧的初始化、啓動和循環更新,重要的三個函數爲eMBInit、eMBEnable、eMBPoll。官方源碼中做爲一個功能循環使用,在RT-Thread中我把其做爲一個獨立任務,在任務函數裏進行協議棧初始化和啓動,狀態更新做爲線程循環。

 1 eMBErrorCode
 2 eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
 3 {
 4     eMBErrorCode    eStatus = MB_ENOERR;
 5     int             iRegIndex;
 6 
 7     if( ( usAddress >= REG_INPUT_START )
 8         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
 9     {
10         iRegIndex = ( int )( usAddress - usRegInputStart );
11         while( usNRegs > 0 )
12         {
13             *pucRegBuffer++ =
14                 ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
15             *pucRegBuffer++ =
16                 ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
17             iRegIndex++;
18             usNRegs--;
19         }
20     }
21     else
22     {
23         eStatus = MB_ENOREG;
24     }
25 
26     return eStatus;
27 }
28 
29 eMBErrorCode
30 eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
31                  eMBRegisterMode eMode )
32 {
33     return MB_ENOREG;
34 }
35 
36 
37 eMBErrorCode
38 eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
39                eMBRegisterMode eMode )
40 {
41     return MB_ENOREG;
42 }
43 
44 eMBErrorCode
45 eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
46 {
47     return MB_ENOREG;
48 }

  這些函數是協議棧對應功能的回調函數,而且給了一個示例,它們由function文件下的函數調用,只需在須要的功能裏做出對應實現便可。這些函數的返回值是特定的形式,參考示例函數進行操做便可,至於相應地址數據的處理根據實際需求。

 

最後:

  新手上路,還有不少地方理解不到位,暫時記錄這麼多,繼續學習!

相關文章
相關標籤/搜索