STM32F429 HAL库移植FreeModbus_RTU详细步骤

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();
}

修改"stm32f4xx_it.c"文件

在stm32f4xx_it.c下添加串口中断函数与定时器中断函数

extern TIM_HandleTypeDef TIM2_Handler;
void TIM2_IRQHandler(void)
{
	HAL_NVIC_ClearPendingIRQ(TIM2_IRQn);
	HAL_TIM_IRQHandler(&TIM2_Handler);
}

extern void prvvUARTTxReadyISR(void);
extern void prvvUARTRxISR(void);
void USART2_IRQHandler(void)
{
  if(__HAL_UART_GET_IT_SOURCE(&USART2_RS485Handler, UART_IT_RXNE)!= RESET) 
	{
		prvvUARTRxISR();//接受中断
	}

	if(__HAL_UART_GET_IT_SOURCE(&USART2_RS485Handler, UART_IT_TXE)!= RESET) 
	{
		prvvUARTTxReadyISR();//发送完成中断
	}
  
  HAL_NVIC_ClearPendingIRQ(USART2_IRQn);
  HAL_UART_IRQHandler(&USART2_RS485Handler);  
}

修改"port.h"

#include <assert.h>
#include <inttypes.h>
#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("eMBRegInputCB\n");
//	用作例子
	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("eMBRegHoldingCB\n");
  return MB_ENOREG;
}


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

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


测试

使用串口调试助手发相应指令,返回相应寄存器值即移植成功。
在这里插入图片描述

************最后更新于2021-01-31**********
***************转载请注明出处***************
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值