STC8H開發(九): STC8H8K64U模擬USB HID外設
- 2022 年 2 月 9 日
- 筆記
- Mobile/Embed, STC8H, MCS-51
目錄
- STC8H開發(一): 在Keil5中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(二): 在Linux VSCode中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(三): 基於FwLib_STC8的模數轉換ADC介紹和演示用例說明
- STC8H開發(四): FwLib_STC8 封裝庫的介紹和使用注意事項
- STC8H開發(五): SPI驅動nRF24L01無線模組
- STC8H開發(六): SPI驅動ADXL345三軸加速度檢測模組
- STC8H開發(七): I2C驅動MPU6050三軸加速度+三軸角速度檢測模組
- STC8H開發(八): NRF24L01無線傳輸音頻(對講機原型)
- STC8H開發(九): STC8H8K64U模擬USB HID外設
關於USB
通用串列匯流排(Universal Serial Bus, 簡稱USB), 是當前使用最廣泛的外設介面. 因為供電簡單, 支援熱插拔, 擴展埠簡單, 傳輸方式多樣化, 兼容性好, 支援的外設類型豐富, 基本成為PC標配.
STC MCU從STC15開始支援USB ISP, 但是僅僅用於下載和調試, 可在程式碼中配置的USB外設功能直到STC8H8K64U才出現. USB標準規範包括USB1.0, USB1.1, USB2.0, USB3.0 以及2019年9月發布的 USB4TM, STC8H8K64U 支援的是 USB2.0 標準.
USB的物理連接結構
USB系統由一個USB Host, 一個或多個USB Hub, 一個或多個USB Node 組成. USB的物理連接是層次性的星型結構, 在系統中, 有且僅有一個USB主機, USB Hub實際上就是一個具有特殊功能的USB設備. 所有的USB設備都連接在USB Hub上, 同時Hub有責任為每個連接其上的USB Node 提供 +5V 和 500mA 的電源.
USB匯流排採用的是樹形結構、主從工作模式. USB主機根據各個設備的屬性, 周期性訪問各個設備. 而USB設備則是被動響應USB主機的訪問請求, 這樣避免了USB設備主動發送數據導致的匯流排衝突. 當然, 這樣就導致沒有USB主機的情況下 USB 設備之間無法通訊. USB OTG(USB On-The-Go)技術用於解決此問題, 拓展了USB在嵌入式設備, 如手機、PDA等方面的應用.
USB系統的分層結構
在系統設計和邏輯連接關係上USB匯流排系統具有明確的分層結構. USB設備與主機的驅動/應用程式通訊, 是通過特定的USB端點來實現的.
整個USB系統可以分為USB匯流排介面層, USB設備層, 功能層
- USB匯流排介面層
USB匯流排介面層主要用於實現USB主機和USB設備之間的數據傳輸, 實際的數據流是在此層運行的. USB規範中 , USB匯流排介面NRZI編碼(反向歸零編碼)來傳輸數據. 編碼的過程是自動進行的, 由USB系統硬體完成. - USB設備層
USB設備層主要用於管理USB設備, 包括分配USB地址、讀取設備描述報文等. 在這一層中, USB主機可以獲取USB設備的各種屬性或能力. 這部分的功能, USB主機通過驅動軟體來完成, 而USB設備的韌體層也需要編寫對應的程式碼進行支援. - 功能層
功能層主要負責數據傳輸, 由USB設備的功能單元和對應的USB主機程式實現. 按照雙方通訊的類型, 可分為- 控制傳輸(Control Transfers). 主要用於傳輸少了的對時間和速率沒有要求的數據, 一般用於USB主機讀取或設置USB設備的配置資訊, 或者其他的簡單操作.
- 中斷傳輸(Interrupt Transfers). 主要用於傳輸少了對傳輸時間具有周期性要求的數據, 在滑鼠、鍵盤等HID設備中經常使用.
- 批量傳輸(Bulk Transfers). 用於傳輸大量的、對傳輸時間和速率沒有嚴格要求的數據.
- 實時傳輸(Isochronous Transfers). 用於傳輸大量的、且傳輸時間具有周期性、速率恆定的數據
在USB HID設備的傳輸中主要使用的是控制傳輸.
USB的命令(USB Device Request)
USB規範定義了設備請求(USB Device Request), 以更好地完成USB主機對匯流排上所有USB設備的統一控制. 此設備請求由USB主機發往USB設備. USB命令包括USB標準命令, 類命令, 廠商命令. 這些命令的格式都是相同的, 如下表所示.
| 偏移 | 欄位 | 長度 | 數值 | 描述 |
|---|---|---|---|---|
| 0 | bmRequesType | 1 | 點陣圖 | D7: 數據的傳輸方向: 0=主機->設備, 1=設備->主機 |
| D6-D5: 命令的類型, 0=標準命令 1=類命令 2=廠商命令 3=保留 | ||||
| D4-D0: 接收對象 0=設備 1=介面 2=端點 3=其他 4…31=保留 | ||||
| 1 | bRequest | 1 | 值 | 命令的序號 |
| 2 | wValue | 2 | 值 | 根據不同的命令, 含義也不同 |
| 4 | wIndex | 2 | 索引或偏移 | 根據不同的命令, 含義不同, 主要用於傳送索引或者偏移 |
| 6 | wLength | 2 | 如果有數據階段, 此欄位為數據的位元組數 |
標準命令是每種USB設備都要支援的, 類命令則與USB設備所述類有關, 比如USB HID設備有HID類特有的命令, 如Get_Report、SetReport等.
USB標準命令
USB 1.1的規範中, 規定了11種USB標準命令, 用來完成各種目的. 根據不同的命令, 相應的欄位含義也有所不同. 下表列出了11個USB標準命令的功能.
| 命令 | 請求號 | 功能描述 |
|---|---|---|
| Get_Status | 0x00 | 讀取USB設備、介面或者埠的狀態 |
| Clear_Feature | 0x01 | 清除或禁止USB設備、介面或端點的某些特徵 |
| Set_Feature | 0x03 | 設置或使能USB設備、介面或端點的某些特徵 |
| Set_Address | 0x05 | 分配USB設備地址 |
| Get_Descriptor | 0x06 | 讀取描述報文 |
| Set_Descriptor | 0x07 | 更新已有的描述報文或添加新的描述報文 |
| Get_Configuration | 0x08 | 讀取USB設備的當前配置值 |
| Set_Configuration | 0x09 | 為USB設備選擇一個合適的配置值 |
| Get_Interface | 0x0A | 獲得設備介面當前工作的選擇設置值 |
| Set_Interface | 0x0B | 激活USB設備的某個介面 |
| Synch_Frame | 0x0C | 設置並報告端點的同步幀號 |
在USB規範中, 對於這些標準的USB命令, 所有的USB設備必須都支援, 並能夠對命令進行響應. 如果不需要對命令進行操作, 也必須準備一個空的響應. 除了這些標準的USB命令, 對於不同的類, 也有類相關的USB命令. 比如人機介面類設備有Set_Report、Get_Report等命令, 集線器類設備有GetHubStatus、GetBusState等命令. 在開發相應類設備的時候, 也需要熟悉這些類本身特有的USB命令.
下表是Get_Descriptor命令的結構
| 偏移 | 欄位 | 內容 |
|---|---|---|
| 0 | bmRequesType | 值為10000000B, 設備到主機 |
| 1 | bRequest | GET_DESCRIPTOR, 0x06 |
| 2 | wValue | 描述報文的類型和描述報文的索引值 |
| 4 | wIndex | 0或語言標識(LANGID) |
| 6 | wLength | 描述報文的長度 |
- Get_Descriptor命令用來獲取USB設備的各種描述報文, 包括設備描述報文、配置描述報文、介面描述報文、端點描述報文和字元串描述報文.
- 需要獲取的描述報文類型, 由wValue欄位給出. wValue由兩個位元組組成, 高位元組表示描述報文的類型, 低位元組表示描述報文的索引值.
- wIndex欄位除去獲取字元串描述報文之外, 其他情況下設置為0. 獲得字元串描述報文的過程分為兩步: 第一次發送命令後獲得語言標識;第二次發送命令時, 將語言標識賦給wIndex欄位, 需要獲取的字元串描述報文的索引值賦給wValue欄位, 即可獲得所需要的字元串.
- Get_Descriptor命令中的欄位wLength, 表示描述報文的位元組長度, 由USB主機指定. 當指定wLength比實際的描述報文長度小時, USB設備嚴格按照主機指定的位元組長度返回描述報文資訊;當wLength比實際的描述報文長度大時, USB設備值返回描述報文長度的資訊. 比如在訪問配置描述報文時, USB主機不清楚配置資訊的總長, 可以將Get_Descriptor命令中的wLength設置為4, 得到配置描述報文中wTotalLength. 然後, 重新發送Get_Descriptor命令, 此時將wLength設置為wTotalLength的值, 從而獲得整個配置描述報文資訊.
USB HID的類命令
HID設備除了支援標準的USB命令外, 還支援6個HID特定的類命令, 如下表所示.
| 命令 | 請求號 | 功能描述 |
|---|---|---|
| Get_Report | 0x01 | USB主機接收HID設備發來的報告 |
| Get_Idle | 0x02 | 用於讀取HID設備當前空閑速率 |
| Get_Protocol | 0x03 | 用於讀取HID設備的協議值 |
| Set_Report | 0x09 | USB主機向HID設備發送報告 |
| Set_Idle | 0x0A | 用於設置HID設備的空閑速率 |
| Set_Protocol | 0x0B | 用於設置HID設備的協議值 |
HID的類命令, 其數據結構與USB的標準命令類似, 而且也是採用控制傳輸發送的. HID示例中主要用到了 Get_Report 和 Set_Report 兩個命令
Get_Report命令
用於獲取HID設備發送來的報告, 它主要在HID設備初始化和讀取HID報告時使用. 此命令是所有HID設備都必須支援的, 其結構如下所示.
| 偏移 | 欄位 | 內容 |
|---|---|---|
| 0 | bmRequesType | 值為10100001B, 設備到主機 |
| 1 | bRequest | GET_REPORT, 0x01 |
| 2 | wValue | 報告類型及報告ID |
| 4 | wIndex | 用於指明支援此命令的介面號碼 |
| 6 | wLength | 報告長度 |
其中, wValue用來指明報告的類型. 它由兩個位元組組成, 低位元組表示報告ID. 高位元組值為1時, 表示Input報告;值為2時, 表示Output報告;值為3時, 表示Feature報告.
Set_Report命令
用於USB主機向HID設備發送報告數據, 它與Get_Report命令類似, 只是數據傳輸的方向不同. Set_Report命令並不是所有HID設備都必須支援的, 其結構如下所示.
| 偏移 | 欄位 | 內容 |
|---|---|---|
| 0 | bmRequesType | 值為00100001B, 主機到設備 |
| 1 | bRequest | SET_REPORT, 0x09 |
| 2 | wValue | 報告類型及報告ID |
| 4 | wIndex | 用於指明支援此命令的介面號碼 |
| 6 | wLength | 報告長度 |
USB 的描述報文
USB 設備響應命令的內容就是描述報文, 為了方便USB主機對USB設備進行管理, USB-IF對USB設備的功能採用了分層結構, 包括設備層、配置層、介面層和端點層. 這四層的作用分別為
- 設備層. 說明USB設備的主要類型特徵(如設備類別、介面、端點等屬性), 保障設備枚舉過程的正常進行
- 配置層. 選擇不同的失敗配置滿足USB主機對設備功能的選擇, 可選擇複式的設備介面功能, 如圖1展示的選擇滑鼠、鍵盤和遊戲桿的複合功能
- 介面層. 將具體功能分類, 不同的功能對用不同的操作方式
- 端點層. 針對特定的設備功能, 選擇不同的端點, 提供不同的數據管道, 與USB主機進行數據通訊
為了描述USB設備的這些特徵, USB規範定義了相應結構的描述報文, 包括設備描述報文、配置描述報文、介面描述報文、端點描述報文和字元串描述報文等. 下表給出了USB1.1下各種USB描述報文的類型值.
| 類型 | 描述報文 | 描述報文值 |
|---|---|---|
| 標準描述報文 | 設備描述報文(Device Descriptor) | 0x01 |
| 配置描述報文(Configuration Descriptor) | 0x02 | |
| 字元串描述報文(String Descriptor) | 0x03 | |
| 介面描述報文(Interface Descriptor) | 0x04 | |
| 端點描述報文(Endpoint Descriptor) | 0x05 | |
| 類描述報文 | 集線器類描述報文(hub descriptor) | 0x29 |
| 人機介面類描述報文(HID) | 0x21 | |
| 廠商自定義 | 0xFF |
其他版本的USB規範, 還定義了其他類型的描述報文, 比如USB 2.0中的設備限定描述報文(Device_Qualifier), USB 3.2中的二進位設備對象存儲描述報文(Binary Device Object Store, 簡稱BOS)等. 這些內容在部落格中不會涉及, 可在USB-IF的官網下載相關的USB規範文檔了解.
USB主機會發送USB命令給USB設備, GET_DESCRIPTOR 是常用的獲取描述報文命令. USB設備根據命令所要求的, 給出對應的描述報文. 本篇主要講述描述報文的結構.
不管哪種USB設備, 都必須提供標準描述報文, 用於告知主機設備本身的屬性. 以下介紹的內容, 可以使用Bus Hound或USB邏輯分析儀等工具, 去抓取USB設備的識別和通訊包.
設備描述報文
USB的設備描述報文用於表示USB設備的一般資訊, 如製造商ID、產品序列號等. 一個USB設備有且只有一個設備描述報文, 它是USB主機所讀取的第一個描述報文, 其結構如下所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | 數字 | 描述報文位元組數長度(0x12) |
| 1 | bDescriptor | 1 | 常量 | 描述報文的類型(0x01) |
| 2 | bcdUSB | 2 | BCD碼 | USB設備支援的協議版本號 |
| 4 | bDeviceClass | 1 | 類 | 設備類程式碼 |
| 5 | bDeviceSubClass | 1 | 子類 | 子類程式碼, 根據bDeviceClass來定 |
| 6 | bDevicePortocol | 1 | 協議 | 協議碼 |
| 7 | bMaxPacketSize0 | 1 | 數字 | 端點0的最大包長度 |
| 8 | idVendor | 2 | ID | 廠商ID(由USB-IF賦值) |
| 10 | idProduct | 2 | ID | 產品ID(由廠商賦值) |
| 12 | bcdDevice | 2 | BCD碼 | 設備發行號(BCD碼) |
| 14 | iManufacturer | 1 | 索引 | 廠商資訊的字元串描述報文索引值 |
| 15 | iProduct | 1 | 索引 | 產品資訊的字元串描述報文索引值 |
| 16 | iSerialNumber | 1 | 索引 | 設備序列號資訊的字元串描述報文索引值 |
| 17 | bNumConfigurations | 1 | 數字 | 配置描述報文數目 |
設備描述報文結構中的
- bMaxPacketSize0, 它用來告知USB主機設備所支援的最大數據長度.
- bDeviceClass表示設備所述的類別, 如果此值為0, 則表示每一個配置中的每個介面來指明它所屬的類別(即在介面描述報文中給出設備類), 並且各介面獨立工作. 如果此值為0xFF, 則由供應商自定義該設備類. 介於兩者之間的值0x1-0xFE, 表示USB規範中定義的某個設備類, 比如0x03表示HID設備類. 它和bDeviceSubClass、bDeviceProtocol共同規定了設備的類別和採用的協議, 更具體的分類定義, 可以參考USB-IF官網.
- iManufacturer、iProduct和iSerialNumber, 使用字元串描述報文的索引值來進行描述, 索引值為0表示沒有字元串描述報文對其進行描述. 通過此索引值和USB命令Get_Descriptor, 可以得到對應的字元串描述報文.
配置描述報文
USB規範中, USB設備可以有一個或者多個配置描述報文, 每個配置描述報文提供了設備特定的配置. 在設備描述報文中的bNumConfigurations提供了配置描述報文的個數, 任何時刻只有一種配置處於工作狀態.
配置描述報文中提供了在該配置下設備的介面數目, 一個設備的不同配置描述報文可能包含不同數目和特性的設備介面. 圖1中的設備配置1, 就包含了滑鼠功能介面和鍵盤功能介面兩種介面. 此外, 配置描述報文中還會描述設備的供電方式(自供電/匯流排供電)、最大耗電量等資訊. 其結構如下表所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | 數字 | 描述報文的位元組數長度(0x09) |
| 1 | bDescriptorType | 1 | 常量 | 配置描述報文的類型(0x02) |
| 2 | wTotalLength | 2 | BCD碼 | 配置資訊的總長(包括配置、介面、端點和設備類及廠商定義的描述報文) |
| 4 | BnumInterfaces | 1 | 類 | 該設備所支援的介面數目 |
| 5 | bConfigurationValue | 1 | 子類 | 配置值 |
| 6 | iConfiguration | 1 | 協議 | 描述該配置的字元串描述報文索引值 |
| 7 | bmAttributes | 1 | 數字 | 配置特性: D7:保留 D6:自供電 D5:遠程喚醒 D4…0:保留 |
| 8 | MaxPower | 1 | 數字 | 該配置下所需最大匯流排電流(2mA為單位) |
介面描述報文
USB設備的介面是端點的集合, 負責完成該設備的特定功能, 比如數據的輸入和輸出. 介面描述報文用來表示在USB設備中, 各個介面的特性, 包括介面的端點個數、所述的設備類和子類等.
擁有多個介面的USB設備, 如果設備描述報文中描述的bDeviceClass不為0, 則表示介面之間是互斥關係, 否則介面相互獨立, 每個介面有自己的類號、子類號和協議號. 類號、子類號和協議號的定義, 與設備描述報文中的定義是一致的. 介面描述報文的結構如下表所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | 數字 | 描述報文的位元組數長度(0x09) |
| 1 | bDescriptorType | 1 | 常量 | 介面描述報文的類型(0x04) |
| 2 | bInterfaceNumber | 1 | 數字 | 介面號(從0開始) |
| 3 | bAlternateSetting | 1 | 數字 | 可選設置的索引值 |
| 4 | bNumEndpoint | 1 | 數字 | 此介面的端點數量(不計默認端點0) |
| 5 | bInterfaceClass | 1 | 類 | 介面所屬的類值 |
| 6 | bInterfaceSubClass | 1 | 子類 | 介面所屬子類的值 |
| 7 | bInterfaceProtocol | 1 | 協議 | 協議碼, 根據上面的兩個值而定 |
| 8 | iInterface | 1 | 索引 | 表示此介面的字元串描述報文的索引值 |
端點描述報文
USB規範中, 端點描述報文用於指出USB設備端點的特性, 包括其所支援的傳輸類型、傳輸方向等. 端點0沒有端點描述報文, 其他端點必須包含端點描述報文.
端點是設備與主機之間進行數據傳輸的邏輯介面, 除配置使用的端點0為雙向外, 其他均為單向. 端點描述報文描述了數據的傳輸類型、傳輸方向、數據包大小, 以及端點地址, 其結構如下表所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | 數字 | 描述報文的位元組數長度(0x07) |
| 1 | bDescriptorType | 1 | 常量 | 端點描述報文的類型(0x05) |
| 2 | bEndPointAddress | 1 | 端點 | 描述了端點的地址、方向 Bit3…0: 端點號 Bit6…4: 保留, 為0 Bit7: 傳輸方向, 如果是控制端點則忽略 0: 輸出端點(主機到設備) 1: 輸入端點(設備到主機) |
| 3 | bmAttributes | 1 | 點陣圖 | 端點傳輸類型 Bit1…0: 傳送類型 00B=控制傳送 01B=實時傳送 10B=批量傳送 11B=中斷傳送 |
| 4 | wMaxPacketSize | 2 | 數字 | 接收/發送的最大數據包長度 |
| 6 | bInterval | 1 | 數字 | 周期數據傳輸端點的時間間隙 |
字元串描述報文
字元串描述報文是可選的, 它描述了製造商、設備名稱或序列號等資訊. 它使用的是Unicode編碼, 並支援多語言. USB主機要求獲得字元串描述報文時, 需要用一個16位的語言標識出語言類別. 比如, 常用的語言標識1033表示美國英語, 而2052表示中文. 其他的語言標識, 可以在微軟的網站上找到 .
USB主機請求得到某個字元串描述報文時分為兩步, 首先向USB設備發送USB命令 Get_Descriptor, 命令的wIndex欄位設置為0, 設備將返回描述語言標識的字元串描述報文, 然後, USB主機根據需要的語言, 向USB設備發送命令 Get_Descriptor, 在命令對應的欄位中設置字元串的索引值和語言標識, 得到需要的字元串描述報文. 字元串描述報文有兩種格式
第一種用來指明所用的語言標識, 如下表所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | N+2 | 描述報文的位元組數長度(N+2位元組) |
| 1 | bDescriptorType | 1 | 常量 | 字元串描述報文的類型(0x03) |
| 2 | wLANGID[0] | 2 | 數字 | 語言標識(LANGID), 碼0 |
| … | … | … | … | … |
| N | wLANGID[x] | 2 | 數字 | 語言標識(LANGID), 碼x |
第二種為Unicode字元串描述報文, 包含了非NULL結尾的Unicode字元串, 如下表所示.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | N+2 | 描述報文的位元組數長度(N+2位元組) |
| 1 | bDescriptorType | 1 | 常量 | 字元串描述報文的類型(0x03) |
| 2 | bString | N | 數字 | Unicode編碼的字元串 |
在實際編寫程式碼中, 介面描述報文、端點描述報文一般是和配置描述報文在同一數組中的
HID設備的描述報文
示例的USB設備是HID類設備. HID(Human Interface Devices)為人機介面設備, 日常使用的鍵盤、滑鼠等, 都屬於HID設備.
USB規範中, HID類設備的規範為Device Definiton for Human Interface Devices, 每個HID設備都必須符合該規範中對描述報文、傳輸類型等的定義. 另外, USB-IF還提供了HID的用例規範, 名為HID Usage Tables, 定義了HID設備和USB主機之間通訊的HID數據. 所有的 HID 傳輸都是使用默認控制管道或是一個中斷管道, HID 設備必須有一個中斷輸入端點來傳送數據到主機, 中斷輸出端點則不是必需的.
HID設備的標準描述報文同樣遵循上一篇所介紹的內容, 也即擁有各種標準描述報文. 對於HID設備, 其設備描述報文的類程式碼、子類程式碼和協議程式碼都需要設置為0;介面描述報文的類程式碼設為0x03, 子類程式碼為0或者0x01, 協議碼為0、0x01或0x02.
HID設備支援3種類描述報文: HID描述報文、報告描述報文和物理描述報文. 一個USB設備只能包含一個HID描述報文, 可以支援多個報告描述報文, 而物理描述報文是可選的. 在示例中, 只用到了HID描述報文和報告描述報文.
HID描述報文
HID描述報文主要用來識別HID設備通訊時所使用的額外資訊(如HID版本號、報告描述報文長度等), 如下表所示, 給出了HID描述報文的定義結構.
| 偏移 | 域 | 大小 | 值 | 描述 |
|---|---|---|---|---|
| 0 | bLength | 1 | 數字 | 描述報文的長度 |
| 1 | bDescriptorType | 1 | 常量 | 描述報文的類型, 0x21 |
| 2 | bcdHID | 2 | BCD碼 | HID規範版本號(BCD碼) |
| 4 | bCountryCode | 1 | 數字 | 國家程式碼 |
| 5 | bNumDescriptor | 1 | 數字 | 支援的其他類描述報文的數量 |
| 6 | bDescriptorType | 1 | 常量 | 類別描述報文的類型 |
| 7 | wDescriptorLength | 2 | 數字 | 報表描述報文的總長度 |
| 9 | bDescriptorType | 1 | 常量 | 識別描述報文類型的常數, 多個描述報文時使用 |
| 10 | wDescriptorLength | 2 | 數字 | 描述報文總長度, 多個描述報文時使用 |
其中
- bCountryCode 表示的是國家程式碼, 一般將其設置為0就可以了. 0表示的是HID設備不是本土化的, 其他的值可以查看HID規範.
- bDescriptorType 識別HID描述報文附屬的描述報文的類型, 報表描述報文的類型為0x22, 物理描述報文的類型為0x23. 每一個 HID設備都必須至少支援一個報表描述報文. 一個介面可以支援多個報表描述報文, 以及一個或多個實體描述報文.
- HID描述報文的偏移量為9和10的bDescriptorType和wDescriptorLength可以重複存在多個
在USB主機發送標準命令 Get_ Configuration, 獲取配置描述報文的時候, 將按照配置描述報文、介面描述報文、HID描述報文、端點描述報文的順序, 返回數據. 也即主機此時可用獲取到HID描述報文, 可以據其資訊再去獲取相關的描述報文(如報告描述報文).
報告描述報文
HID設備的報告描述報文是一種數據報表, 主要用來定義HID設備和USB主機之間的數據交換格式. 與標準描述報文不同, 它沒有固定的長度, 根據設備不同的用途, 需要準備不同的結構和數據描述.
報告描述報文由多個不同的項目(item)組成, 它有兩種編碼: 短項目(short item)和長項目(long item). 長項目保留給未來使用, 本節不對它進行介紹. HID短項目的位元組格式如下所示.
23 16|15 8|7 4|3 2|1 0|
| -data - | -data --| bTag | bType | bSize |
-
bSize用來指出項目所需要的數據位元組(即data部分的位元組長度), 其值可為0(bSize=0)、1(bSize=1)、2(bSize=2)和4(bSize=3). 注意沒有3個位元組長的數據, 大部分項目只需要1個位元組數據.
-
bType表示項目的類型, 用來表示是主(Main)項目、全局(Global)還是局部(Local)項目. 主項目用來定義報告中數據的種類和格式;局部項目表示所定義只能適用於其下的第一個主項目, 不能擴展到其他主項目;全局項目則適用於其下方所有主項目, 除非被另一個相同標籤的全局項目替代. bType=0時, 表示項目為主項目;bType=1時, 項目為全局項目;bType=2時, 項目為局部項目.
-
bTag為標籤, 用來標記各項目的作用.
-
data部分是可選的, 其長度由bSize決定. 比如集合結束(End Collection)項目, 其值一般為0xC0, 後面不帶有任何數據.
主項目中的Input、Output和Feature用來定義報告中的數據通訊欄位, 每個項目標籤之後是用來描述特性的32位數, 其中前9位有不同的含義, 後23位被保留. 當然, HID項目中的data部分, 不一定是32位數, 其長度仍舊由bSize值決定. 這三個項目的特性描述, 如下表所示.
| 偏移 | 描述 |
|---|---|
| 0 | 0=數據, 表示項目內容可改;1=常數, 項目內容不可改 |
| 1 | 0=數組, 表示項目描述每個控制的狀態;1=變數, 項目只報告作用中的控制 |
| 2 | 0=絕對, 表示數值以固定值為基準;1=相對, 當前數值以上一數值為基準 |
| 3 | 0=沒有折行, 數據不作折返處理;1=有折行, 遇到最大最小界限時折返 |
| 4 | 0=線性, 測量與報告數據為線性關係;1=非線性, 測量與報告數據非線性關係 |
| 5 | 0=優選狀態, 無交互時, 回到特定狀態;1=非優選狀態 |
| 6 | 0=沒有空位置;1=空狀態 |
| 7 | 0=非揮發;1=揮發, 設備可以自己改變數值. 此位對Input無效 |
| 8 | 0=位欄位, 表示每一位或每一位元組內的群組位可代表一份數據;1=緩衝位元組, 表示資訊包含一個或者多個位元組, 緩衝位元組的報告大小必須為8 |
| 9-23 | 保留 |
表2中的Usage Page和Usage是最複雜的項目, 為此USB-IF專門為它們準備了參考文檔. Usage Page是全局項目, 用來定義數據的用法或功能;Usage是局部項目, 用來描述項目或集合的用途.
Usage Page一般和Usage, 或者和Usage Minimum、Usage Maximum共同決定設備的用途. 如示例1所示, 這是一個常見的Usage Page和Usage的定義項目.
USB示例
示例說明
在demo中提供了兩個HID示例, 一個是響應輸入返回ADC取樣結果, 另一個是模擬鍵盤輸出按鍵狀態.
程式碼的工作流程都是相似的, 初始化USB, 初始化通道(Endpoint), 在USB的中斷響應中, 判斷類型和通道分別處理. 在初始化階段根據不同的命令返回對應的描述報文, 在輸入輸出階段響應對應的數據.
示例程式碼
接線說明
與PC的連線
轉接板 STC8H8K64U
3.3V -> VCC
D- -> P3.0
D+ -> P3.1
GND -> GND
轉接板僅將5V轉為3.3V, 可以參考前面的文章說明
