1. 開(kāi)發(fā)環(huán)境
使用stm32f103c8t6,HAL庫(kù),使用CUBE自帶的USB庫(kù)。工程使用vscode+gcc編譯,工程文件在文末鏈接下載,提供makefile和keil兩個(gè)版本。
2. 功能介紹
使用stm32 USB功能完成USB轉(zhuǎn)串口功能,使用引腳配置如下:
使用USART1作為調(diào)試信息輸出,USART2作為串口輸出,LED為系統(tǒng)指示。
3. CubeMX 配置
設(shè)置系統(tǒng)時(shí)鐘為72MHZ,調(diào)試串口UASART1波特率為921600(選擇高波特率,少占用中斷時(shí)間),USART2波特率默認(rèn)為115200,開(kāi)啟中斷。
選擇USB Device功能,速度為默認(rèn)全速USB設(shè)備12MHZ,并使能USB_DEVICE庫(kù),選擇Virtual Port Com (虛擬串口,VPC),使用默認(rèn)配置。
?
設(shè)置系統(tǒng)時(shí)鐘為72MHZ,然后生成工程。
4.軟件部分
使用cube生成的代碼編譯下載后,將USB插入電腦,在電腦設(shè)備管理器中將顯示新的串口設(shè)備(使用STM32的USB VPC時(shí)需要對(duì)應(yīng)的驅(qū)動(dòng)程序,驅(qū)動(dòng)在程序也在文末的鏈接中)
在串口調(diào)試助手中,可打開(kāi)或關(guān)閉串口,不過(guò)此時(shí)還沒(méi)有任何功能。
4.1 發(fā)送函數(shù)
接下來(lái)進(jìn)行功能配置,虛擬串口的主要配置代碼在 src->usbd_cdc_if.c中,其中幾個(gè)重要函數(shù)為:
?
?
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);函數(shù)用于向USB VPC發(fā)送數(shù)據(jù),Buf為待發(fā)送的數(shù)據(jù)緩沖區(qū)地址,Len為待發(fā)送數(shù)據(jù)長(zhǎng)度。
?
?
/*示例一,在main函數(shù)中的while循環(huán)中輸入下列代碼 ????????在連接打開(kāi)串口助手后可接收到數(shù)據(jù)*/ while(1) { ????CDC_Control_FS((uint8_t?*)"hello ",6); ????HAL_Delay(1000); }
?
?
在編譯下載后,將USB插入電腦,使用川酷哦調(diào)試助手將會(huì)每秒接收到一次"hello"。
4.2 USB上電重新枚舉
在使用上面代碼的時(shí)候存在一個(gè)問(wèn)題:每次下載完程序后都需要重新拔插一次USB才可以識(shí)別串口,這是由于芯片在下載完程序后沒(méi)有重新枚舉所導(dǎo)致的。需要在設(shè)備上電后對(duì)USB進(jìn)行重新枚舉即可,使用方法為將USB DP(PA12)引腳拉低一段時(shí)間后即可。
?
?
/*USB?重新枚舉函數(shù)*/ 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); }
?
?
該函數(shù)使用時(shí)應(yīng)放在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();
?
?
重新下載上電后,可發(fā)現(xiàn)串口已重新枚舉識(shí)別,只需重新開(kāi)啟串口調(diào)試助手即可。
4.3 USB接收函數(shù)
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)為USB接收回調(diào)函數(shù),在USB VPC接收到數(shù)據(jù)時(shí),會(huì)進(jìn)入該函數(shù),在該函數(shù)中進(jìn)行USB數(shù)據(jù)接收處理即可。
USB轉(zhuǎn)串口設(shè)備,需要在stm32的USB端接收到數(shù)據(jù)后轉(zhuǎn)發(fā)到stm32 串口端
?
?
static?int8_t?CDC_Receive_FS(uint8_t*?Buf,?uint32_t?*Len) { ??/*?USER?CODE?BEGIN?6?*/ ??extern?UART_HandleTypeDef?huart2,huart1; ??/*將USB接收到的數(shù)據(jù)轉(zhuǎn)發(fā)到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虛擬的串口中發(fā)送數(shù)據(jù),可在stm32的USART2的TX引腳(PA2)收接收到數(shù)據(jù)。
4.4 設(shè)置USB虛擬串口波特率
在前面的發(fā)送和接收中,均不能進(jìn)行波特率設(shè)置,usb發(fā)送到串口的數(shù)據(jù)波特率為默認(rèn)值115200。USB的波特率配置在static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)函數(shù)中,cmd為usb cdc的控制命令,pbuf為數(shù)據(jù)接收指針,length為數(shù)據(jù)長(zhǎng)度。
當(dāng)cmd為0x20時(shí)為設(shè)置虛擬串口波特率;
其接收到的數(shù)據(jù)一共七位,數(shù)據(jù)格式定義(小端模式)如下:
由于stm32芯片并不支持這么多串口參數(shù),在無(wú)對(duì)應(yīng)參數(shù)時(shí)使用默認(rèn)配置。在接收到修改波特率命令后修改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;
?
?
配置完成后,在串口調(diào)試助手中修改波特率,可該改變對(duì)應(yīng)串口數(shù)據(jù)輸出波特率,實(shí)測(cè)1.5M波特率可正常運(yùn)行。
4.5 串口接收數(shù)據(jù)
在前面部分已經(jīng)完成了USB轉(zhuǎn)串口的發(fā)送部分,還有USB轉(zhuǎn)串口的接收部分未完成。
該部分實(shí)現(xiàn)思路為在串口中斷中接收數(shù)據(jù),然后將數(shù)據(jù)發(fā)送至USB。
不過(guò)由于USB協(xié)議并不是實(shí)時(shí)發(fā)送,經(jīng)過(guò)測(cè)試兩次連續(xù)調(diào)用CDC_Transmit_FS小于100us將導(dǎo)致數(shù)據(jù)丟包,.并且由于USB緩沖區(qū)大小原因,一次性發(fā)送或接收大量數(shù)據(jù)將會(huì)嚴(yán)重丟包。
故使用循環(huán)隊(duì)列對(duì)發(fā)送接收數(shù)據(jù)進(jìn)行緩沖,在發(fā)送和接收數(shù)據(jù)時(shí)先進(jìn)入緩沖區(qū),然后使用定每隔500us定時(shí)將緩沖區(qū)數(shù)據(jù)分包發(fā)送。
編輯:黃飛
?
評(píng)論
查看更多