STM32串口IDLE中断接收+DMA(HAL库)

目录

一、CubeMX配置

二、程序编写

三、最终结果


一、CubeMX配置

1、打开异步串口,配置相关参数:

2、使能发送和接收DMA,模式配置为单次发送,也就是每次发送完之后需要手动开启DMA,这样可以使得接收数据的过程更好控制;选择Memory地址自增,也就是每存一个数据,地址指针自动加1;数据宽度选择Byte:

 3、打开串口中断,并按需配置中断优先级,然后生成代码:

二、程序编写

1、首先在usart.h中,定义所需要用到的变量,这里我定义了一个串口数据结构体,并声明为外部变量:

#define BUFFER_SIZE 1024  //Receive datas size
//Define struct of the receive data
typedef struct {
  volatile uint16_t rx_len;
  volatile uint8_t recv_end_flag;
  uint8_t* rx_buf;
}UART_RxData_t;
extern UART_RxData_t rx_datas;

2、然后在usart.c中初始化串口数据结构体,并在MX_USART2_UART_Init串口初始化函数中调用串口空闲中断函数以及开启串口DMA接收:

/* USER CODE BEGIN 0 */
uint8_t rx_buffer[BUFFER_SIZE]={0};//Define receive array
UART_RxData_t rx_datas = {  //define receive data
  .recv_end_flag = 0,
  .rx_len = 0,
  .rx_buf = rx_buffer
};

/* USER CODE END 0 */
/* USER CODE BEGIN USART2_Init 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//Enable IDLE interrupt
HAL_UART_Receive_DMA(&huart2, rx_datas.rx_buf, BUFFER_SIZE);//Start RX DMA

/* USER CODE END USART2_Init 2 */

 3、接着去到stm32f1xx_it.c中断函数文件中,找到串口中断函数USART2_IRQHandler,并添加如下代码:

/**
  * @brief This function handles USART2 global interrupt.
  */
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
  //IDLE interrupt
  if(RESET != __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) {
    __HAL_UART_CLEAR_IDLEFLAG(&huart2);
    HAL_UART_DMAStop(&huart2);  //Stop RX DMA
    //Get the receive datas len
    rx_datas.rx_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
    rx_datas.recv_end_flag = 1;//Mark the end of receive
  }
  
  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

 4、最后在主循环中判断接收标志位是否为1,再将数据发回到上位机:

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    if(rx_datas.recv_end_flag) {
      rx_datas.recv_end_flag = 0;//Clear flag
      //Send the datas of receive
      if(HAL_OK != HAL_UART_Transmit_DMA(&huart2, rx_datas.rx_buf, rx_datas.rx_len)) {
        Error_Handler();
      }
      rx_datas.rx_len = 0;
      HAL_UART_Receive_DMA(&huart2, rx_datas.rx_buf, BUFFER_SIZE);//Start receive
    }
  }
  /* USER CODE END 3 */

 三、最终结果

 

可以看到给下位机发了700多个字符也能全部发送回上位机。

PS.代码仅作为学习记录,至于为什么心血来潮用英文写注释,完全是因为用中文写注释的时候,我用VSCode打开用CubeMX生成的新Keil工程后,中文乱码了。。。没办法,只能当作好好学习英语了~~~

以上均为个人学习心得,如有错误,请不吝赐教~

THE END

### STM32H7 UART DMA Receive Example Code For implementing UART reception using Direct Memory Access (DMA) on the STM32H7 microcontroller, a structured approach is necessary to ensure reliable data transfer without CPU intervention during the process of receiving bytes over UART. The following example demonstrates how this can be achieved by configuring UART and DMA peripherals properly. #### Initialization Function for UART with DMA Configuration The initialization function sets up both UART and DMA configurations required for non-blocking reception via DMA: ```c #include "stm32h7xx_hal.h" UART_HandleTypeDef huart1; DMA_HandleTypeDef hdma_usart1_rx; void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; 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(); } } static void MX_DMA_Init(void) { /* Init DMAs */ __HAL_RCC_DMAMUX1_CLK_ENABLE(); __HAL_RCC_MDMA_CLK_ENABLE(); hdma_usart1_rx.Instance = MDMA_Channel0; hdma_usart1_rx.Init.Request = MDMA_REQUEST_USART1_RX; hdma_usart1_rx.Init.TransferTriggerMode = MDMA_BLOCK_TRANSFER_EACH_PULSE; hdma_usart1_rx.Init.SourceInc = MDMA_SOURCE_INC_BYTE; hdma_usart1_rx.Init.DestInc = MDMA_DESTINATION_INC_BYTE; hdma_usart1_rx.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; hdma_usart1_rx.Init.DestDataSize = MDMA_DST_DATASIZE_BYTE; hdma_usart1_rx.Init.NodeNumber = 1; hdma_usart1_rx.Init.BufferOffset = 0; hdma_usart1_rx.Init.SourceBurst = DMA_SBURST_SINGLE; hdma_usart1_rx.Init.DestBurst = DMA_DBURST_SINGLE; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx); } ``` This setup ensures that `USART1` operates at 115200 baud rate while being configured for full-duplex communication mode[^1]. Additionally, it links the initialized DMA channel (`MDMA_Channel0`) specifically designed for handling RX transfers from `USART1`. #### Enabling DMA Reception To start receiving data through DMA once everything has been set up correctly: ```c uint8_t rxBuffer[64]; // Buffer size depends upon application needs // Start DMA-based reception before entering main loop or any other task. if(HAL_UART_Receive_DMA(&huart1, rxBuffer, sizeof(rxBuffer)) != HAL_OK){ // Handle error here... } ``` With these settings applied, whenever new characters arrive at the serial port's input pin, they will automatically get transferred into memory pointed by `rxBuffer`, freeing the processor core to perform tasks unrelated to I/O operations until an interrupt occurs indicating completion or overflow conditions. #### Handling Received Data After enabling DMA reception, one must also implement callback functions which handle events such as successful completions or errors associated with ongoing transactions between hardware components involved in the operation described above: ```c void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1){ // Process received buffer content when complete printf("Received %d bytes\n", strlen((char*)rxBuffer)); // Restart DMA receive after processing current batch HAL_UART_Receive_DMA(&huart1, rxBuffer, sizeof(rxBuffer)); } } void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1){ // Implement appropriate recovery strategy based on detected issue(s). // For demonstration purposes only: printf("Error occurred!\n"); } } ``` These callbacks allow developers to define custom logic executed immediately after each transaction ends successfully or encounters problems requiring attention.
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值