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

如何在裸机stm32移植FreeModbus

[复制链接]
攻城狮Melo 发布时间:2023-3-14 16:54
官方下载freemodbus-v1.6.zip源码,然后把源码中的modbus文件夹、demo\BARE\port文件夹导入工程。

先是一波无脑导,把文件夹里所有文件导入。

存储区配置,单片机上定义的起始地址要比实际通信过程中读写的地址+1。
  1. #include "mb.h"
  2. #include "mbport.h"
  3. #include "mbutils.h"
  4. //输入寄存器
  5. #define REG_INPUT_START 1001
  6. #define REG_INPUT_NREGS 2

  7. static USHORT   usRegInputStart = REG_INPUT_START;
  8. static USHORT   usRegInputBuf[REG_INPUT_NREGS];

  9. //保持寄存器
  10. #define REG_HOLDING_START 2001
  11. #define REG_HOLDING_NREGS 1

  12. static USHORT   usRegHoldingStart = REG_HOLDING_START;
  13. static USHORT   usRegHoldingBuf[REG_HOLDING_NREGS];

  14. //输出线圈点
  15. #define REG_COILS_START 3001
  16. #define REG_COILS_SIZE 4

  17. static USHORT   usRegCoilsStart = REG_COILS_START;
  18. static UCHAR           ucRegCoilsBuf[REG_COILS_SIZE/8+(REG_COILS_SIZE%8?1:0)];

  19. //离散输入点
  20. #define REG_DISCRETE_START 4001
  21. #define REG_DISCRETE_SIZE 8

  22. static USHORT   usRegDiscreteStart = REG_DISCRETE_START;
  23. static UCHAR           ucRegDiscreteBuf[REG_DISCRETE_SIZE/8+(REG_DISCRETE_SIZE%8?1:0)];

复制代码

主程序就是标准的运行三连+IO读写。
  1. eStatus = eMBInit( MB_RTU, addr, 0, 9600, MB_PAR_EVEN );

  2.     /* Enable the Modbus Protocol Stack. */
  3.     eStatus = eMBEnable(  );

  4.     for( ;; )
  5.     {
  6.         ( void )eMBPoll(  );
  7.         usRegInputBuf[0]=Get_Adc_Average(8,10);
  8.         usRegInputBuf[1]=Get_Adc_Average(9,10);
  9.                        
  10.         ucRegDiscreteBuf[0]=(GPIOB->IDR&0xFFFFFF00)>>8;
  11.         GPIOB->ODR=GPIOB->ODR&0xFFFFFF0F;
  12.         GPIOB->ODR=GPIOB->ODR|ucRegCoilsBuf[0]<<4;
  13.     }
复制代码

支持的4种读写function扔在主函数后面就行了。
  1. /**
  2. * @brief 输入寄存器处理函数,输入寄存器可读,但不可写。
  3. * @param pucRegBuffer 返回数据指针
  4. * usAddress 寄存器起始地址
  5. * usNRegs 寄存器长度
  6. * @retval eStatus 寄存器状态
  7. */
  8. eMBErrorCode
  9. eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
  10. {
  11.     eMBErrorCode eStatus = MB_ENOERR;
  12.     int16_t iRegIndex;

  13.     //查询是否在寄存器范围内
  14.     //为了避免警告,修改为有符号整数
  15.     if( ( (int16_t)usAddress >= REG_INPUT_START ) \
  16.             && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
  17.     {
  18.         //获得操作偏移量,本次操作起始地址-输入寄存器的初始地址
  19.         iRegIndex = ( int16_t )( usAddress - REG_INPUT_START );
  20.         //逐个赋值
  21.         while( usNRegs > 0 )
  22.         {
  23.             //赋值高字节
  24.             *pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] >> 8 );
  25.             //赋值低字节
  26.             *pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] & 0xFF );
  27.             //偏移量增加
  28.             iRegIndex++;
  29.             //被操作寄存器数量递减
  30.             usNRegs--;
  31.         }
  32.     }
  33.     else
  34.     {
  35.         //返回错误状态,无寄存器
  36.         eStatus = MB_ENOREG;
  37.     }

  38.     return eStatus;
  39. }

  40. /**
  41. * @brief 保持寄存器处理函数,保持寄存器可读,可读可写
  42. * @param pucRegBuffer 读操作时--返回数据指针,写操作时--输入数据指针
  43. * usAddress 寄存器起始地址
  44. * usNRegs 寄存器长度
  45. * eMode 操作方式,读或者写
  46. * @retval eStatus 寄存器状态
  47. */
  48. eMBErrorCode
  49. eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
  50.                  eMBRegisterMode eMode )
  51. {
  52.     //错误状态
  53.     eMBErrorCode eStatus = MB_ENOERR;
  54.     //偏移量
  55.     int16_t iRegIndex;

  56.     //判断寄存器是不是在范围内
  57.     if( ( (int16_t)usAddress >= REG_HOLDING_START ) \
  58.             && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
  59.     {
  60.         //计算偏移量
  61.         iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START );

  62.         switch ( eMode )
  63.         {
  64.         //读处理函数
  65.         case MB_REG_READ:
  66.             while( usNRegs > 0 )
  67.             {
  68.                 *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
  69.                 *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
  70.                 iRegIndex++;
  71.                 usNRegs--;
  72.             }
  73.             break;

  74.         //写处理函数
  75.         case MB_REG_WRITE:
  76.             while( usNRegs > 0 )
  77.             {
  78.                 usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  79.                 usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  80.                 iRegIndex++;
  81.                 usNRegs--;
  82.             }
  83.             break;
  84.         }
  85.     }
  86.     else
  87.     {
  88.         //返回错误状态
  89.         eStatus = MB_ENOREG;
  90.     }

  91.     return eStatus;
  92. }




  93. /**
  94. * @brief 线圈寄存器处理函数,线圈寄存器可读,可读可写
  95. * @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
  96. * usAddress 寄存器起始地址
  97. * usNRegs 寄存器长度
  98. * eMode 操作方式,读或者写
  99. * @retval eStatus 寄存器状态
  100. */
  101. eMBErrorCode
  102. eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
  103.                eMBRegisterMode eMode )
  104. {
  105.     //错误状态
  106.     eMBErrorCode eStatus = MB_ENOERR;
  107.     //寄存器个数
  108.     int16_t iNCoils = ( int16_t )usNCoils;
  109.     //寄存器偏移量
  110.     int16_t usBitOffset;

  111.     //检查寄存器是否在指定范围内
  112.     if( ( (int16_t)usAddress >= REG_COILS_START ) &&
  113.             ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
  114.     {
  115.         //计算寄存器偏移量
  116.         usBitOffset = ( int16_t )( usAddress - REG_COILS_START );
  117.         switch ( eMode )
  118.         {
  119.         //读操作
  120.         case MB_REG_READ:
  121.             while( iNCoils > 0 )
  122.             {
  123.                 *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,
  124.                                                   ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );
  125.                 iNCoils -= 8;
  126.                 usBitOffset += 8;
  127.             }
  128.             break;

  129.         //写操作
  130.         case MB_REG_WRITE:
  131.             while( iNCoils > 0 )
  132.             {
  133.                 xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,
  134.                                 ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),
  135.                                 *pucRegBuffer++ );
  136.                 iNCoils -= 8;
  137.                 usBitOffset += 8;
  138.             }
  139.             break;
  140.         }

  141.     }
  142.     else
  143.     {
  144.         eStatus = MB_ENOREG;
  145.     }
  146.     return eStatus;
  147. }




  148. /**
  149. * @brief 开关输入寄存器处理函数,开关输入寄存器,可读
  150. * @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
  151. * usAddress 寄存器起始地址
  152. * usNRegs 寄存器长度
  153. * eMode 操作方式,读或者写
  154. * @retval eStatus 寄存器状态
  155. */
  156. eMBErrorCode
  157. eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
  158. {
  159.     //错误状态
  160.     eMBErrorCode eStatus = MB_ENOERR;
  161.     //操作寄存器个数
  162.     int16_t iNDiscrete = ( int16_t )usNDiscrete;
  163.     //偏移量
  164.     uint16_t usBitOffset;

  165.     //判断寄存器时候再指定范围内
  166.     if( ( (int16_t)usAddress >= REG_DISCRETE_START ) &&
  167.             ( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE ) )
  168.     {
  169.         //获得偏移量
  170.         usBitOffset = ( uint16_t )( usAddress - REG_DISCRETE_START );

  171.         while( iNDiscrete > 0 )
  172.         {
  173.             *pucRegBuffer++ = xMBUtilGetBits( ucRegDiscreteBuf, usBitOffset,
  174.                                               ( uint8_t)( iNDiscrete > 8 ? 8 : iNDiscrete ) );
  175.             iNDiscrete -= 8;
  176.             usBitOffset += 8;
  177.         }

  178.     }
  179.     else
  180.     {
  181.         eStatus = MB_ENOREG;
  182.     }
  183.     return eStatus;
  184. }


复制代码

porttimer.c是和定时器相关的实现接口,计算好预分频与装载值之后,可以直接调用原子例程。
  1. /*
  2. * FreeModbus Libary: BARE Port
  3. * Copyright (C) 2006 Christian Walter <wolti@sil.at>
  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$
  20. */

  21. #include "port.h"

  22. /* ----------------------- Modbus includes ----------------------------------*/
  23. #include "mb.h"
  24. #include "mbport.h"

  25. #include "rs485.h"

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

  29. /* ----------------------- Start implementation -----------------------------*/
  30. void
  31. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  32. {
  33.     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
  34.      * transmitter empty interrupts.
  35.      */
  36.     if(xRxEnable)
  37.     {
  38.         //使能接收和接收中断
  39.         USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
  40.         //MAX485操作 低电平为接收模式
  41.         //GPIO_ResetBits(GPIOD,GPIO_Pin_8);
  42.         RS485_TX_EN=0;
  43.     }
  44.     else
  45.     {
  46.         USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
  47.         //MAX485操作 高电平为发送模式
  48.         //GPIO_SetBits(GPIOD,GPIO_Pin_8);
  49.         RS485_TX_EN=1;
  50.     }

  51.     if(xTxEnable)
  52.     {
  53.         //使能发送完成中断
  54.         USART_ITConfig(USART2, USART_IT_TC, ENABLE);
  55.     }
  56.     else
  57.     {
  58.         //禁止发送完成中断
  59.         USART_ITConfig(USART2, USART_IT_TC, DISABLE);
  60.     }


  61. }

  62. BOOL
  63. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  64. {
  65.     RS485_Init(9600);        //初始化RS485
  66.     return TRUE;
  67.     //return FALSE;
  68. }

  69. BOOL
  70. xMBPortSerialPutByte( CHAR ucByte )
  71. {
  72.     /* Put a byte in the UARTs transmit buffer. This function is called
  73.      * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  74.      * called. */
  75.     //发送数据
  76.     USART_SendData(USART2, ucByte);
  77.     return TRUE;
  78. }


  79. BOOL
  80. xMBPortSerialGetByte( CHAR * pucByte )
  81. {
  82.     /* Return the byte in the UARTs receive buffer. This function is called
  83.      * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  84.      */
  85.     //接收数据
  86.     *pucByte = USART_ReceiveData(USART2);
  87.     return TRUE;

  88. }

  89. /* Create an interrupt handler for the transmit buffer empty interrupt
  90. * (or an equivalent) for your target processor. This function should then
  91. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
  92. * a new character can be sent. The protocol stack will then call
  93. * xMBPortSerialPutByte( ) to send the character.
  94. */
  95. static void prvvUARTTxReadyISR( void )
  96. {
  97.     pxMBFrameCBTransmitterEmpty(  );
  98. }

  99. /* Create an interrupt handler for the receive interrupt for your target
  100. * processor. This function should then call pxMBFrameCBByteReceived( ). The
  101. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
  102. * character.
  103. */
  104. static void prvvUARTRxISR( void )
  105. {
  106.     pxMBFrameCBByteReceived(  );
  107. }

  108. void USART2_IRQHandler(void)
  109. {
  110.     if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
  111.     {
  112.         prvvUARTRxISR();
  113.         //清除中断标志位
  114.         USART_ClearITPendingBit(USART2, USART_IT_RXNE);
  115.     }

  116.     //发生完成中断
  117.     if(USART_GetITStatus(USART2, USART_IT_TC) == SET)
  118.     {
  119.         prvvUARTTxReadyISR();
  120.         //清除中断标志
  121.         USART_ClearITPendingBit(USART2, USART_IT_TC);
  122.     }

  123. }

复制代码

modbus移植过程基本就完成了。
————————————————
版权声明:小盼你最萌哒
如有侵权请联系删除


收藏 评论0 发布时间:2023-3-14 16:54

举报

0个回答

所属标签

相似分享

官网相关资源

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