你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32移植FreeModbus实现ModBusRTU协议

[复制链接]
STMCU小助手 发布时间:2022-4-23 15:41
首先将FreeModbus移植到自己工程中,如下图所示:
20200323104757628.png

然后修改portserial.c和porttimer.c文件:
portserial.c

  1. /*
  2. * FreeModbus Libary: BARE Port
  3. * Copyright (C) 2006 Christian Walter
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18. *
  19. * File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
  20. */

  21. #include "port.h"
  22. #include "stm32f10x.h"
  23. #include "modbus.h"
  24. /* ----------------------- Modbus includes ----------------------------------*/
  25. #include "mb.h"
  26. #include "mbport.h"

  27. /* ----------------------- static functions ---------------------------------*/
  28. static void prvvUARTTxReadyISR( void );
  29. static void prvvUARTRxISR( void );

  30. /* ----------------------- Start implementation -----------------------------*/
  31. void
  32. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  33. {
  34.     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
  35.      * transmitter empty interrupts.
  36.      */
  37.         if(xRxEnable == TRUE)
  38.         {
  39.                 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  40.         }
  41.         else
  42.         {
  43.                 USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
  44.         }
  45.         
  46.         if(xTxEnable == TRUE)
  47.         {
  48.                 USART_ITConfig(USART2, USART_IT_TC, ENABLE);
  49.         }
  50.         else
  51.         {
  52.                 USART_ITConfig(USART2, USART_IT_TC, DISABLE);
  53.         }
  54. }

  55. BOOL
  56. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  57. {
  58.         modbus_uart_init((uint16_t)ulBaudRate);  

  59.         return TRUE;
  60. }

  61. BOOL
  62. xMBPortSerialPutByte( CHAR ucByte )
  63. {
  64.     /* Put a byte in the UARTs transmit buffer. This function is called
  65.      * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  66.      * called. */
  67.         
  68.         USART_SendData(USART2, ucByte);
  69.     return TRUE;
  70. }

  71. BOOL
  72. xMBPortSerialGetByte( CHAR * pucByte )
  73. {
  74.     /* Return the byte in the UARTs receive buffer. This function is called
  75.      * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  76.      */
  77.   *pucByte = USART_ReceiveData(USART2);
  78.         return TRUE;
  79. }

  80. /* Create an interrupt handler for the transmit buffer empty interrupt
  81. * (or an equivalent) for your target processor. This function should then
  82. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
  83. * a new character can be sent. The protocol stack will then call
  84. * xMBPortSerialPutByte( ) to send the character.
  85. */
  86. static void prvvUARTTxReadyISR( void )
  87. {
  88.     pxMBFrameCBTransmitterEmpty(  );
  89. }

  90. /* Create an interrupt handler for the receive interrupt for your target
  91. * processor. This function should then call pxMBFrameCBByteReceived( ). The
  92. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
  93. * character.
  94. */
  95. static void prvvUARTRxISR( void )
  96. {
  97.     pxMBFrameCBByteReceived(  );
  98. }

  99. /**
  100.   * @brief  This function handles usart1 Handler.
  101.   * @param  None
  102.   * @retval None
  103.   */
  104. void USART2_IRQHandler(void)
  105. {
  106.         //发生接收中断
  107.         if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
  108.         {
  109.                 prvvUARTRxISR();
  110.                 //清除中断标志位   
  111.                 USART_ClearITPendingBit(USART2, USART_IT_RXNE);   
  112.         }

  113.         if(USART_GetITStatus(USART2, USART_IT_ORE) == SET)
  114.         {  
  115.                 USART_ClearITPendingBit(USART2, USART_IT_ORE);
  116.                 prvvUARTRxISR();         
  117.         }

  118.         //发生完成中断
  119.         if(USART_GetITStatus(USART2, USART_IT_TC) == SET)
  120.         {
  121.                 prvvUARTTxReadyISR();
  122.                 //清除中断标志
  123.                 USART_ClearITPendingBit(USART2, USART_IT_TC);
  124.         }
  125. }
复制代码

porttimer.c


  1. ```c
  2. /*
  3. * FreeModbus Libary: BARE Port
  4. * Copyright (C) 2006 Christian Walter <<a href="mailto:wolti@sil.at">wolti@sil.at</a>>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  19. *
  20. * File: $Id: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
  21. */

  22. /* ----------------------- Platform includes --------------------------------*/
  23. #include "port.h"
  24. #include "modbus.h"
  25. /* ----------------------- Modbus includes ----------------------------------*/
  26. #include "mb.h"
  27. #include "mbport.h"

  28. /* ----------------------- static functions ---------------------------------*/
  29. static void prvvTIMERExpiredISR( void );

  30. /* ----------------------- Start implementation -----------------------------*/
  31. BOOL
  32. xMBPortTimersInit( USHORT usTim1Timerout50us )
  33. {
  34.         modbus_timer_init(usTim1Timerout50us);

  35.         return TRUE;
  36. }


  37. void
  38. vMBPortTimersEnable(  )
  39. {
  40.     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
  41.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  42.         TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  43.         TIM_SetCounter(TIM3,0x0000);
  44.         TIM_Cmd(TIM3, ENABLE);
  45. }

  46. void
  47. vMBPortTimersDisable(  )
  48. {
  49.     /* Disable any pending timers. */
  50.   TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  51.   TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
  52.   TIM_SetCounter(TIM3,0x0000);
  53.   TIM_Cmd(TIM3, DISABLE);
  54. }

  55. /* Create an ISR which is called whenever the timer has expired. This function
  56. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
  57. * the timer has expired.
  58. */
  59. static void prvvTIMERExpiredISR( void )
  60. {
  61.     ( void )pxMBPortCBTimerExpired(  );
  62. }

  63. void TIM3_IRQHandler(void)
  64. {
  65.         if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  66.         {
  67.                 prvvTIMERExpiredISR();
  68.                 TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  69.         }
  70. }
复制代码

然后主函数中调用


  1. int main(void)
  2. {               
  3.         delay_init();                     //延时函数初始化         
  4.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  5.         uart_init(115200);
  6.         eMBInit(MB_RTU, 0x01, 0x01, 9600, MB_PAR_NONE);
  7.         eMBEnable();  
  8.          while(1)
  9.         {
  10.                 (void)eMBPoll();
  11.                 delay_ms(5);
  12.                
  13.         }         
  14. }
复制代码

其次还要实现读线圈、写线圈、读离散输入、写保持寄存器、读保持寄存器、读输入寄存器等功能,如下:

  1. #define REG_INPUT_START       0x0001        //输入寄存器起始地址
  2. #define REG_INPUT_NREGS       8                        //输入寄存器数量

  3. #define REG_HOLDING_START     0x0001        //保持寄存器起始地址
  4. #define REG_HOLDING_NREGS     8                        //保持寄存器数量

  5. #define REG_COILS_START       0x0001        //线圈起始地址
  6. #define REG_COILS_SIZE        16                        //线圈数量

  7. #define REG_DISCRETE_START    0x0001        //开关寄存器其实地址
  8. #define REG_DISCRETE_SIZE     16                        //开关寄存器数量
  9. //输入寄存器内容
  10. uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007};
  11. //保持寄存器内容               
  12. uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007};                                       
  13. //线圈状态
  14. uint8_t ucRegCoilsBuf[REG_COILS_SIZE] = {0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00};
  15. //离散寄存器内容
  16. uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE] = {0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x01};

  17. /****************************************************************************
  18. * 名          称:eMBRegInputCB
  19. * 功    能:读取输入寄存器,对应功能码是 04 eMBFuncReadInputRegister
  20. * 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
  21. *                                                usAddress: 寄存器地址
  22. *                                                usNRegs: 要读取的寄存器个数
  23. * 出口参数:
  24. * 注          意:上位机发来的 帧格式是: SlaveAddr(1 Byte)+FuncCode(1 Byte)
  25. *                                                                +StartAddrHiByte(1 Byte)+StartAddrLoByte(1 Byte)
  26. *                                                                +LenAddrHiByte(1 Byte)+LenAddrLoByte(1 Byte)+
  27. *                                                                +CRCAddrHiByte(1 Byte)+CRCAddrLoByte(1 Byte)
  28. *                                                        3 区
  29. ****************************************************************************/
  30. eMBErrorCode
  31. eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
  32. {
  33.     eMBErrorCode    eStatus = MB_ENOERR;
  34.     int             iRegIndex;

  35.     if( ( usAddress >= REG_INPUT_START )
  36.         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
  37.     {
  38.         iRegIndex = ( int )( usAddress - REG_INPUT_START );
  39.         while( usNRegs > 0 )
  40.         {
  41.             *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );
  42.             *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );
  43.             iRegIndex++;
  44.             usNRegs--;
  45.         }
  46.     }
  47.     else
  48.     {
  49.         eStatus = MB_ENOREG;
  50.     }

  51.     return eStatus;
  52. }

  53. /****************************************************************************
  54. * 名          称:eMBRegHoldingCB
  55. * 功    能:对应功能码有:06 写保持寄存器 eMBFuncWriteHoldingRegister
  56. *                                                                                                        16 写多个保持寄存器 eMBFuncWriteMultipleHoldingRegister
  57. *                                                                                                        03 读保持寄存器 eMBFuncReadHoldingRegister
  58. *                                                                                                        23 读写多个保持寄存器 eMBFuncReadWriteMultipleHoldingRegister
  59. * 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
  60. *                                                usAddress: 寄存器地址
  61. *                                                usNRegs: 要读写的寄存器个数
  62. *                                                eMode: 功能码
  63. * 出口参数:
  64. * 注          意:4 区
  65. ****************************************************************************/
  66. eMBErrorCode
  67. eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
  68. {
  69.         eMBErrorCode    eStatus = MB_ENOERR;
  70.         int             iRegIndex;


  71.         if((usAddress >= REG_HOLDING_START)&&\
  72.                 ((usAddress+usNRegs) <= (REG_HOLDING_START + REG_HOLDING_NREGS)))
  73.         {
  74.                 iRegIndex = (int)(usAddress - REG_HOLDING_START);
  75.                 switch(eMode)
  76.                 {                                       
  77.                         case MB_REG_READ://读 MB_REG_READ = 0
  78.                                 while(usNRegs > 0)
  79.                                 {
  80.                                         *pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] >> 8);            
  81.                                         *pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] & 0xFF);
  82.                                         iRegIndex++;
  83.                                         usNRegs--;                                       
  84.                                 }                           
  85.                         break;
  86.                         case MB_REG_WRITE://写 MB_REG_WRITE = 0
  87.                                 while(usNRegs > 0)
  88.                                 {         
  89.                                         usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  90.                                         usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  91.                                         iRegIndex++;
  92.                                         usNRegs--;
  93.                                 }
  94.                         break;                                
  95.                 }
  96.         }
  97.         else//错误
  98.         {
  99.                 eStatus = MB_ENOREG;
  100.         }        
  101.         
  102.         return eStatus;
  103. }

  104. /****************************************************************************
  105. * 名          称:eMBRegCoilsCB
  106. * 功    能:对应功能码有:01 读线圈 eMBFuncReadCoils
  107. *                                                  05 写线圈 eMBFuncWriteCoil
  108. *                                                  15 写多个线圈 eMBFuncWriteMultipleCoils
  109. * 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
  110. *                                                usAddress: 线圈地址
  111. *                                                usNCoils: 要读写的线圈个数
  112. *                                                eMode: 功能码
  113. * 出口参数:
  114. * 注          意:如继电器
  115. *                                                0 区
  116. ****************************************************************************/
  117. eMBErrorCode
  118. eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
  119. {
  120.         eMBErrorCode    eStatus = MB_ENOERR;
  121.         int             iRegIndex;
  122.         u8 i;
  123.         USHORT readNumber=usNCoils;
  124.         USHORT coilValue=0x0000;
  125.         if((usAddress >= REG_COILS_START)&&\
  126.         ((usAddress+usNCoils) <= (REG_COILS_START + REG_COILS_SIZE)))
  127.         {
  128.                 iRegIndex = (int)(usAddress + usNCoils-REG_COILS_START);
  129.                 switch(eMode)
  130.                 {                                       
  131.                         case MB_REG_READ://读 MB_REG_READ = 0
  132.                                 for(i=0;i<usNCoils;i++)
  133.                                 {
  134.                                         readNumber--;
  135.                                         iRegIndex--;
  136.                                         coilValue|=ucRegCoilsBuf[iRegIndex]<<readNumber;
  137.                                 }
  138.                                 if(usNCoils<=8)
  139.                                 {
  140.                                         * pucRegBuffer=coilValue;
  141.                                 }
  142.                                 else
  143.                                 {
  144.                                         * pucRegBuffer++ = (coilValue)&0x00ff;
  145.                                         * pucRegBuffer++ = (coilValue>>8)&0x00ff;
  146.                                 }
  147.                         break;                           
  148.                         case MB_REG_WRITE://写 MB_REG_WRITE = 1
  149.                                 while(usNCoils > 0)
  150.                                 {         
  151.                                         //                         usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  152.                                         //           usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  153.                                                 iRegIndex++;
  154.                                                 usNCoils--;
  155.                                 }
  156.                         break;
  157.                 }
  158.         }
  159.         else//错误
  160.         {
  161.                 eStatus = MB_ENOREG;
  162.         }        

  163.         return eStatus;
  164. }
  165. /****************************************************************************
  166. * 名          称:eMBRegDiscreteCB
  167. * 功    能:读取离散寄存器,对应功能码有:02 读离散寄存器 eMBFuncReadDiscreteInputs
  168. * 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
  169. *                                                usAddress: 寄存器地址
  170. *                                                usNDiscrete: 要读取的寄存器个数
  171. * 出口参数:
  172. * 注          意:1 区
  173. ****************************************************************************/
  174. eMBErrorCode
  175. eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
  176. {
  177.         eMBErrorCode    eStatus = MB_ENOERR;
  178.         int             iRegIndex;
  179.         u8 i;
  180.         USHORT readNumber=usNDiscrete;
  181.         USHORT coilValue=0x0000;
  182.         iRegIndex = (int)(usAddress + usNDiscrete-REG_DISCRETE_START);
  183.         if((usAddress >= REG_DISCRETE_START)&&\
  184.         ((usAddress+usNDiscrete) <= (REG_DISCRETE_START + REG_DISCRETE_SIZE)))
  185.         {
  186.                 for(i=0;i<usNDiscrete;i++)
  187.                 {
  188.                         readNumber--;
  189.                         iRegIndex--;
  190.                         coilValue|=ucRegDiscreteBuf[iRegIndex]<<readNumber;
  191.                 }
  192.                 if(usNDiscrete<=8)
  193.                 {
  194.                         * pucRegBuffer=coilValue;
  195.                 }
  196.                 else
  197.                 {
  198.                         * pucRegBuffer++ = (coilValue)&0x00ff;
  199.                         * pucRegBuffer++ = (coilValue>>8)&0x00ff;
  200.                 }
  201.         }
  202.         else
  203.         {
  204.                 eStatus = MB_ENOREG;
  205.         }
  206.     return eStatus;
  207. }




复制代码



收藏 评论0 发布时间:2022-4-23 15:41

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版