串口空闲DMA任意长度接收

第一步、在串口初始化过程中手动添加:

if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */
        MX_DMA_Init();
  /* 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_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA1_Channel5;
    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;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
        __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
  /* USER CODE END USART1_MspInit 1 */
  }

第二步、在main函数中添加:

  /* USER CODE BEGIN 2 */

  HAL_UART_Receive_DMA(&huart1,RxBuf,UARTRXBUFFSIZE);

 /* USER CODE END 2 */

第三步、在串口中断函数添加:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    #if            Custom_Uart==true    //定义宏   Custom_Uart  

     Custom_UartDMAHandler(&huart1,&hdma_usart1_rx);
    #else

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
    #endif
  /* USER CODE END USART1_IRQn 1 */
}

第四步、串口空闲接收自定义函数:

void Custom_UartDMAHandler(UART_HandleTypeDef *huart,DMA_HandleTypeDef *hdma_rx)
{
    //数据接收完成
    if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE)!=RESET)) //进入空闲中断
    { 
        HAL_UART_AbortReceive(huart);
 
        if(huart->Instance==USART1){
            huart->RxXferCount= UARTRXBUFFSIZE - __HAL_DMA_GET_COUNTER(hdma_rx);
            osMessageQueuePut(DEBUGHandle,RxBuf,NULL,0);//发送消息至线程
            HAL_UART_Receive_DMA(huart,RxBuf,UARTRXBUFFSIZE);//重新打开DMA接收  
         }
    }
}




已邀请:

public_rtos

赞同来自: uouo00

这个方法我试过,很好用的。我用STM32F0芯片,两个UART同时DMA方式工作,一个用来接收GPS的NMEA0183协议,另一个用来驱动GPRS模块,PPP拨号,UDP通讯,真的很好用,节省CPU资源。
我的GPRS模块没有使用内置协议,没有使用LWIP和UIP,直接PPP拨号上网,在链路层自己写了一个UDP协议,拨号上网了之后采用DNS协议解析域名,然后连到远端服务器。整个AT命令设置参数、PPP拨号上网、DNS协议解析域名、UDP协议,加起来才1000来行,并且内存也占用极少。

要回复问题请先登录注册