周所周知,#STM32 有著板載#USB 接口,之前我們利用STM32的USB實現(xiàn)VCP(虛擬串口)來代替原始串口實現(xiàn)串口。
但是USB的功能還有很多很多,本期我們來介紹利用STM32的USB實現(xiàn)鼠標(biāo)輸入功能。
硬件平臺采用STM32F407ZGT6
1、HID
#HID(Human Interface Device)全稱#人機接口設(shè)備,是一類允許人類與計算機進行交互的設(shè)備。我們常用的鼠標(biāo)、鍵盤、觸摸屏都屬于HID設(shè)備。它定義了輸入/輸出數(shù)據(jù)的格式和協(xié)議,不需要專用驅(qū)動就能識別。
例如目前在用的鼠標(biāo)接入電腦時,系統(tǒng)會將其識別為HID鼠標(biāo)。
HID設(shè)備以中斷方式與主機通信,定時上報數(shù)據(jù)主機通過GetReport/SetReport與設(shè)備進行數(shù)據(jù)交互數(shù)據(jù)采用HID報告(HIDReport)格式,描述鼠標(biāo)移動、按鍵狀態(tài)等
要在STM32中實現(xiàn)鼠標(biāo)輸入,就是STM32作為主機HOST來獲取鼠標(biāo)設(shè)備的HIDReport。下面介紹#CubeMX?的配置和部分代碼。
2、CubeMX配置
首先開啟一組USART用來輸出調(diào)試信息,接著開啟USB_OTG_FS功能,模式選擇為主機模式(Host_Only)。
由于對USB設(shè)備的性能要求不高,因此不用選擇USB_OTG_HS而選擇FS即可。
在拓展包中的USB_HOST中,為FS選擇HID設(shè)備。
對于下方的HID配置詳細解釋如下:
條目 | 作用 |
USBH_MAX_NUM_ENDPOINTS | USB 接口支持的最大端點 |
USBH_MAX_NUM_INTERFACES | 每個 USB 設(shè)備支持的最大接口
數(shù)量 |
USBH_MAX_NUM_SUPPORTED_CLASS | 最大 USB 設(shè)備類數(shù)量 |
USBH_MAX_NUM_CONFIGURATION | USB 主機庫支持的最大配置數(shù)量 |
USBH_KEEP_CFG_DESCRIPTOR | 保留 USB 設(shè)備的配置描述符 |
USBH_MAX_SIZE_CONFIGURATION | 設(shè)備配置描述符最大允許大小 |
USBH_MAX_DATA_BUFFER | 主機庫在內(nèi)存中分配的數(shù)據(jù)緩沖區(qū)的最大大小 |
USBH_DEBUG_LEVEL | 調(diào)試信息的輸出級別 |
這里其他的都選擇默認(rèn)配置,只有最后的調(diào)試信息輸出級別,推薦使用級別2.
而且需要注意的是,USB庫的調(diào)試信息使用printf輸出,這要求我們對系統(tǒng)進行串口重定向。大家可以參考#串口重定向?那期的文章基于HAL庫和CubeMX的STM32 串口通信以及重定向?(點擊連接跳轉(zhuǎn))。
由于我的板子需要單獨開啟USB電源,因此需要開啟一個GPIO來作為USB電源控制。
將一個GPIO設(shè)置為OutPut模式之后,同樣的可以在USB_HOST中配置電源控制為GPIO:Output。
3、時鐘要求
這個晶振時鐘也是在CubeMX中配置的,但是這里要單獨強調(diào)一下,否則會導(dǎo)致工作失敗。
USB正常工作要求時鐘為48MHZ,但是CubeMX默認(rèn)工程中大家需要注意修改HSE外部高速時鐘的輸入和自己芯片的實際輸入是否一致,否則可能會導(dǎo)致工作失敗。
4、文件結(jié)構(gòu)和使用
CubeMX生成工程之后會出現(xiàn)USB主機庫,這里是不需要我們修改什么東西的,大家把目光著重放到main.c中。
? while (1)
? {
? ??/* USER CODE END WHILE */
? ? MX_USB_HOST_Process();
? ??/* USER CODE BEGIN 3 */
? }
這個函數(shù)是處理 USB 主機的狀態(tài)機和相關(guān)事件,是 USB 主機庫運行機制的核心部分,負(fù)責(zé)推進 USB 主機的狀態(tài)機,使主機能夠在不同狀態(tài)之間切換,如未初始化、已初始化、已連接設(shè)備、已配置設(shè)備等,確保能根據(jù)設(shè)備連接狀態(tài)執(zhí)行相應(yīng)的操作。
接著我們在頭文件中包含下面這個頭文件
#include"usbh_hid.h"
之后我們編寫鼠標(biāo)回調(diào)函數(shù):
voidUSBH_HID_EventCallback(USBH_HandleTypeDef *phost)
{
? ? HID_MOUSE_Info_TypeDef *mouse_info = USBH_HID_GetMouseInfo(phost);
if?(mouse_info != NULL)
? ? {
printf("X: %dtY: %dtButtons: L:%d M:%d R:%drn",
? ? ? ? ? ? ? ?mouse_info->x,
? ? ? ? ? ? ? ?mouse_info->y,
? ? ? ? ? ? ? ?mouse_info->buttons[0],
? ? ? ? ? ? ? ?mouse_info->buttons[1],
? ? ? ? ? ? ? ?mouse_info->buttons[2]);
? ? }
}
每當(dāng)我們運動鼠標(biāo)的時候,這個中斷回調(diào)函數(shù)就會觸發(fā),因此我們可以獲得鼠標(biāo)運動狀態(tài)。
4、鼠標(biāo)屏幕相結(jié)合
我們在回調(diào)函數(shù)中將鼠標(biāo)運動狀態(tài)累加起來就可以得到鼠標(biāo)的位置了,接下來我們設(shè)置一下當(dāng)按下鼠標(biāo)左鍵時候,可以在屏幕中畫圖。按下鼠標(biāo)右鍵的時候可以清空畫布。