STM32F429 HAL库移植FreeModbus_RTU详细步骤

2023-11-18

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**********
***************转载请注明出处***************
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32F429 HAL库移植FreeModbus_RTU详细步骤 的相关文章

  • 138-基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真+源程序

    资料编号 138 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 ds1302时钟 LED灯 蜂鸣器 电位器 制作一个基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真 2 通过DHT1
  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • HAL 锁定和解锁函数如何使用以及为什么?

    我试图理解另一位程序员编写的代码 它使用了I C http en wikipedia org wiki I C2 B2C通信以将数据写入 STM32 微控制器的 EEPROM 一般来说 我理解他的代码是如何工作的 但我不明白他为什么使用HA
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • RS485:设备的 ioctl 不合适

    我使用以下代码访问 RS485 从站 但收到错误 读取 ioctl 端口 25 时出错 设备的 ioctl 不合适 我的代码如下 include
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • 毕设开题分享 单片机智能教室系统(智能照明+人数统计)

    1 简介 Hi 大家好 今天向大家介绍一个学长做的单片机项目 单片机智能教室系统 智能照明 人数统计 大家可用于 课程设计 或 毕业设计 项目分享 https gitee com feifei1122 simulation project
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • Arm:objcopy 如何知道 elf 中的哪些部分要包含在二进制或 ihex 中?

    我正在开发一个项目 其中涉及解析arm elf 文件并从中提取部分 显然 elf 文件中有很多部分没有加载到闪存中 但我想知道 objcopy 到底如何知道要在二进制文件中包含哪些部分以直接闪存到闪存中 以arm elf文件的以下reade
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • 将两个原始值转换为 32 位 IEEE 浮点数

    我正在尝试通过 TCP modbus 解码来自 Shark 100 功率计的一些数据 我已经成功地拉下了我需要的寄存器 并从寄存器中留下了两个原始值 如下所示 17138 59381 从手册中 我知道我需要将这两个数字转换为32位IEEE浮
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • STM32内部时钟

    我对 STM32F7 设备 意法半导体的 Cortex M7 微控制器 上的时钟系统感到困惑 参考手册没有充分阐明这些时钟之间的差异 SYSCLK HCLK FCLK 参考手册中阅读章节 gt RCC 为 Cortex 系统定时器 SysT
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re

随机推荐