STM32使用DMA接收不定长数据

  1. 开启串口,是能串口全局中断

  2. 配置DMA并勾选Memory选项
    STM32使用DMA接收不定长数据

  3. 继续配置工程并且生成代码

  4. 添加一些串口通讯使用的全局变量

    volatile uint8_t rx1_len    = 0;          //接收数据长度
    volatile uint8_t recv1_flag = 0;          //接收完成标记位
    uint8_t          rx1_buffer[BUFFER_SIZE]; //接收缓存
    
  5. 在主函数中开启串口中断和DMA接收

    // 由于HAL库本身的问题,可能需要在外设初始化后重启一下DMA
    // HAL_DMA_DeInit(&hdma_usart1_tx);
    // HAL_DMA_Init(&hdma_usart1_tx);
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);            // 使能idle中断
    HAL_UART_Receive_DMA(&huart1, rx1_buffer, BUFFER_SIZE); // 打开DMA接收
    

注意:
CubeMX生成的代码先初始化了串口再初始化DMA,会导致串口只能接收到最后一个字符的数据。这里需要将默认的初始化顺序调整一下,先初始化DMA,再初始化串口,即更改为:

MX_DMA_Init();
MX_USART1_UART_Init();
  1. 在中断处理函数中将串口数据存入缓冲区

    /**
      * @brief This function handles USART1 global interrupt.
      */
    void USART1_IRQHandler(void)
    {
    /* USER CODE BEGIN USART1_IRQn 0 */
    uint32_t tmp_flag = 0;
    uint32_t temp;
    tmp_flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE); //获取IDLE标志位
    if ((tmp_flag != RESET)) // idle标志被置位
    {
    	__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除标志位
    	temp = huart1.Instance->SR;         //清除状态寄存器SR
    	temp = huart1.Instance->DR;         //读取数据寄存器中的数据
    	HAL_UART_DMAStop(&huart1);
    	temp = hdma_usart1_rx.Instance->CNDTR; //获取DMA中未传输的数据个数
    	rx1_len        = BUFFER_SIZE - temp;   //得到已经接收的数据个数
    	recv1_flag = 1;                    //接受完成标志位置1
    }
    
    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */
    
    /* USER CODE END USART1_IRQn 1 */
    }
    
  2. 在主函数中轮询或在另一个线程中处理接收完成的数据

    if(recv_end_flag ==1)
    {
    	printf("rx_len=%d\r\n",rx_len);                      //打印接收长度
    	HAL_UART_Transmit(&huart2,rx_buffer, rx_len,200);    //接收数据打印出来
    	for(uint8_t i=0;i<rx_len;i++)
    	{
    	 rx_buffer[i]=0;      //清接收缓存
    	}
    	rx_len=0;        //清除计数
    	recv_end_flag=0;    //清除接收结束标志位
    }
    
  3. 数据处理结束后要重新打开DMA

    HAL_UART_Receive_DMA(&huart1, rx1_buffer, BUFFER_SIZE); //重新打开DMA接收
    
上一篇:蓝桥杯学习笔记八:捕获计数器


下一篇:stm32F103RCT6的DMA使用经历