当前位置: 首页 > article >正文

【蓝桥杯嵌入式】串口空闲中断+DMA接收不定长数据

MCU:STM32G431RBT6

一、实验效果

        将USART1接收到的数据原封不动的重新发送回去

二、STM32CUBEMX配置

        USART1的模式为异步通信、115200波特率、数据长度8位、无校验位、停止位1位

         注意:需要手动将USART1的引脚修改成PA9和PA10

        因为开发板上串口使用的是这个引脚进行通信,而开启USART1的默认引脚不是PA9和PA10,需要手动修改一下。

        DMA Settings

         NVIC Settings

         这里两个中断优先级我都给了1,根据不同情况修改中断优先级

         生成工程文档

三、keil代码

        首先确保魔术棒中的LIB这个选项勾选上,不然串口发送数据会不正常

        添加头文件,因为要使用memset函数

#include "string.h"

        定义串口接收数据数组

#define BUFF_SIZE	128			    //接收缓存大小
uint8_t rx_buffer[BUFF_SIZE];      // 创建接收缓存,大小为BUFF_SIZE

        在usart.h外部声明 hdma_usart1_rx,在main函数当中要使用

extern UART_HandleTypeDef huart1;

/* USER CODE BEGIN Private defines */
extern DMA_HandleTypeDef hdma_usart1_rx;
/* USER CODE END Private defines */

void MX_USART1_UART_Init(void);

         在main函数初始化添加这两个函数,不然串口首次无法进入中断

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFF_SIZE);	//启动串口DMA搬运
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   	//手动关闭DMA_IT_HT中断	

        重定向 HAL_UARTEx_RxEventCallback回调函数,该函数将串口接收到的数据原封不动的发送回去,若接收到的数据长度过长,会导致>Size后的数据丢失。在这里设置的是BUFF_SIZE=128。

/* 串口空闲中断回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART1)
    {
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收完毕后重启
		HAL_UART_Transmit(&huart1, rx_buffer, Size, 0xffff);         // 将接收到的数据再发出
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   		// 手动关闭DMA_IT_HT中断
		memset(rx_buffer, 0, BUFF_SIZE);							   	// 清除接收缓存
    }
}

        重定向 HAL_UART_ErrorCallback串口错误回调函数,若发生错误,重新使能DMA等。

        若是一开始电脑与开发板通信的波特率错误会导致开发板的串口空闲中断不再开启,这个回调函数里面的内容,让串口错误之后依旧可以恢复到正常的波特率进行通信。

/* 串口错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
{
    if(huart->Instance == USART1)
    {
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收发生错误后重启
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   // 手动关闭DMA_IT_HT中断
		memset(rx_buffer, 0, BUFF_SIZE);							   // 清除接收缓存
    }
}

        main函数完整代码

#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
#include "string.h"

void SystemClock_Config(void);

#define BUFF_SIZE	128			//接收缓存大小
uint8_t rx_buffer[BUFF_SIZE];  // 创建接收缓存,大小为BUFF_SIZE

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  
	HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,BUFF_SIZE);	//启动串口DMA搬运
	__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   	//手动关闭DMA_IT_HT中断	

  while (1)
  {
    
  }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* 串口空闲中断回调函数 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART1)
    {
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收完毕后重启
		HAL_UART_Transmit(&huart1, rx_buffer, Size, 0xffff);         // 将接收到的数据再发出
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   		// 手动关闭DMA_IT_HT中断
		memset(rx_buffer, 0, BUFF_SIZE);							   	// 清除接收缓存
    }
}

/* 串口错误回调函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef * huart)
{
    if(huart->Instance == USART1)
    {
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buffer, BUFF_SIZE); // 接收发生错误后重启
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);		   // 手动关闭DMA_IT_HT中断
		memset(rx_buffer, 0, BUFF_SIZE);							   // 清除接收缓存
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

四、参考文章

        好文

【STM32 HAL库实战】串口DMA + 空闲中断 实现不定长数据接收_hal dma 空闲中断-CSDN博客

五、原理

        参考文章写的挺详细,不过我实践测试起来还是有点小问题,之后补充。


http://www.kler.cn/a/506307.html

相关文章:

  • Docker PG流复制搭建实操
  • CentOS 9 Stream 上安装 Node.js 18.20.5
  • SDK调用文心一言如何接入,文心一言API接入教程
  • 【Compose multiplatform教程】05 IOS环境编译
  • 基于springboot的自习室预订系统
  • 微服务之松耦合
  • Swift语言的数据库编程
  • 【大语言模型】ACL2024论文-37 交互式文本到图像检索与大型语言模型:一种即插即用的方法
  • LeetCode 916. Word Subsets
  • pnpm add 和 pnpm install 的区别?
  • EE213 Lab virtuoso final project SRAM designlayout
  • SEO优化与版权保护:提升WordPress网站内容安全和价值
  • 朝天椒USB服务器在万家基金的前置机应用案例
  • 屏幕共享——局域网多个电脑信息分发屏幕分组-直播分享
  • 全面掌握WRF气象模拟与Python数据处理的集成应用与实践
  • C# 运算符和类型强制转换(用户定义的数据类型转换)
  • 如何查看特定版本的Spring源码
  • 深度剖析:NLP 领域基于 TF-IDF 和 Text-Rank 的关键字提取原理
  • Spring Boot集成Sharding-JDBC实现分库分表
  • 解密AIGC三大核心算法:GAN、Transformer、Diffusion Models原理与应用
  • Ubuntu打开文件夹不显示文件
  • 如何选择正确的电源 IC
  • 原神5.0单机版【完全无脑搭建】纯单机*稳定版*
  • 语法
  • leetcode 面试经典 150 题:汇总区间
  • 深度神经网络的校准问题研究:从架构差异到温度缩放优化