STM32串口转虚拟串口---实现USB转串口功能
- 开源代码
- 2025-09-03 15:03:02

一,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)); } } }STM32串口转虚拟串口---实现USB转串口功能由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“STM32串口转虚拟串口---实现USB转串口功能”