STM32 USB 系列之 虛擬串口(VPC)

STM32 USB系列之虛擬串口

這段時間緩慢更新一下stm32 usb系列的博客,前段時間在多個地方零零散散的學習和使用USB協議,在網上查找的資料也是零零散散的,整理一下寫成博客。


1. 開發環境

使用stm32f103c8t6,HAL庫,使用CUBE自帶的USB庫。工程使用vscode+gcc編譯,工程文件在文末鏈接下載,提供makefile和keil兩個版本。

2. 功能介紹

使用stm32 USB功能完成USB轉串口功能,使用引腳配置如下:
引腳配置
使用USART1作爲調試信息輸出,USART2作爲串口輸出,LED爲系統指示。

3. CubeMX 配置

設置系統時鐘爲72MHZ,調試串口UASART1波特率爲921600(選擇高波特率,少佔用中斷時間),USART2波特率默認爲115200,開啓中斷。
在這裏插入圖片描述
選擇USB Device功能,速度爲默認全速USB設備12MHZ,並使能USB_DEVICE庫,選擇Virtual Port Com (虛擬串口,VPC),使用默認配置。
在這裏插入圖片描述
在這裏插入圖片描述
設置系統時鐘爲72MHZ,然後生成工程。
在這裏插入圖片描述

4.軟件部分

使用cube生成的代碼編譯下載後,將USB插入電腦,在電腦設備管理器中將顯示新的串口設備(使用STM32的USB VPC時需要對應的驅動程序,驅動在程序也在文末的鏈接中)
在這裏插入圖片描述
在串口調試助手中,可打開或關閉串口,不過此時還沒有任何功能。

4.1 發送函數

接下來進行功能配置,虛擬串口的主要配置代碼在 src->usbd_cdc_if.c中,其中幾個重要函數爲:

static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len);
uint8_t CDC_Control_FS(uint8_t* Buf, uint16_t Len);

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);函數用於向USB VPC發送數據,Buf爲待發送的數據緩衝區地址,Len爲待發送數據長度。

/*示例一,在main函數中的while循環中輸入下列代碼
		在連接打開串口助手後可接收到數據*/
while(1)
{
	CDC_Control_FS((uint8_t *)"hello\n",6);
	HAL_Delay(1000);
}

在編譯下載後,將USB插入電腦,使用川酷哦調試助手將會每秒接收到一次"hello"。

4.2 USB上電重新枚舉

在使用上面代碼的時候存在一個問題:每次下載完程序後都需要重新拔插一次USB纔可以識別串口,這是由於芯片在下載完程序後沒有重新枚舉所導致的。需要在設備上電後對USB進行重新枚舉即可,使用方法爲將USB DP(PA12)引腳拉低一段時間後即可。

/*USB 重新枚舉函數*/
void USB_Reset(void)
{
  	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
	HAL_Delay(100);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
}

該函數使用時應放在USB初始化之前,或者使用其他IO控制三極管拉低電平。

 /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  USB_Reset();
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_USB_DEVICE_Init();
  MX_USART2_UART_Init();

在這裏插入圖片描述
重新下載上電後,可發現串口已重新枚舉識別,只需重新開啓串口調試助手即可。

4.3 USB接收函數

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)爲USB接收回調函數,在USB VPC接收到數據時,會進入該函數,在該函數中進行USB數據接收處理即可。
USB轉串口設備,需要在stm32的USB端接收到數據後轉發到stm32 串口端

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  extern UART_HandleTypeDef huart2,huart1;
  /*將USB接收到的數據轉發到USART2*/
  HAL_UART_Transmit_IT(&huart2,Buf,*Len);
  
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
  /* USER CODE END 6 */
}

在stm32虛擬的串口中發送數據,可在stm32的USART2的TX引腳(PA2)收接收到數據。
在這裏插入圖片描述

4.4 設置USB虛擬串口波特率

在前面的發送和接收中,均不能進行波特率設置,usb發送到串口的數據波特率爲默認值115200。
USB的波特率配置在static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)函數中,cmd爲usb cdc的控制命令,pbuf爲數據接收指針,length爲數據長度。
當cmd爲0x20時爲設置虛擬串口波特率;
在這裏插入圖片描述
其接收到的數據一共七位,數據格式定義(小端模式)如下:

偏移 含義 數據大小 說明
0-3 波特率 4字節 串口波特率,位每秒
4 停止位 1字節 0 ~ 一位停止位、1 ~ 1.5位停止位 、2 ~ 2位停止位
5 校驗位 1字節 0無校驗、1奇校驗、2偶校驗、3、4~是啥我也不知道了
6 數據位 1字節 5,6,7,8,16

由於stm32芯片並不支持這麼多串口參數,在無對應參數時使用默認配置。在接收到修改波特率命令後修改USART配置。

case CDC_SET_LINE_CODING:
{
      extern UART_HandleTypeDef huart2;
      huart2.Init.BaudRate=*((uint32_t*)pbuf);
      switch (pbuf[4])
      {
      case 2:
        huart2.Init.StopBits=UART_STOPBITS_2;
        break;
      default:
        huart2.Init.StopBits=UART_STOPBITS_1;
        break;
      }
      switch (pbuf[5])
      {
      case 1:
        huart2.Init.Parity=UART_PARITY_ODD;
        break;
      case 2:
        huart2.Init.Parity=UART_PARITY_EVEN;
        break;
      default:
        huart2.Init.Parity=UART_PARITY_NONE;
        break;
      }

      huart2.Init.WordLength=UART_WORDLENGTH_8B;
      HAL_UART_Init(&huart2);
}
break;

配置完成後,在串口調試助手中修改波特率,可該改變對應串口數據輸出波特率,實測1.5M波特率可正常運行。
在這裏插入圖片描述

4.5 串口接收數據

在前面部分已經完成了USB轉串口的發送部分,還有USB轉串口的接收部分未完成。
該部分實現思路爲在串口中斷中接收數據,然後將數據發送至USB。
不過由於USB協議並不是實時發送,經過測試兩次連續調用CDC_Transmit_FS小於100us將導致數據丟包,.並且由於USB緩衝區大小原因,一次性發送或接收大量數據將會嚴重丟包。
故使用循環隊列對發送接收數據進行緩衝,在發送和接收數據時先進入緩衝區,然後使用定每隔500us定時將緩衝區數據分包發送。

附件

如果感覺寫的還不錯的話,給我點個贊或者github來一個star吧!😊

github下載
CSDN下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章