1、HAL库UART 中断|DMA 自动回显接收数据

文章详细介绍了如何在STM32F4微控制器上使用HAL库配置UART,包括开启宏定义、初始化函数、DMA和中断设置。通过HAL_UART_Init()和HAL_UART_MspInit()函数进行硬件层和外设层的初始化,实现了UART的DMA中断接收和中断接收两种模式,同时提供了串口重定向函数fputc()以支持printf()功能。此外,文章还提到了CubeMX配置中断和DMA接收数据回显的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、实现代码:

stm32f4xx_hal_conf.h文件开启UART宏定义

#define HAL_UART_MODULE_ENABLED

添加stm32f4xx_hal_uart.c和stm32f4xx_hal_dma.c到自己工程;
编写好的代码:usart_Driver.c

/**********************************************************************
*file:串口驱动
*author:残梦
*date:2023.2.13
*note:
**********************************************************************/
#include "usart_Driver.h"

#define UART1_BAUDRATE 2000000 //波特率
#define UART1_RX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART1_RX_GPIO_PORT              GPIOA
#define UART1_RX_GPIO_PIN               GPIO_PIN_10
#define UART1_RX_AF                     GPIO_AF7_USART1

#define UART1_TX_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOA_CLK_ENABLE()
#define UART1_TX_GPIO_PORT              GPIOA
#define UART1_TX_GPIO_PIN               GPIO_PIN_9
#define UART1_TX_AF                     GPIO_AF7_USART1

UART_HandleTypeDef huart1;

#ifndef _UART1_RX_MODE
    DMA_HandleTypeDef hdma_usart1_rx;
#endif
uint8_t huart1_RxData[50] = {0};
/****************************************************
@function:串口1初始化
@param:void
@return:void
@date:2023.2.13
@note:
****************************************************/
void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = UART1_BAUDRATE;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if(HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}

    #ifdef _UART1_RX_MODE
        HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));
    #else
        HAL_UART_Receive_DMA(&huart1,huart1_RxData,sizeof(huart1_RxData));
    #endif
}

/****************************************************
@function:串口1
@param:void
@return:void
@date:2023.2.13
@note:
****************************************************/
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_USART1_CLK_ENABLE();
    UART1_RX_GPIO_CLK_ENABLE();
    UART1_TX_GPIO_CLK_ENABLE();

    //外设引脚初始化
    GPIO_InitStruct.Pin = UART1_RX_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = UART1_RX_AF;
    HAL_GPIO_Init(UART1_RX_GPIO_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = UART1_TX_GPIO_PIN;
    GPIO_InitStruct.Alternate = UART1_TX_AF;
    HAL_GPIO_Init(UART1_TX_GPIO_PORT, &GPIO_InitStruct);

    #ifdef _UART1_RX_MODE
        HAL_NVIC_SetPriority(USART1_IRQn,1,0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    #else
        __HAL_RCC_DMA2_CLK_ENABLE();
        hdma_usart1_rx.Instance = DMA2_Stream2;
        hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
        hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        hdma_usart1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
        hdma_usart1_rx.Init.MemBurst = DMA_MBURST_SINGLE;
        hdma_usart1_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
        if(HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){Error_Handler();}

        __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx);//关联DMA句柄
        HAL_NVIC_SetPriority(DMA2_Stream2_IRQn,0,0);
        HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
    #endif
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发

    #ifdef _UART1_RX_MODE
        HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));//中断方式接收则需开启,否则会导致接收完指定数据个数后自动关闭
    #endif
}

usart_Driver.h

#ifndef _usart_Driver_H_
#define _usart_Driver_H_
#include "Common_Driver.h"
//#define _UART1_RX_MODE //未定义--DMA方式接收,定义--中断接收方式

extern UART_HandleTypeDef huart1;
extern void MX_USART1_UART_Init(void);

#endif

在stm32f4xx_it.c文件中添加中断处理函数:

/* USER CODE BEGIN 1 */
#include "usart_driver.h"
#ifdef _UART1_RX_MODE
void USART1_IRQHandler(void)
{
  extern UART_HandleTypeDef huart1;
  HAL_UART_IRQHandler(&huart1);
}
#else
void DMA2_Stream2_IRQHandler(void)
{
  extern DMA_HandleTypeDef hdma_usart1_rx;
  HAL_DMA_IRQHandler(&hdma_usart1_rx);
}
#endif
/* USER CODE END 1 */
```c
/****************************************************
@function:串口重定义
@param:void
@return:void
@date:2023.2.14
@note:使用printf时需要此函数,并在Keil魔术棒中勾选User MicroLIB库
****************************************************/
int fputc(int ch,FILE *f)
{
    uint8_t data = ch;
	HAL_UART_Transmit(&huart1,&data,1,1);
	return(ch);
}

主函数调用MX_USART1_UART_Init();即可实现自收自发
在这里插入图片描述

2、电路推荐:CH340N

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、初始化处理框架 MX_USART1_UART_Init()

void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = UART1_BAUDRATE;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if(HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}

    #ifdef _UART1_RX_MODE
        HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));
    #else
        HAL_UART_Receive_DMA(&huart1,huart1_RxData,sizeof(huart1_RxData));
    #endif
}

OverSampling :过采样
8倍过采样速度更快,最高速度可达fPCLK/8,fPCLK为USART时钟;
16倍过采样速度虽然没有8倍过采样那么快,但得到的数据更加精准,其最大速度为fPCLK/16;

那么HAL_UART_Init()里面做了什么呢?

移除参数检查,提取主要后

HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
{
  if (huart->gState == HAL_UART_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    huart->Lock = HAL_UNLOCKED;
    /* Init the low level hardware : GPIO, CLOCK */
    HAL_UART_MspInit(huart);
  }

  huart->gState = HAL_UART_STATE_BUSY;

  /* Disable the peripheral */
  __HAL_UART_DISABLE(huart);

  /* Set the UART Communication parameters */
  UART_SetConfig(huart);

  /* In asynchronous mode, the following bits must be kept cleared:
     - LINEN and CLKEN bits in the USART_CR2 register,
     - SCEN, HDSEL and IREN  bits in the USART_CR3 register.*/
  CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
  CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));

  /* Enable the peripheral */
  __HAL_UART_ENABLE(huart);

  /* Initialize the UART state */
  huart->ErrorCode = HAL_UART_ERROR_NONE;
  huart->gState = HAL_UART_STATE_READY;
  huart->RxState = HAL_UART_STATE_READY;

  return HAL_OK;
}

所以这个函数顺序则先通过函数HAL_UART_MspInit()初始化底层硬件:GPIO, CLOCK
再调用UART_SetConfig()设置时串口通信参数
__HAL_UART_ENABLE()启用外围设备

那么HAL_UART_MspInit()里面做了什么呢?

该函数主要是初始化底层硬件:GPIO、CLOCK、DMA、中断
开启DMA时需要关联句柄

__HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx);//关联DMA句柄

为什么使用的是DMA2_Stream2 且通道4呢
在这里插入图片描述
可以看到USART1挂载在APB2上
在这里插入图片描述
在这里插入图片描述
由此知晓DMA使用的流和通道

启动中断|DMA去接收数据

中断接收函数:HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size)
1、使用此函数值得注意的是此函数
Size参数代表接收的数据个数,在接收完该个数后会自动关闭中断,导致后续数据不去接收了**
所以在接收到数据回调函数中需要再次调用此函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发

    #ifdef _UART1_RX_MODE
        HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));//中断方式接收则需开启,否则会导致接收完指定数据个数后自动关闭
    #endif
}

2、使用前需开启串口中断

    HAL_NVIC_SetPriority(USART1_IRQn,1,0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);

**DMA中断接收函数:HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size)
1、使用前需要开启DMA中断并关联DMA句柄

    __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx);//关联DMA句柄
    HAL_NVIC_SetPriority(DMA2_Stream2_IRQn,0,0);
    HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);

中断函数调用HAL库处理函数中的处理

在stm32f4xx_it.c文件中添加中断处理函数:HAL_外设名_IRQHandler();
如HAL_UART_IRQHandler()或者HAL_DMA_IRQHandler();
注意:在HAL_UART_IRQHandler()函数中会调用函数:
函数中会在接收完指定数据个数后会执行的关闭中断(在使用函数HAL_UART_Receive_IT()时)

static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
 ......省略
    if (--huart->RxXferCount == 0U)//此处就是在接收完指定数据个数后会执行的关闭中断
    {
      /* Disable the UART Data Register not empty Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

      /* Disable the UART Parity Error Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

      /* Rx process is completed, restore huart->RxState to Ready */
      huart->RxState = HAL_UART_STATE_READY;

      /* Check current reception Mode :
         If Reception till IDLE event has been selected : */
      if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
      {
      	......
      }
      else
      {
        /*Call legacy weak Rx complete callback*/
        HAL_UART_RxCpltCallback(huart);
      }
    }
 ......省略
}

HAL_DMA_IRQHandler()函数可是不会去关闭的哈

4、CubeMx UART 中断接收回显数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生成代码即可
在这里插入图片描述
1、main.h中包含stdio.h文件

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

2、usart.c中
定义接收数据区变量

/* USER CODE BEGIN 0 */
uint8_t huart1_RxData[50] = {0};
/* USER CODE END 0 */

MX_USART1_UART_Init()函数中添加数据中断接收函数:

  /* USER CODE BEGIN USART1_Init 2 */
  HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));
  /* USER CODE END USART1_Init 2 */

添加回调函数并发送接收到的数据

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发
  HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));//中断方式接收则需开启,否则会导致接收完指定数据个数后自动关闭
}

编写串口重定义函数,方便使用printf()

/****************************************************
@function:串口重定义
@param:void
@return:void
@date:2023.2.14
@note:使用printf时需要此函数,并在Keil魔术棒中勾选User MicroLIB库
****************************************************/
int fputc(int ch,FILE *f)
{
    uint8_t data = ch;
	HAL_UART_Transmit(&huart1,&data,1,1);
	return(ch);
}

在这里插入图片描述
usart.c

/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
uint8_t huart1_RxData[50] = {0};
/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 2000000;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
  HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));
  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/****************************************************
@function:串口重定义
@param:void
@return:void
@date:2023.2.14
@note:使用printf时需要此函数,并在Keil魔术棒中勾选User MicroLIB库
****************************************************/
int fputc(int ch,FILE *f)
{
    uint8_t data = ch;
	HAL_UART_Transmit(&huart1,&data,1,1);
	return(ch);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发
  HAL_UART_Receive_IT(&huart1, huart1_RxData, sizeof(huart1_RxData));//中断方式接收则需开启,否则会导致接收完指定数据个数后自动关闭
}

/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

UART 中断接收完整工程:
链接:https://pan.baidu.com/s/1p34JFrjOUl2_IsnvZBSn0w
提取码:au2o

## 5、CubeMx UART DMA中断接收回显数据

注意:除了USART1外其他配置和CubeMx UART 中断接收回显数据一样
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
产生工程代码
1、usart.c中
定义接收数据区变量

/* USER CODE BEGIN 0 */
uint8_t huart1_RxData[50] = {0};
/* USER CODE END 0 */

MX_USART1_UART_Init()函数中添加数据DMA中断接收函数:

  /* USER CODE BEGIN USART1_Init 2 */
  HAL_UART_Receive_DMA(&huart1,huart1_RxData,sizeof(huart1_RxData));
  /* USER CODE END USART1_Init 2 */

添加回调函数并发送接收到的数据

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发
}

在这里插入图片描述
usart.c

/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
uint8_t huart1_RxData[50] = {0};
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 2000000;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
  HAL_UART_Receive_DMA(&huart1,huart1_RxData,sizeof(huart1_RxData));
  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_Transmit(&huart1,huart1_RxData,sizeof(huart1_RxData),10);//自收自发
}
/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

UART DMA接收完整工程:
链接:https://pan.baidu.com/s/15aVMAqIVg8DrLjlPVGY5ag
提取码:3nmu

UART DMA或者中断发送完成可以依靠如下实现:
while(!(huart1.Instance->SR & (0x01 << 6)))osDelay(1);//判断TC发送完成标志

<think>嗯,用户想了解如何使用STM32 HAL实现串口中断接收功能,还要示例代码。首先,我需要顾一下HAL的串口中断处理流程。记得HAL提供了中断处理函数,比如HAL_UART_IRQHandler,但用户需要自己编写调函数来处理接收完成的事件。 首先,用户可能已经用STM32CubeMX配置了串口,但需要确认是否开启了中断。在CubeMX中,启用USART的全局中断是必须的,否则无法触发中断。然后,初始化部分要调用HAL_UART_Init,接着启动接收,使用HAL_UART_Receive_IT函数,这个函数会启动中断接收,并设置接收缓冲区和长度。 接下来,中断服务函数的问题。HAL已经处理了大部分底层的中断标志,用户只需要在stm32f1xx_it.c中调用HAL_UART_IRQHandler,然后实现HAL_UART_RxCpltCallback调函数。这个调函数会在接收完成时被调用,用户可以在里面处理接收到的数据,比如或者存储。 用户可能遇到接收卡死的问题,比如没有及时重启接收中断,或者在调函数中做了太多操作,导致中断被阻塞。这时候需要确保在调函数中尽快处理数据,并重新启动接收。例如,在调函数里调用HAL_UART_Receive_IT再次启动接收,以等待下一个数据。 示例代码方面,可能需要展示CubeMX的配置步骤,比如选择USART1,设置波特率,开启中断,生成代码。然后添加用户代码,在main函数中启动接收,并实现调函数。还要注意volatile变量来存储接收数据,避免编译器优化导致的问题。 另外,用户可能对HAL的函数不太熟悉,需要解释HAL_UART_Receive_IT的参数,比如huart指向串口句柄,pData是缓冲区指针,Size是接收的字节数。还要提醒错误处理,检查返值,确保接收启动成功。 可能还需要提到DMA方式与中断方式的区别,但用户明确要求中断接收,所以可以暂不展开。不过如果提到性能优化,可能可以建议在后续问题中探讨。 最后,确保答结构清晰,分步骤说明配置和代码实现,并给出常见问题的解决方法,比如接收卡死的可能原因,如未重新启动接收中断。同时引用提供的参考资料,比如引用[1]提到的接收卡死问题,引用[2]和[3]中的HAL函数说明。</think>### STM32 HAL串口中断接收实现方法 #### 一、实现步骤 1. **CubeMX配置** - 启用USART模块并配置参数(波特率/数据位/校验位) - 在NVIC Settings中勾选USART全局中断使能 - 生成代码时选择生成HAL初始化代码 2. **关键代码实现** ```c // 在main.c中添加全局变量 volatile uint8_t rx_buffer[1]; // 单字节接收缓冲区 int main(void) { HAL_Init(); SystemClock_Config(); MX_USART1_UART_Init(); // 启动中断接收 HAL_UART_Receive_IT(&huart1, rx_buffer, 1); while (1) { // 主循环处理其他任务 } } // 中断调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { // 处理接收到的数据(示例:HAL_UART_Transmit(&huart1, rx_buffer, 1, 100); // 重新启动接收 HAL_UART_Receive_IT(&huart1, rx_buffer, 1); } } ``` #### 二、关键函数说明 1. `HAL_UART_Receive_IT()`:启动非阻塞接收 - 参数:串口句柄/接收缓冲区指针/接收数据长度 - 返值:HAL_OK表示启动成功 2. `HAL_UART_RxCpltCallback()`:接收完成调函数 - 在中断服务程序中被自动调用 - 必须重新调用`HAL_UART_Receive_IT()`以持续接收 #### 三、常见问题解决 1. **接收卡死**:确保在调函数中重新启动接收[^1] 2. **数据丢失**:使用循环缓冲区并提高中断优先级 3. **波特率误差**:通过CubeMX时钟树配置确保波特率精度 #### 四、完整示例流程图 ``` CubeMX配置 ↓ 生成初始化代码 ↓ main()启动中断接收 ↓ 中断触发→调用HAL_UART_IRQHandler ↓ 自动调用RxCpltCallback ↓ 处理数据并重启接收 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值