目的
USB是目前最流行的接口,現(xiàn)在很多個(gè)人用的電子設(shè)備也都是USB設(shè)備。目前大多數(shù)單片機(jī)都有USB接口,使用USB接口作為HID類設(shè)備來使用是非常常用的,比如USB鼠標(biāo)、鍵盤都是這一類。這篇文章將簡(jiǎn)單介紹使用STM32實(shí)現(xiàn)相關(guān)內(nèi)容。
基礎(chǔ)說明
一些USB相關(guān)最基礎(chǔ)的內(nèi)容可以參考下面文章中 基礎(chǔ)說明 部分:
《STM32 USB使用記錄:使用CDC類虛擬串口(VCP)進(jìn)行通訊》
USB設(shè)備通過一系列的描述符來描述自己,告訴主機(jī)自己是什么設(shè)備、具有什么功能等。描述符一些基本的說明如下:
- 每一個(gè)USB設(shè)備只有一個(gè)設(shè)備描述符,主要向主機(jī)說明設(shè)備類型、端點(diǎn)0最大包長(zhǎng)、設(shè)備版本、配置數(shù)量等等;
- 每一個(gè)USB設(shè)備至少有一個(gè)或者多個(gè)配置描述符,但是主機(jī)同一時(shí)間只能選擇某一種配置,標(biāo)準(zhǔn)配置描述符主要向主機(jī)描述當(dāng)前配置下的設(shè)備屬性、所需電流、支持的接口數(shù)、配置描述符集合長(zhǎng)度等等;
- 主機(jī)在獲取配置描述符集合的時(shí)候會(huì)先獲取一次標(biāo)準(zhǔn)配置描述符,然后根據(jù)里面的配置描述符集合長(zhǎng)度屬性值獲取配置描述符集合的所有描述符信息,配置描述符集合有標(biāo)準(zhǔn)配置描述符、接口描述符、端點(diǎn)描述符、HID描述符;
- 每一個(gè)USB配置下至少有一個(gè)或者多個(gè)接口描述符,接口描述符主要說明設(shè)備類型、此接口下使用的端點(diǎn)數(shù)(不包括0號(hào)號(hào)端點(diǎn)),一個(gè)接口就是實(shí)現(xiàn)一種功能,實(shí)現(xiàn)這種功能可能需要端點(diǎn)0就夠了,可能還需要其它的端點(diǎn)配合;
- 每一個(gè)USB接口下至少有0個(gè)或者多個(gè)端點(diǎn)描述符,端點(diǎn)描述符用來描述符端點(diǎn)的各種屬性;
- 端點(diǎn)是實(shí)現(xiàn)USB設(shè)備功能的物理緩沖區(qū)實(shí)體,USB主機(jī)和設(shè)備是通過端點(diǎn)進(jìn)行數(shù)據(jù)交互的;
- 一個(gè)USB設(shè)備有一個(gè)或多個(gè)配置描述符。每個(gè)配置有一個(gè)或多個(gè)接口,每個(gè)接口有零個(gè)或多個(gè)端點(diǎn);
- 字符串描述符就是用字符串描述一個(gè)設(shè)備的一些屬性,描述的屬性包括設(shè)備廠商名字、產(chǎn)品名字、產(chǎn)品序列號(hào)、各個(gè)配置名字、各個(gè)接口名字;
- HID描述符只有HID設(shè)備才會(huì)存在;
- HID設(shè)備至少有一個(gè)報(bào)告描述符;
- 報(bào)告描述符主要作用就是描述主機(jī)和HID設(shè)備交互的數(shù)據(jù),向主機(jī)說明這些數(shù)據(jù)中哪些位是用來做什么用的;
HID類演示
使用 STM32CubeIDE
或者 STM32CubeMX
可以方便的建立 STM32 USB HID 的項(xiàng)目。這里直接進(jìn)行配置演示,圖中只列出最關(guān)鍵的內(nèi)容。
啟用USB接口:
啟用USB設(shè)備中間件:
需要注意的是根據(jù)H750芯片數(shù)據(jù)手冊(cè)中說明,這里USB時(shí)鐘推薦使用48MHz,如果是使用 USB HS 外接PHY的話,時(shí)鐘使用60MHz:
上面配置下默認(rèn)生成的是 鼠標(biāo)設(shè)備
在生產(chǎn)的代碼中的 main.c
中添加幾行代碼即可測(cè)試效果:
int main(void)
{
HAL_Init();
MPU_Config();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
// 默認(rèn)配置生成的鼠標(biāo)設(shè)備每次向電腦發(fā)送四個(gè)字節(jié)數(shù)據(jù),這些內(nèi)容是在HID設(shè)備的報(bào)告描述符中定義的
// buff[0] bit0 bit1 bit2 分別代表 左鍵、右鍵、中鍵
// buff[1] X 軸位移 (-127~127)
// buff[2] Y 軸位移 (-127~127)
// buff[3] Wheel 滾輪 (-127~127)
uint8_t buff[4] = {0, 10, 0 ,0}; // X軸設(shè)置了位移量
while (1)
{
extern uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);
extern USBD_HandleTypeDef hUsbDeviceFS;
USBD_HID_SendReport(&hUsbDeviceFS, buff, 4); // 發(fā)送數(shù)據(jù)
HAL_Delay(1000); // 按照buff中的值,每秒電腦上的光標(biāo)將向右移動(dòng)一次
}
}
記住上圖左邊幾個(gè)文件,后面會(huì)介紹其中一些內(nèi)容。
編譯程序下載到芯片中就可以查看效果了,每隔一秒光標(biāo)會(huì)向右移動(dòng)一次。
可以使用 USB Device Tree Viewer
工具來查看電腦上的USB設(shè)備:
https://www.uwe-sieber.de/usbtreeview_e.html
代碼分析
這里只是簡(jiǎn)單做個(gè)介紹。
首先是 main.c
中執(zhí)行的 MX_USB_DEVICE_Init()
函數(shù),該函數(shù)在 usb_device.c
文件中,函數(shù)內(nèi)容如下:
void MX_USB_DEVICE_Init(void)
{
// 初始化USB設(shè)備
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS)
// 初始化USB設(shè)備具體類型(這里是HID設(shè)備)
USBD_RegisterClass(&hUsbDeviceFS, &USBD_HID)
// 啟動(dòng)USB
USBD_Start(&hUsbDeviceFS)
}
FS_Desc
結(jié)構(gòu)體在 usbd_desc.c
文件中定義,看名字就可以了解是前面基礎(chǔ)說明中提到的各種描述符:
USBD_DescriptorsTypeDef FS_Desc =
{
USBD_FS_DeviceDescriptor
, USBD_FS_LangIDStrDescriptor
, USBD_FS_ManufacturerStrDescriptor
, USBD_FS_ProductStrDescriptor
, USBD_FS_SerialStrDescriptor
, USBD_FS_ConfigStrDescriptor
, USBD_FS_InterfaceStrDescriptor
};
USBD_HID
結(jié)構(gòu)體的相關(guān)內(nèi)容主要都在 usbd_hid.h / usbd_hid.c
文件中,這兩個(gè)文件就是庫(kù)中默認(rèn)的HID鼠標(biāo)設(shè)備了,其中有HID描述符和報(bào)告描述符等。
這里的配置描述符描述設(shè)備為HID的鼠標(biāo)、設(shè)備電流、輸入輸出端點(diǎn)等:
/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor
describing the configuration */
#if (USBD_SELF_POWERED == 1U)
0xE0, /* bmAttributes: Bus Powered according to user configuration */
#else
0xA0, /* bmAttributes: Bus Powered according to user configuration */
#endif /* USBD_SELF_POWERED */
USBD_MAX_POWER, /* MaxPower (mA) */
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
0, /* iInterface: Index of string descriptor */
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x11, /* bcdHID: HID Class Spec release number */
0x01,
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
0x22, /* bDescriptorType */
HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType:*/
HID_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
HID_EPIN_SIZE, /* wMaxPacketSize: 4 Bytes max */
0x00,
HID_FS_BINTERVAL, /* bInterval: Polling Interval */
/* 34 */
};
報(bào)告描述符就描述了設(shè)備收發(fā)數(shù)據(jù)結(jié)構(gòu)信息等內(nèi)容:文章來源:http://www.zghlxwxcb.cn/news/detail-600521.html
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x02, /* Usage (Mouse) */
0xA1, 0x01, /* Collection (Application) */
0x09, 0x01, /* Usage (Pointer) */
0xA1, 0x00, /* Collection (Physical) */
0x05, 0x09, /* Usage Page (Button) */
0x19, 0x01, /* Usage Minimum (0x01) */
0x29, 0x03, /* Usage Maximum (0x03) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x95, 0x03, /* Report Count (3) */
0x75, 0x01, /* Report Size (1) */
0x81, 0x02, /* Input (Data,Var,Abs) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x05, /* Report Size (5) */
0x81, 0x01, /* Input (Const,Array,Abs) */
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x30, /* Usage (X) */
0x09, 0x31, /* Usage (Y) */
0x09, 0x38, /* Usage (Wheel) */
0x15, 0x81, /* Logical Minimum (-127) */
0x25, 0x7F, /* Logical Maximum (127) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x03, /* Report Count (3) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0xC0, /* End Collection */
0x09, 0x3C, /* Usage (Motion Wakeup) */
0x05, 0xFF, /* Usage Page (Reserved 0xFF) */
0x09, 0x01, /* Usage (0x01) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x02, /* Report Count (2) */
0xB1, 0x22, /* Feature (Data,Var,Abs,NoWrp) */
0x75, 0x06, /* Report Size (6) */
0x95, 0x01, /* Report Count (1) */
0xB1, 0x01, /* Feature (Const,Array,Abs,NoWrp) */
0xC0 /* End Collection */
};
總結(jié)
這篇文章到這里先告一段落了,看似什么都沒講,因?yàn)檫@篇文章的目的是對(duì) HID 整體有個(gè)印象。大部分時(shí)候?qū)嶋H開發(fā)中我們并不會(huì)去使用默認(rèn)的鼠標(biāo)類型HID設(shè)備,而是使用自定義的HID設(shè)備(Custom Human Interface Device Class)。而自定義設(shè)備中像是報(bào)告描述符等一些內(nèi)容需要自行編輯,用來實(shí)現(xiàn)特定功能需求,比如HID設(shè)備用作雙向透?jìng)鞯?。這些內(nèi)容將在下一篇文章中進(jìn)行介紹。文章來源地址http://www.zghlxwxcb.cn/news/detail-600521.html
到了這里,關(guān)于STM32 USB使用記錄:HID類設(shè)備(前篇)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!