欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32 HAL库 DMA接收数据丢失

程序员文章站 2022-06-03 20:44:55
...

STM32 HAL库 DMA接收数据丢失

一、STM32 DMA串口中断一般配置方法


/**
  * @brief This function handles USART6 global interrupt.
  */
void USART6_IRQHandler(void)
{
  /* USER CODE BEGIN USART6_IRQn 0 */

  /* USER CODE END USART6_IRQn 0 */
  HAL_UART_IRQHandler(&huart6;
  /* USER CODE BEGIN USART6_IRQn 1 */
    if((__HAL_UART_GET_FLAG(&huart6,UART_FLAG_IDLE) != RESET))//当发生空闲中断时
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart6);//清除标志位
        HAL_UART_DMAStop(&huart6); //停止接收
        //总计数减去未传输的数据个数,得到已经接收的数据个数;  
        //__HAL_DMA_GET_COUNTER(&hdma_usart6_rx);// 获取DMA中未传输的数据个数
        rx6_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart6_rx);
        HAL_UART_Receive_DMA(&huart6,rx6_buffer,BUFFER_SIZE);//重新打开DMA接收,BUFFER_SIZE大小为1024字节
    }
  /* USER CODE END USART6_IRQn 1 */
}

工作原理:
当发生空闲中断时,就会将数据接收到rx2_buffer中,若再次发生空闲中断时数据会从头覆盖rx2_buffer。

遇到的问题:
这种接收一般的数据没有任何问题,但是有一种情况会造成数据丢失:
当外界传输进来一段数据如:
[0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]
但是这段数据之间时间间隔比较大,变成:
[0x01,0x02,0x03,0x04,0x05,0x06,20ms,0x07,0x08] //因为某种原因中间多了20ms
这段数据的头尾有时间间隔,对于STM32 DMA来说发生了两次空闲中断,第二段数据就会覆盖掉第一段数据,变成:
[0x07,0x08,0x03,0x04,0x05,0x06,0x00,0x00]
则接收到的数据就丢失了。

二、解决方法

void USART6_IRQHandler(void)
{
  /* USER CODE BEGIN USART6_IRQn 0 */
    static unsigned int add_len = 0; //累加数据
  /* USER CODE END USART6_IRQn 0 */
  HAL_UART_IRQHandler(&huart6);
  /* USER CODE BEGIN USART6_IRQn 1 */
    
    if((__HAL_UART_GET_FLAG(&huart6,UART_FLAG_IDLE) != RESET))//idle标志被置位
    {
        recv6_end_flag = 1; // 接受完成标志位置1
        __HAL_UART_CLEAR_IDLEFLAG(&huart6);//清除标志位

        HAL_UART_DMAStop(&huart6); 
        
        add_len = rx6_len;
        
       //总计数减去未传输的数据个数,得到已经接收的数据个数;  
       //__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数     
        rx6_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart6_rx); 
        if((add_len + rx6_len) >= BUFFER_SIZE)
        {
            add_len = 0;
        }
        memcpy(&temp_buf[add_len],rx6_buffer,rx6_len);

        add_len += rx6_len;
        
        rx6_len = add_len;
        
        HAL_UART_Receive_DMA(&huart6,rx6_buffer,BUFFER_SIZE);//重新打开DMA接收
    }


  /* USER CODE END USART6_IRQn 1 */
}

解析:
将数据不断的累加进temp_buf数组里,使用的时候我们HAL_Delay()一段时间去取temp_buf中的数据,这样就会将所有的数据接收进来等待处理。

前后的对比:
1、前一段处理方式:可以正常接收,但是当一段数据中的数据片段之间时间间隔比较大就会多次触发空闲中断,导致数据覆盖而丢失。
2、后一段处理方式:将数据叠加在一起,根据实际情况延时取数据,然后再进行处理,防止数据丢失。
3、文中有许多细节未处理,不要太过纠结,只提供思路,其实还有其他的方式如回调函数等等。。。还有就是串口中断中不宜添加大量的代码如printf()函数等,否则也会丢数据。