串口不定长接收在项目中经常用到,像MODBUS串口服务器中就会经常传来一大帧数据,数据的长度不定,通常人们的做法是采用环形队列接收的方式,以特定的结束标志位如0x0d 0x0a等用以判断一帧数据的结束,但实际上STM32这种高级的ARM单片机是带有空闲中断和DMA的,不需要用环形队列这种纯软件的做法实现不定长接收,直接用空闲中断+DMA就可以实现了,非常简单,小白也能一看就懂。 
    首先是要初始化串口不定长接收,比如打开空闲中断,打开DMA,这里我选的是板上的USB转TTL串口即串口3,对应的接收DMA为DMA1流1: 
 
 
  
代码如下: 
 
 
void UART3_Init(int baud) 
{ 
        __HAL_RCC_GPIOB_CLK_ENABLE(); 
        __HAL_RCC_USART3_CLK_ENABLE(); 
        __HAL_RCC_DMA1_CLK_ENABLE(); 
         
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11; 
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
  GPIO_InitStruct.Pull = GPIO_PULLUP; 
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3; 
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 
         
  huart3.Instance = USART3; 
  huart3.Init.BaudRate = baud; 
  huart3.Init.WordLength = UART_WORDLENGTH_8B; 
  huart3.Init.StopBits = UART_STOPBITS_1; 
  huart3.Init.Parity = UART_PARITY_NONE; 
  huart3.Init.Mode = UART_MODE_TX_RX; 
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; 
  huart3.Init.OverSampling = UART_OVERSAMPLING_16; 
  HAL_UART_Init(&huart3); 
        __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE); 
        HAL_NVIC_SetPriority(USART3_IRQn,0,0); 
  HAL_NVIC_EnableIRQ(USART3_IRQn); 
         
        hdma_usart3_rx.Instance = DMA1_Stream1; 
  hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4; 
  hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; 
  hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE; 
  hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE; 
  hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; 
  hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 
  hdma_usart3_rx.Init.Mode = DMA_NORMAL; 
  hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW; 
  hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 
  HAL_DMA_Init(&hdma_usart3_rx); 
         
  __HAL_LINKDMA(&huart3,hdmarx,hdma_usart3_rx); 
} 
 
 
void USART3_IRQHandler() 
{ 
        int temp; 
        if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)) 
        { 
                __HAL_UART_CLEAR_IDLEFLAG(&huart3); 
                HAL_UART_DMAStop(&huart3); 
                temp=__HAL_DMA_GET_COUNTER(&hdma_usart3_rx); 
                rx_len_uart3=BUFFERSIZE-temp;  
                rx_flag_uart3=1; 
        } 
} 
在主循环中加入以下语句以让单片机轮询串口不定长接收的标志位,并在液晶彩屏上显示出来: 
void UART_DMA_Get() 
{ 
        int i; 
        if(rx_flag_uart1==1) 
        { 
                printf("rx_len=%d\n\n",rx_len_uart1); 
                printf("%s\n\n",rx_buf_uart1);  
                rx_len_uart1=0; 
                rx_flag_uart1=0; 
        } 
        if(rx_flag_uart3==1) 
        { 
                printf("rx_len=%d\n\n",rx_len_uart3); 
                for(i=0;i<rx_len_uart3;i++) 
                { 
                        if(rx_buf_uart3=='\r'||rx_buf_uart3=='\n') 
                                rx_buf_uart3=0; 
 
 
                } 
                printf("%s\n\n",rx_buf_uart3); 
                SPILCD_DrawString(0,128,"                              ",BLACK,CYAN,ZF32_NORMAL); 
                SPILCD_DrawString(0,128,rx_buf_uart3,BLACK,CYAN,ZF32_NORMAL); 
 
 
                rx_len_uart3=0; 
                rx_flag_uart3=0; 
        } 
        HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf_uart1,BUFFERSIZE); 
        HAL_UART_Receive_DMA(&huart3,(uint8_t*)rx_buf_uart3,BUFFERSIZE); 
} 
 
 
看看效果,可以看到,上位机串口程序那边发什么,显示屏就显示什么: 
 
 
  
 
 
 
本文转载于【F407开发板】串口空闲中断+DMA实现不定长接收&处理 
http://www.stmcu.org.cn/module/forum/thread-619033-1-1.html 
 
 
 
 |   
     
  
 |