STM32 串口转 虚拟串口---实现USB转串口功能

发布于:2025-02-14 ⋅ 阅读:(31) ⋅ 点赞:(0)

一,USART与UART 区别

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收/发送器

相较于UART:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)多了一个S,即synchronous(同步)。

也就是说UART相较于USART只是少了一个同步方式而已,而串口在嵌入式中经常使用,但是我们一般使用UART就够

这些操作可以在Cubemx下自动生成。

二,串口初始化

void MX_USART1_Init(void)
{

  husart1.Instance = USART1;
  husart1.Init.BaudRate = 115200;
  husart1.Init.WordLength = USART_WORDLENGTH_8B;
  husart1.Init.StopBits = USART_STOPBITS_1;
  husart1.Init.Parity = USART_PARITY_NONE;
  husart1.Init.Mode = USART_MODE_TX_RX;
  husart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  husart1.Init.OverSampling = UART_OVERSAMPLING_16;
  husart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  husart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&husart1) != HAL_OK)
  {
    Error_Handler();
  }
    
    //HAL_UART_Receive_IT(&husart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
    
    //HAL_UARTEx_ReceiveToIdle_IT(&husart1, (u8 *)aRxBuffer, RXBUFFERSIZE);//串口接收任意字长字符串
}

三。IO初始化,DMA通道的设置


void HAL_UART_MspInit(UART_HandleTypeDef* usartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(usartHandle->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();
  			

		  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_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    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_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(usartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA1_Channel4;
    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;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(usartHandle,hdmatx,hdma_usart1_tx);

   
 #if EN_USART1_RX
		 /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 1,1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
#endif	
  }
}

四。DMA 中断的设置,注意,如果USART或DMA的中断优先级被设置得太低,它们可能会被其他高优先级的中断延迟。

void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
  /* DMA1_Channel5_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);

}

 五,DMA中断服务函数 不定长接收

停止HAL_UART_DMAStop(&husart1);  


  dat_len =  sizeof(aRxBuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);     //计算接收到的数据长度
        
        USB_USART_Send(aRxBuffer,dat_len);//虚拟串口转发    
        dat_len = 0;//清零
         memset(aRxBuffer,0,sizeof(aRxBuffer)); //重置
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));//再次开启DMA

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) 
{
    
    if(huart->Instance==USART1)//如果是串口1
    {
        HAL_UART_DMAStop(&husart1);  
        dat_len =  sizeof(aRxBuffer) - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);     //计算接收到的数据长度
        
        USB_USART_Send(aRxBuffer,dat_len);//虚拟串口转发    
        dat_len = 0;
         memset(aRxBuffer,0,sizeof(aRxBuffer)); 
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
    }
    
}
//串口1中断服务程序
void USART1_IRQHandler(void)                    
{     
    HAL_UART_IRQHandler(&husart1);    //调用HAL库中断处理公用函数    
} 
void DMA1_Channel4_IRQHandler(void)
{
 
  HAL_DMA_IRQHandler(&hdma_usart1_tx);
}

/**
  * @brief This function handles DMA1 channel5 global interrupt.
  */
void DMA1_Channel5_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_usart1_rx);
}

六,初始化 及溢出错误处理

if (Error_code_uart1 != HAL_OK)//出错,重开
    {
        // 清空缓冲,置位一些标志,具体看函数内部
        HAL_UART_AbortReceive(&husart1);
        // 重启接收
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
        }

int main(void)
{  
	u8 len;	
	

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init(); 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
	
	
	USB_Reset();       // USB断开再重连
	HAL_Delay(1);
	MX_USB_DEVICE_Init();
	MX_DMA_Init();
	MX_USART1_Init();

	HAL_Delay(2000);//等待虚拟串口初始化完成
	Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
  while (1)
  {
		u8 usbstatus = 0;

    if (usbstatus != USB_GetStatus())
    {
        usbstatus = USB_GetStatus(); // 记录新的状态
    }
		if (Error_code_uart1 != HAL_OK)//出错,重开
    {
        // 清空缓冲,置位一些标志,具体看函数内部
        HAL_UART_AbortReceive(&husart1);
        // 重启接收
        Error_code_uart1=HAL_UARTEx_ReceiveToIdle_DMA(&husart1, (u8 *)aRxBuffer, sizeof(aRxBuffer));
		}
	}
  
}