STM32
直播中

周棠亨

8年用户 1065经验值
擅长:可编程逻辑 电源/新能源
私信 关注
[问答]

请问STM32F429 HAL库如何移植FreeModbus_RTU?

请问STM32F429 HAL库如何移植FreeModbus_RTU?

回帖(1)

刘萍

2021-11-18 11:44:38
freemodbus下载地址:freemodbus-v1.6
开发环境说明

1、基于正点原子F429例程-实验28 RS485移植
2、采用致远485摸块(自收发)
完整工程文件下载地址

如果不想手动移植可以点击跳转下载->F429_HAL_Freemodbus_rtu
F407也移植了相应的HAL库的Freemodbus_rtu,也可以点击跳转下载->F407_HAL_Freemodbus_rtu
本人也移植了带操作系统的相应例程,和RTU_TCP共用的相应例程,如果有需要,评论留言我再上传。
移植前提

取freemodbus文件目录下两个文件夹,分别是modbus与demo-BARE-port










BARE下取port





Modbus下取以下文件





在keil project下声明相应的.c与.h文件










修改"RS485.c"文件

在RS485.c文件下初始化串口usart与定时器tim;

void RS485_Init(u32 bound)
{
    //GPIO端口设置
        GPIO_InitTypeDef GPIO_Initure;
       
        __HAL_RCC_GPIOA_CLK_ENABLE();                        //使能GPIOA时钟
        __HAL_RCC_GPIOD_CLK_ENABLE();                        //使能GPIOA时钟
        __HAL_RCC_USART2_CLK_ENABLE();                        //使能USART2时钟
       
        GPIO_Initure.Pin=GPIO_PIN_3;                        //PA3
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;                //复用推挽输出
        GPIO_Initure.Pull=GPIO_PULLUP;                        //上拉
        GPIO_Initure.Speed=GPIO_SPEED_HIGH;                //高速
        GPIO_Initure.Alternate=GPIO_AF7_USART2;        //复用为USART2
        HAL_GPIO_Init(GPIOA,&GPIO_Initure);                   //初始化PA3
       
    GPIO_Initure.Pin=GPIO_PIN_5;                        //PD5
        GPIO_Initure.Mode=GPIO_MODE_AF_PP;                //复用推挽输出
        GPIO_Initure.Pull=GPIO_PULLUP;                        //上拉
        GPIO_Initure.Speed=GPIO_SPEED_HIGH;                //高速
        GPIO_Initure.Alternate=GPIO_AF7_USART2;        //复用为USART2
        HAL_GPIO_Init(GPIOD,&GPIO_Initure);                   //初始化PD5
       
    //USART 初始化设置
        USART2_RS485Handler.Instance=USART2;                                //USART2
        USART2_RS485Handler.Init.BaudRate=bound;                        //波特率
        USART2_RS485Handler.Init.WordLength=UART_WORDLENGTH_8B;        //字长为8位数据格式
        USART2_RS485Handler.Init.StopBits=UART_STOPBITS_1;                //一个停止位
        USART2_RS485Handler.Init.Parity=UART_PARITY_NONE;                //无奇偶校验位
        USART2_RS485Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;        //无硬件流控
        USART2_RS485Handler.Init.Mode=UART_MODE_TX_RX;                    //收发模式
        USART2_RS485Handler.Init.OverSampling = UART_OVERSAMPLING_16;
        HAL_UART_Init(&USART2_RS485Handler);                                //HAL_UART_Init()会使能USART2
   
  __HAL_UART_DISABLE_IT(&USART2_RS485Handler,UART_IT_TC);
#if EN_USART2_RX
        __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_RXNE);//开启接收中断
        HAL_NVIC_SetPriority(USART2_IRQn,0,1);                                //抢占优先级3,子优先级3
        HAL_NVIC_EnableIRQ(USART2_IRQn);                                        //使能USART1中断
#endif       
  RS485_TX_Set(0);                                        //设置为接收模式       
}


void TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;


  TIM2_Handler.Instance = TIM2;
  TIM2_Handler.Init.Prescaler = (9000-1);
  TIM2_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
  TIM2_Handler.Init.Period = 50;
  TIM2_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_Base_Init(&TIM2_Handler);


  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&TIM2_Handler, &sClockSourceConfig);


  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&TIM2_Handler, &sMasterConfig);  
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM2)
  {
    /* 基本定时器外设时钟使能 */
    __HAL_RCC_TIM2_CLK_ENABLE();


    /* 外设中断配置 */
    HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
  }
}
/**
  * 函数功能: 基本定时器硬件反初始化配置
  * 输入参数: htim_base:基本定时器句柄类型指针
  * 返 回 值: 无
  * 说    明: 该函数被HAL库内部调用
  */
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM2)
  {
    /* 基本定时器外设时钟禁用 */
    __HAL_RCC_TIM2_CLK_DISABLE();


    /* 关闭外设中断 */
    HAL_NVIC_DisableIRQ(TIM2_IRQn);
  }
}
修改"portserial.c"文件


#include "port.h"
#include "stm32f4xx_hal.h"
#include "rs485.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"


/* ----------------------- static functions ---------------------------------*/
//void prvvUARTTxReadyISR( void );
//void prvvUARTRxISR( void );
extern UART_HandleTypeDef USART2_RS485Handler;  //USART2句柄(用于RS485)


/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
        if (xRxEnable)
        {
                __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_RXNE);
        }
        else
        {
                __HAL_UART_DISABLE_IT(&USART2_RS485Handler,UART_IT_RXNE);
        }
        if (xTxEnable)
        {
                __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_TXE);
        }
        else
        {
                __HAL_UART_DISABLE_IT(&USART2_RS485Handler,UART_IT_TXE);
        }
}


BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    return TRUE;
}


BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
    /* Put a byte in the UARTs transmit buffer. This function is called
     * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
     * called. */
    if(HAL_UART_Transmit(&USART2_RS485Handler ,(uint8_t *)&ucByte,1,0x01) != HAL_OK )
        {
                return FALSE ;
        }
        else
        {
                return TRUE;
        }
}


BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
    /* Return the byte in the UARTs receive buffer. This function is called
     * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
     */
        if(HAL_UART_Receive (&USART2_RS485Handler ,(uint8_t *)pucByte,1,0x01) != HAL_OK )
        {
                return FALSE ;
        }
        else
        {
                return TRUE;
        }
}


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


/* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR( void )
{
    pxMBFrameCBByteReceived(  );
}
修改"porttimer.c"文件


/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
#include "stm32f4xx_hal.h"
#include "rs485.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
extern TIM_HandleTypeDef TIM2_Handler;      //定时器句柄
/* ----------------------- static functions ---------------------------------*/
//void prvvTIMERExpiredISR( void );


/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
    TIM2_Init();
    return TRUE;
}




inline void
vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
        __HAL_TIM_CLEAR_IT(&TIM2_Handler,TIM_IT_UPDATE);
        __HAL_TIM_SetCounter(&TIM2_Handler,0);
  
        /* 在中断模式下启动定时器 */
        HAL_TIM_Base_Start_IT(&TIM2_Handler);
}


inline void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
        HAL_TIM_Base_Stop_IT(&TIM2_Handler);
  
        __HAL_TIM_SetCounter(&TIM2_Handler,0);
        __HAL_TIM_CLEAR_IT(&TIM2_Handler,TIM_IT_UPDATE);  
}


/* Create an ISR which is called whenever the timer has expired. This function
* must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
* the timer has expired.
*/
void prvvTIMERExpiredISR( void )
{
    ( void )pxMBPortCBTimerExpired(  );
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
        prvvTIMERExpiredISR();
}
修改"port.h"


#include
#include
#include "stm32f4xx_hal.h" //添加声明
#define        INLINE                      inline
#define PR_BEGIN_EXTERN_C           extern "C" {
#define        PR_END_EXTERN_C             }


#define ENTER_CRITICAL_SECTION( )   __set_PRIMASK(1) //完善定义
#define EXIT_CRITICAL_SECTION( )    __set_PRIMASK(0) //完善定义
修改"main.c"文件

修改main.c函数,添加寄存器定义与modbus初始化


#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
#include "rs485.h"
#include "mb.h"
#include "mbport.h"


/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define REG_INPUT_START 0
#define REG_INPUT_NREGS 4


/* 私有变量 ------------------------------------------------------------------*/
static USHORT   usRegInputStart = REG_INPUT_START;
static USHORT   usRegInputBuf[REG_INPUT_NREGS];


int main(void)
{
    HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED
        KEY_Init();                     //初始化按键
       
        RS485_Init(9600);                        //初始化RS485
        eMBInit(MB_RTU, 0x01, 3, 9600, MB_PAR_NONE);
        /* Enable the Modbus Protocol Stack. */
        eMBEnable();
                                                                          
        while(1)
          {
                  (void)eMBPoll();
        }                      
}


eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
  eMBErrorCode    eStatus = MB_ENOERR;
  int             iRegIndex;
  
  printf("eMBRegInputCBn");
//        用作例子
        usRegInputBuf[0] = 0x11;
        usRegInputBuf[1] = 0x22;
        usRegInputBuf[2] = 0x33;
        usRegInputBuf[3] = 0x44;
//        例子结束
  if((usAddress>=REG_INPUT_START)&&(usAddress+usNRegs<=REG_INPUT_START+REG_INPUT_NREGS))
  {
    iRegIndex=(int)(usAddress-usRegInputStart);
    while( usNRegs > 0 )
    {
      *pucRegBuffer++ = (unsigned char)(usRegInputBuf[iRegIndex]>>8);
      *pucRegBuffer++ = (unsigned char)(usRegInputBuf[iRegIndex]&0xFF);
      iRegIndex++;
      usNRegs--;
    }
  }
  else
  {
    eStatus = MB_ENOREG;
  }
  return eStatus;
}


eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,eMBRegisterMode eMode )
{
  printf("eMBRegHoldingCBn");
  return MB_ENOREG;
}




eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,eMBRegisterMode eMode )
{
  printf("eMBRegCoilsCBn");
  return MB_ENOREG;
}


eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
  printf("eMBRegDiscreteCBn");
  return MB_ENOREG;
}


测试

使用串口调试助手发相应指令,返回相应寄存器值即移植成功。





  ************最后更新于2021-01-31**********  ***************转载请注明出处***************
举报

更多回帖

发帖
×
20
完善资料,
赚取积分