Porting FreeModbus based on RT-Thread

Posted by 4evernomad on Fri, 21 Feb 2020 03:42:13 +0100

Platform: Positive Atom STM32F407 Explorer Development Pad + FreeModbus V1.6 + RT-Thread

Source link: https://www.embedded-solutions.at/en/freemodbus-downloads/

The source list is shown in the figure. The files needed include the ports related files in the modbus folder and demo folder. The location of the ports is shown below.

Within the BASE folder, there is a port folder (which contains the required port-related files) and a demo file, and the demo file has written the startup usage of FreeModbus.

Load these files into the project and include associated header files

Because of the first transplant, I dare not disturb, so I just transplant all of them in and turn on only the functions I need.The file at the beginning of the mb is a protocol stack program and does not need to be changed at this time; the file at the beginning of the port is a file that requires user configuration.portevent.c is not used. portserial.c and porttimer.c implement serial port and timer functions internally, including initialization of configuration and start and close.

Step 1: Configure portserial.c

The source file portserial.c contains the following functions, which are described in the comments.

 1 void
 2 vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )//Receive and receive mode of RS485 transceiver can be configured according to input parameters
 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 {
    //Initialize Serial Port-->Find Serial Port Device, Configure Serial Port according to Parameters, Open Serial Port Device, Set Serial Port Receive Callback Function, etc.
12 return FALSE;//Change to TRUE after adding code 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. */
    //Send a byte of data, just call the send interface
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 */
    //Receive a byte of data
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 {
    //Send interrupt function of protocol stack, which can be called inside serial send interrupt
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 {
    //The receive interrupt function of the protocol stack, which can be called inside the serial receive interrupt; put in the callback function
51 pxMBFrameCBByteReceived( ); 52 }

Step 2: Configure porttimer.c

The source file is similar to the form of serial port, as follows

 1 BOOL
 2 xMBPortTimersInit( USHORT usTim1Timerout50us )//Timer device initialization, find device, open device, configure device, set timeout according to parameters
 3 {
 4     return FALSE;//After adding code, you need to change to TRUE
 5 }
 6 
 7 
 8 inline void
 9 vMBPortTimersEnable(  )//This is interpreted as the start of a timer, which starts when the interface is called
10 {
11     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
12 }
13 
14 inline void
15 vMBPortTimersDisable(  )//The timer is off, the single timer I use personally, so I don't do anything about it.Close the timer if it is needed for a loop
16 {
17     /* Disable any pending timers. */
18 }
19 
20 static void prvvTIMERExpiredISR( void )//Timeout function, which can be called in timer timeout callback function
21 {
22     ( void )pxMBPortCBTimerExpired(  );
23 }

Step 3: Configure demo.c file

There is a main function under this file, and the other functions are callback functions of different functions.The main function and eMBRegInputCB in the officially downloaded source code have been implemented and can be used for reference.

 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 }

The main function implements the initialization, startup, and looping updates of the protocol stack. The three important functions are eMBInit, eMBEnable, and eMBPoll.It is used as a function loop in official source code, as a stand-alone task in RT-Thread, protocol stack initialization and startup in task function, and state update as thread loop.

 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 }

These functions are callback functions for the corresponding functions of the protocol stack, and an example is given. They are called by functions under the function file and only need to be implemented in the required functions.The return values of these functions are in a specific form and can be manipulated with reference to the example functions, so that the corresponding address data is processed according to actual needs.

 

Last:

Beginners on the road, there are still many places to understand not in place, temporarily record so much, continue learning!

Topics: C