ST意法半导体
直播中

崔映芬

8年用户 1001经验值
私信 关注
[问答]

stm32F407使用HAL_UARTEx_RxEventCallback实现的uart数据接收不会被清理,一直累加怎么解决?

我正在使用STM32F407学些开发stm32环境,在调试usart1的环境中遇到了问题:我使用DMA+中断的方式来实现数据的收发,但是每次我使用串口工具发送相同长度的数据过来,在HAL_UARTEx_RxEventCallback中断回调函数中发现size是在一直增加的,不会被清理,想请教在中断回调函数中怎么清理dma?贴上的的代码实现:
UART_HandleTypeDef huart1;#if 1#ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endifPUTCHAR_PROTOTYPE{    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);    return ch;}#endif#define UART1_READ_BUF_SIZE      256#define RXBUFFERSIZE             256                       /* 缓存大小 */static uint8_t g_rx_buffer[RXBUFFERSIZE];                  /* HAL库使用的串口接收缓冲 *//* USER CODE END 0 */DMA_HandleTypeDef hdma_usart1_rx;DMA_HandleTypeDef hdma_usart1_tx;static RingBufferStruct uart1_ring_buf;static mutex_handle_t uart1_mutex;static uint8_t uart1_read_buf[UART1_READ_BUF_SIZE];/* USART1 init function */void MX_USART1_UART_Init(uint32_t baud_rate){  /* USER CODE BEGIN USART1_Init 0 */  ring_buf_init(&uart1_ring_buf, uart1_read_buf, UART1_READ_BUF_SIZE);  /* USER CODE END USART1_Init 0 */  /* USER CODE BEGIN USART1_Init 1 */  /* USER CODE END USART1_Init 1 */  huart1.Instance = USART1;  huart1.Init.BaudRate = baud_rate;  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_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);  osal_mutex_create(&uart1_mutex);  /* 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_NORMAL;    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);    /* USART1_TX Init */    hdma_usart1_tx.Instance = DMA2_Stream7;    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    hdma_usart1_tx.Init.Mode = DMA_NORMAL;    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)    {      Error_Handler();    }    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);    /* USART1 interrupt Init */    HAL_NVIC_SetPriority(USART1_IRQn, 5, 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 DMA DeInit */    HAL_DMA_DeInit(uartHandle->hdmarx);    HAL_DMA_DeInit(uartHandle->hdmatx);    /* USART1 interrupt Deinit */    HAL_NVIC_DisableIRQ(USART1_IRQn);  /* USER CODE BEGIN USART1_MspDeInit 1 */  /* USER CODE END USART1_MspDeInit 1 */  }}/* USER CODE BEGIN 1 *//** * @brief       Rx传输回调函数 * @param       huart: UART句柄类型指针 * @retval      无 */void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){    if(huart->Instance == USART1)    {    }}void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size){    if (huart->Instance == USART1)    {        HAL_UART_Transmit(&huart1, g_rx_buffer, size, 0xFFFF);        if (ring_uf_get_nused_size(&uart1_ring_buf) >= size)        {            ring_buf_put(&uart1_ring_buf, g_rx_buffer, size);        }        memset(g_rx_buffer, 0, size);        HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);    }}uint32_t MX_USART1_UART_Send(const uint8_t *pdata, uint16_t size, uint32_t timeout){    return HAL_UART_Transmit(&huart1, pdata, size, timeout);}uint32_t MX_USART1_UART_Receive(const uint8_t *pData, uint16_t Size){    osal_mutex_lock(uart1_mutex);    uint16_t ret = ring_buf_get(&uart1_ring_buf, pData, Size);    osal_mutex_unlock(uart1_mutex);    return ret;}

回帖(1)

张明

2025-3-8 17:36:46

在使用STM32F407的HAL库进行UART通信时,你提到在HAL_UARTEx_RxEventCallback回调函数中发现接收到的数据长度size一直在增加,这表明DMA缓冲区中的数据没有被正确清理或重置。这通常是因为DMA缓冲区没有被重新初始化或清空,导致每次接收到的数据都追加到缓冲区中。


解决方法




  1. 在回调函数中重新启动DMA接收
    HAL_UARTEx_RxEventCallback回调函数中,重新启动DMA接收,以便DMA缓冲区从头开始接收数据。这样可以确保每次接收到的数据都是从缓冲区的起始位置开始写入。


    void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
    {
       if (huart->Instance == USART1)
       {
           // 处理接收到的数据
           // ...

           // 重新启动DMA接收
           HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)your_buffer, BUFFER_SIZE);
       }
    }



  2. 清空DMA缓冲区
    在重新启动DMA接收之前,可以手动清空DMA缓冲区,以确保没有残留数据。


    void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
    {
       if (huart->Instance == USART1)
       {
           // 处理接收到的数据
           // ...

           // 清空DMA缓冲区
           memset(your_buffer, 0, BUFFER_SIZE);

           // 重新启动DMA接收
           HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)your_buffer, BUFFER_SIZE);
       }
    }



  3. 确保DMA配置正确
    确保DMA配置正确,特别是在DMA初始化时,DMA缓冲区的地址和大小要正确设置。


    void MX_USART1_UART_Init(void)
    {
       // 配置USART1
       // ...

       // 配置DMA
       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_HIGH;
       hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
       hdma_usart1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
       hdma_usart1_rx.Init.MemBurst = DMA_MBURST_SINGLE;
       hdma_usart1_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
       HAL_DMA_Init(&hdma_usart1_rx);

       __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx);

       // 启动DMA接收
       HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t*)your_buffer, BUFFER_SIZE);
    }



  4. 检查DMA模式
    如果你使用的是循环模式(DMA_CIRCULAR),DMA缓冲区会循环覆盖旧数据。如果你希望每次接收到的数据都是独立的,可以考虑使用非循环模式(DMA_NORMAL),并在每次接收完成后手动重新启动DMA。


    hdma_usart1_rx.Init.Mode = DMA_NORMAL;



总结


通过在HAL_UARTEx_RxEventCallback回调函数中重新启动DMA接收并清空缓冲区,可以确保每次接收到的数据都是从缓冲区的起始位置开始写入,从而避免数据累加的问题。同时,确保DMA配置正确,特别是在DMA初始化时,DMA缓冲区的地址和大小要正确设置。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分