USB的協議其實是很復雜的,如果要深入學習估計要一兩年才能熟悉透。本文主要是講如何使用官方已經寫好的庫進行二次開發,以達到我們自己使用的目的。我們知道USB可以用來接U盤,聲卡,讀卡器,鼠標鍵盤等等,這里主要是講USB接口用來當虛擬串口使用,這個VCP(虛擬串口)是通過USB的CDC(通信設備類)類來實現的,本文是基於CPU是STM32F4的USB來講解的:
1.安裝和使用STM32 CubeMx軟件:
該軟件是STM官方提供的圖形化配置底層驅動的軟件,可生成工程與代碼,可去官方下載安裝:
1)安裝后如下界面:
2)接下來再點擊菜單欄中的help選擇安裝庫:
我們使用的是F4的底層庫,該庫為HAL庫,不再是以前STM32的標准庫,大約到2014年左右,ST在標准庫的基礎上又推出了HAL庫。實際上,HAL庫和標准庫本質上是一樣的,都是提供底層硬件操作API,而且在使用上也是大同小異。有過標准庫基礎的同學對HAL庫的使用也很容易入手。個人認為ST官方之所以這幾年大力推廣HAL庫,是因為HAL的結構更加容易整合STM32Cube,而STM32CubeMX是ST這幾年極力推薦的程序生成開發工具。所以這兩年新出的STM32芯片,ST直接只提供HAL庫。在新型的STM32芯片中,用HAL庫逐步淘汰標准庫。
3)選擇自己的mcu型號,選擇好后雙擊打開:
4)配置RCC,USB等:
5)配置時鍾樹,根據自己硬件情況:
6)點擊工具欄的生成代碼工具,注意填寫的堆棧空間要大一點,防止空間不夠的意外:
點擊OK后生成工程代碼,可以下載測試驗證,接下我們來分析生成的代碼,並修改成自己想要的:
2.分析與修改代碼:
1)生成的代碼我們首先來看,初始化USB功能的
點擊其中的Init
這里是關鍵,主要的功能是把CDC類的功能和我們用戶要調用的_fops_FS函數都注冊到USB的設備類里,這樣在USB內核運行的時候就會調動我們注冊進去的函數,點擊USBD_Interface_fops_FS進去,這里面的函數指針 指向的函數就是我們需要使用和修改的了
函數在如下文件中:
2)我們修改這個文件:
首先在里面定義個串口屬性的結構體:
USBD_CDC_LineCodingTypeDef linecoding =
{
USB_VIRTUAL_COM_BAUDRATE, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};
然后修改CDC_Control_FS函數:
{
/* USER CODE BEGIN 5 */
switch (cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
linecoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
linecoding.format = pbuf[4];
linecoding.paritytype = pbuf[5];
linecoding.datatype = pbuf[6];
/* Add your code here */
break;
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(linecoding.bitrate);
pbuf[1] = (uint8_t)(linecoding.bitrate >> 8);
pbuf[2] = (uint8_t)(linecoding.bitrate >> 16);
pbuf[3] = (uint8_t)(linecoding.bitrate >> 24);
pbuf[4] = linecoding.format;
pbuf[5] = linecoding.paritytype;
pbuf[6] = linecoding.datatype;
/* Add your code here */
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
}
return (USBD_OK);
/* USER CODE END 5 */
}
3)基本配置完畢,接下來就是發送和接收的,發送主要調用CDC_Transmit_FS函數:
示例:
很簡單吧,由於我們的USB是從端,PC是主端,這里發送最后是寫入到一個BUF里,PC會主動過來查詢並讀取.
繼續看接收,接收的我們在CDC_Receive_FS函數加入自己的代碼即可
示例:
到此,我們就完成了USB的配置,發送,接收等,最后看下效果:
PC裝上stm的官方USB VCP驅動,然后連上電腦:
通信結果OK: