平台:正点原子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文件下的函数调用,只需在须要的功能里做出对应实现便可。这些函数的返回值是特定的形式,参考示例函数进行操做便可,至于相应地址数据的处理根据实际需求。
最后:
新手上路,还有不少地方理解不到位,暂时记录这么多,继续学习!