国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備

這篇具有很好參考價值的文章主要介紹了第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

前言

文章中的部分概念可參考第9課【USB協(xié)議】USB總線 接口 端點(diǎn) 管道 數(shù)據(jù)包 枚舉 STM32_USB-FS-Device_Lib V4.1.0

USB設(shè)備類別

USB協(xié)議中為了提供對多樣設(shè)備的支持,定義了許多外部設(shè)備子類,常見的包括:

  • 人機(jī)交互類設(shè)備HID(Human Interface Device)
  • 通信類設(shè)備CDC(Communicate Device Class)
  • 大容量存儲設(shè)備MSC(Mass Storage Class)
  • 視頻類設(shè)備UVC(USB Video Class)
  • 音頻類設(shè)備UAC(USB Audio Class)

USB支持的設(shè)備眾多,實(shí)現(xiàn)方法上會有很多不同點(diǎn)。但從實(shí)現(xiàn)思路上可以重點(diǎn)關(guān)注兩個點(diǎn):

  • 設(shè)備描述符實(shí)現(xiàn):配置從機(jī)類型,方便主機(jī)加載從機(jī)對應(yīng)驅(qū)動及對從機(jī)數(shù)據(jù)的識別
  • 配置描述符實(shí)現(xiàn):配置設(shè)備專用的描述符,方便啟用特定的設(shè)備操作和特性;配置從機(jī)端點(diǎn)信息,方便主機(jī)從端點(diǎn)讀/寫數(shù)據(jù)

未定義設(shè)備

指僅能讓計(jì)算機(jī)識別出其USB設(shè)備身份,沒有具體指明其功能的USB設(shè)備

識別USB設(shè)備的硬件前提
USB集線器識別USB設(shè)備是否接入依賴的是USB總線上D+/D-的電平變化。在USB集線器上,D+/D-信號線上都會接一個15kΩ的下拉電阻,而對應(yīng)的USB設(shè)備上都會在D+/D-接上一個1.5kΩ上拉電阻(高速全速設(shè)備上拉電阻在D+,低速設(shè)備的上拉電阻在D-),當(dāng)集線器檢測到空閑的USB接口D+/D-信號線的電平突然被拉高時,就知道有USB設(shè)備接入了,進(jìn)而進(jìn)入美劇流程

設(shè)備描述符/配置描述符分析

const uint8_t Undefined_USB_DeviceDescriptor[18] =
{
	0x12,                       // bLength:描述符長度,固定為0x12
	0x01,                       // bDescriptorType:描述符類型,固定為0x01,表示設(shè)備描述符
	0x00, 0x02,                 // bcdUSB:USB協(xié)議版本號,這里是2.0
	0x00,                       // bDeviceClass:設(shè)備類別,0表示未定義
	0x00,                       // bDeviceSubClass:設(shè)備子類別,0表示未定義
	0x00,                       // bDeviceProtocol:設(shè)備協(xié)議,0表示未定義
	0x40,                       // bMaxPacketSize:最大數(shù)據(jù)包大小,這里是64字節(jié)
	0x83, 0x04,                 // idVendor:USB設(shè)備廠商ID,這里是0x0483
	0x20, 0x57,                 // idProduct:USB設(shè)備產(chǎn)品ID,這里是0x5720
	0x00, 0x01,                 // bcdDevice:設(shè)備版本號,這里是1.0
	0x01,                       // iManufacturer:USB設(shè)備制造商字符串描述符的索引值,這里是1
	0x02,                       // iProduct:USB設(shè)備產(chǎn)品字符串描述符的索引值,這里是2
	0x03,                       // iSerialNumber:USB設(shè)備序列號字符串描述符的索引值,這里是3
	0x01                        // bNumConfigurations:USB設(shè)備支持的配置數(shù)量,這里是1
}

const uint8_t Undefined_USB_ConfigDescriptor[32] =
{
    /************** 配置描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x02                      // bDescriptorType: 描述符類型,表示該描述符的類型為Configuration Descriptor,固定為2
	0x20 
	0x00                   // wTotalLength: 該配置描述符及其所包含的所有描述符的總長度,單位為字節(jié)
	0x01                      // bNumInterfaces: 該配置所包含的接口數(shù)量
	0x01                      // bConfigurationValue: 該配置的值,用于選擇設(shè)備的配置
	0x00                      // iConfiguration: 該配置的字符串描述符的索引,如果不存在則為0
	0xA0                      // bmAttributes: 該配置的屬性,包括供電方式和遠(yuǎn)程喚醒功能等
	0x32                      // bMaxPower: 該配置所需的最大電流,單位為2mA
    /************** 接口描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x04                      // bDescriptorType: 描述符類型,表示該描述符的類型為Interface Descriptor,固定為4
	0x00                      // bInterfaceNumber: 該接口的編號
	0x00                      // bAlternateSetting: 備用設(shè)置的編號,用于支持多種設(shè)置
	0x02                      // bNumEndpoints: 該接口所包含的端點(diǎn)數(shù)量
	0x00                      // bInterfaceClass: 該接口的類別,0表示未定義
	0x00                      // bInterfaceSubClass: 該接口的子類別,0表示未定義
	0x00                      // bInterfaceProtocol: 該接口的協(xié)議,0表示未定義
	0x00                      // iInterface: 該接口的字符串描述符的索引,如果不存在則為0
    /************** 端點(diǎn)描述符 ****************/
	0x07                      // bLength: 描述符長度,固定為7
	0x05                      // bDescriptorType: 描述符類型,表示該描述符的類型為Endpoint Descriptor,固定為5
	0x81                      // bEndpointAddress: 該端點(diǎn)的地址,包括端點(diǎn)方向和端點(diǎn)編號,表示為IN端點(diǎn)1
	0x02                      // bmAttributes: 該端點(diǎn)的屬性,包括傳輸類型和數(shù)據(jù)類型等,表示為Bulk傳輸類型
	0x40 
	0x00                      // wMaxPacketSize: 該端點(diǎn)所支持的最大數(shù)據(jù)包大小,單位為字節(jié)
	0x00                      // bInterval: 該端點(diǎn)所需的輪詢間隔,單位為毫秒
    /************** 端點(diǎn)描述符 ****************/
	0x07                      // bLength: 描述符長度,固定為7
	0x05                      // bDescriptorType: 描述符類型,表示該描述符的類型為Endpoint Descriptor,固定為5
	0x02                      // bEndpointAddress: 該端點(diǎn)的地址,包括端點(diǎn)方向和端點(diǎn)編號,表示為OUT端點(diǎn)2
	0x02                      // bmAttributes: 該端點(diǎn)的屬性,包括傳輸類型和數(shù)據(jù)類型等,表示為Bulk傳輸類型
	0x40 
	0x00                      // wMaxPacketSize: 該端點(diǎn)所支持的最大數(shù)據(jù)包大小,單位為字節(jié)
	0x00                      // bInterval: 該端點(diǎn)所需的輪詢間隔,單位為毫秒
};

設(shè)備描述符定義了一個未指定功能的USB設(shè)備,支持的USB協(xié)議為USB2.0,單次傳輸最大數(shù)據(jù)包傳輸大小為64字節(jié),配置描述符描述了未定義USB設(shè)備的接口,接口對應(yīng)功能也是未定義的,所以也不能通過端點(diǎn)傳輸數(shù)據(jù)

配置從機(jī)類型

以上設(shè)備描述符中有三個重要的值,用于指定USB設(shè)備身份:

  • bDeviceClass:表明設(shè)備類別
  • bDeviceSubClass:表明設(shè)備子類別
  • bDeviceProtocol:表明設(shè)備協(xié)議

對于常用的設(shè)備類型,它們有以下組合方式:

設(shè)備類別 bDeviceClass bDeviceSubClass(多選一) bDeviceProtocol(多選一)
未定義 0x00 0x00 0x00
人機(jī)交互類設(shè)備 HID 0x03 未定義:0x00
啟動接口子類:0x01
鼠標(biāo)接口子類:0x02
搖桿接口子類:0x03
游戲手柄接口子類:0x04
鍵盤接口子類:0x05
未定義:0x00
鍵盤協(xié)議:0x01
鼠標(biāo)協(xié)議:0x02
搖桿協(xié)議:0x03
游戲手柄協(xié)議:0x04
通信類設(shè)備 CDC 0x02 未定義:0x00
ACM子類:0x01
ECM子類:0x02
NCM子類:0x03
自定義子類:0xFE
未定義:0x00
V.25ter協(xié)議:0x01
AT命令協(xié)議:0x02
PPP協(xié)議:0x03
Ethernet Emulation協(xié)議:0x04
ATM Emulation協(xié)議:0x05
供應(yīng)商自定義協(xié)議: 0xFF
大容量存儲設(shè)備 MSC 0x08 未定義:0x00
公開SCSI命令集子類:0x01
ATAPI命令集子類:0x02
USB命令集子類:0x03
自定義子類:0xFE
未定義:0x00
USB批量傳輸協(xié)議:0x01
公開SCSI協(xié)議:0x50
UAS傳輸協(xié)議:0x62
自定義協(xié)議:0x80~0xFF
組合設(shè)備 0xEF 通用子類:0x01
IAD多接口子類:0x02
供應(yīng)商自定義子類:0x0F
未定義:0x00
IAD多接口協(xié)議:0x01
供應(yīng)商自定義協(xié)議:0xFF

配置設(shè)備專用的描述符

要配置設(shè)備專用描述符和從機(jī)端點(diǎn),首先要了解配置描述符的組成。常見的配置描述符結(jié)構(gòu)如下:

第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
能看出配置描述符的一些特點(diǎn):

  • 上層描述符如果包含下層描述符,那么下層描述符的實(shí)現(xiàn)必須緊挨著上層描述符
  • 一個上層描述符如果包含了多個下層描述符,那多個下層描述符的實(shí)現(xiàn)按照順序緊挨著上層描述符
  • 一個配置描述符中可以有多個接口描述符
  • 一個接口描述符可以包含多個端點(diǎn)描述符
  • 多個接口描述符通過接口關(guān)聯(lián)描述符整合

接口關(guān)聯(lián)描述符
Interface Associate Descriptor接口關(guān)聯(lián)描述符。在USB部分設(shè)備中,一般實(shí)現(xiàn)某個設(shè)備功能只會要求使用一個接口,但也可能會要求使用兩個或以上的接口,這時候就需要將使用到的多個接口,通過IAD描述符關(guān)聯(lián)起來,以便于主機(jī)識別這些關(guān)聯(lián)接口之間的關(guān)系。一般來說IAD描述符出現(xiàn)在配置描述符之后,接口描述符之前,IAD描述符之后會緊跟著相關(guān)聯(lián)的接口描述符

根據(jù)上述的特點(diǎn),設(shè)備專用的描述符只要插入了其上層描述符之后就可以了,如果有多個,按照包含順序緊挨著實(shí)現(xiàn)。一般來說因?yàn)榻涌诿枋龇驮O(shè)備的功能有緊密的聯(lián)系,所以設(shè)備專用的描述符位置都和接口描述符并列,或者包含于接口描述符之中

配置從機(jī)端點(diǎn)

端點(diǎn)描述符的配置較為簡單,一般要:

  • 確定需要的端點(diǎn)數(shù)量,以及每個端點(diǎn)的數(shù)據(jù)方向:輸入/輸出
  • 配置緩沖區(qū)描述表,為緩沖區(qū)描述表頭和端點(diǎn)分配讀寫緩沖區(qū)

緩沖區(qū)及緩沖區(qū)描述表
緩沖區(qū)是在STM32 USB標(biāo)準(zhǔn)庫開發(fā)中的概念。緩沖區(qū)實(shí)際大小為512Bytes,位于STM32的RAM中,地址為0x40006000~0x400063FF(大小為1KByte,由于對于內(nèi)核是通過32位的讀取方式讀取緩沖的,而USB外設(shè)是通過16位的方式讀取緩沖區(qū)。內(nèi)核讀取到的四個字節(jié)只有兩個是有意義的,另一半由于沒有對應(yīng)的實(shí)際存儲器,會讀取不到東西),用于存放緩沖區(qū)描述表,同時還用作端點(diǎn)收發(fā)數(shù)據(jù)Buffer。緩沖區(qū)描述表是緩沖區(qū)中的一個區(qū)域,記錄緩沖區(qū)端點(diǎn)相關(guān)寄存器信息。緩沖區(qū)中除了描述表的以外空間可以分配給端點(diǎn),作為收發(fā)數(shù)據(jù)Buffer,Buffer之間不能重疊,一個Buffer的最大為64Bytes
緩沖區(qū)描述表頭和端點(diǎn)分配
緩沖區(qū)描述表頭應(yīng)該位于緩沖區(qū)的最前面,記錄每個端點(diǎn)相關(guān)的四個寄存器信息,包括緩沖地址寄存器,發(fā)送數(shù)據(jù)字節(jié)寄存器,接收緩沖地址寄存器,接收數(shù)據(jù)字節(jié)寄存器,每個寄存器占用兩個字節(jié),所以每增加一個端點(diǎn)會讓表頭增大八個字節(jié)。一般來說緊挨著表頭是端點(diǎn)0Buffer地址,會定義在距離表頭64Bytes的位置,因?yàn)閱蝹€USB設(shè)備可用端點(diǎn)為8個,所以所有的寄存器信息大小為8*8=64Bytes。之后的表頭地址就根據(jù)各個端點(diǎn)Buffer需求的大小定義即可,可參考以下示例:

// 端點(diǎn)數(shù)量
#define EP_NUM     (5)

// 緩沖區(qū)描述表定義
// 緩沖區(qū)描述表頭
#define BTABLE_ADDRESS      (0x00)

// 端點(diǎn)0發(fā)送/接收Buffer首地址,大小都為64Bytes
#define ENDP0_RXADDR        (0x40)
#define ENDP0_TXADDR        (0x80)
// 端點(diǎn)1發(fā)送/接收Buffer首地址,大小都為64Bytes
#define ENDP1_TXADDR        (0xC0)
#define ENDP1_RXADDR        (0x100)

// 端點(diǎn)2發(fā)送/接收Buffer首地址,大小都為64Bytes
#define ENDP2_TXADDR        (0x140)
#define ENDP2_RXADDR        (0x180)

// 端點(diǎn)3發(fā)送Buffer首地址,大小都為64Bytes
#define ENDP3_TXADDR        (0x1C0)

實(shí)現(xiàn)設(shè)備類特定請求

USB設(shè)備類特定請求屬于USB設(shè)備標(biāo)準(zhǔn)請求的拓展,其數(shù)據(jù)內(nèi)容類似于標(biāo)準(zhǔn)請求,都有請求碼,索引,值和長度。USB設(shè)備標(biāo)準(zhǔn)請求是所有USB設(shè)備都支持的,它可以實(shí)現(xiàn)最基礎(chǔ)的USB設(shè)備配置和控制功能。而USB設(shè)備類特定請求指的是針對特定設(shè)備的請求,例如HID設(shè)備的GET_REPORT/SET_REPORT請求,CDC設(shè)備的GET_LINE_CODING/SET_LINE_COFING請求。具體到每種設(shè)備,其對類特定請求的定義和實(shí)現(xiàn)都不同,這類請求一般由開發(fā)者來實(shí)現(xiàn)

HID設(shè)備

HID設(shè)備是USB協(xié)議中定義的一種廣泛運(yùn)用于計(jì)算機(jī),游戲機(jī),工業(yè)設(shè)備等電子設(shè)備中的輸入設(shè)備子類,包括鼠標(biāo),鍵盤,搖桿,游戲手柄等。符合HID規(guī)范的設(shè)備不僅可以通過USB,還可以通過藍(lán)牙,無線電的方式同主機(jī)相連接,通過特殊的HID報文同主機(jī)進(jìn)行數(shù)據(jù)傳輸

HID設(shè)備有以下優(yōu)點(diǎn):

  • 免驅(qū)動:HID設(shè)備的驅(qū)動通常都已經(jīng)內(nèi)置于操作系統(tǒng)之中
  • 低功耗:HID設(shè)備通常都通過總線供電或自帶電池供電
  • 多樣性:HID設(shè)備種類繁多,基本的輸入設(shè)備都可以作為HID設(shè)備,例如鼠標(biāo),鍵盤,手柄,指點(diǎn)桿等等

特點(diǎn)

USB HID協(xié)議中額外規(guī)定了HID設(shè)備/主機(jī)之間的通信格式和通信協(xié)議。所以相對于標(biāo)準(zhǔn)USB設(shè)備,HID設(shè)備實(shí)現(xiàn)上有以下的特點(diǎn):

  • 設(shè)備描述符不同,配置描述符中多出了HID設(shè)備專用的HID主描述符,HID報文描述符,HID實(shí)體描述符(可選)

第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備

  • 僅需定義三個端點(diǎn):一個端點(diǎn)0用傳輸控制;一個IN端點(diǎn),用于設(shè)備向主機(jī)發(fā)送數(shù)據(jù);一個OUT端點(diǎn),用于主機(jī)向設(shè)備發(fā)送數(shù)據(jù),其中IN,OUT端點(diǎn)都使用中斷傳輸模式

第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備

  • 通過HID報文描述符定義的報文格式同主機(jī)溝通(報文格式多變,幾乎可以傳輸任何數(shù)據(jù),但其內(nèi)容也幾乎相當(dāng)于一門編程語言)

HID鍵盤描述符實(shí)例

const uint8_t HID_Keyboard_DeviceDescriptor[18] =
{
	0x12,                       // bLength: 描述符長度,固定為0x12
	0x01,                       // bDescriptorType: 描述符類型,固定為0x01,表示設(shè)備描述符
	0x00, 0x02,                 // bcdUSB: USB協(xié)議版本號,這里是2.0
	0x03,                       // bDeviceClass: 設(shè)備類別,3表示HID設(shè)備
	0x01,                       // bDeviceSubClass: 設(shè)備子類別,1表示啟動接口子類
	0x01,                       // bDeviceProtocol: 設(shè)備協(xié)議,1表示鍵盤協(xié)議
	0x40,                       // bMaxPacketSize0: 最大數(shù)據(jù)包大小,這里是64字節(jié)
	0x83, 0x04,                 // idVendor: USB設(shè)備廠商ID,這里是0x0483
	0x20, 0x57,                 // idProduct: USB設(shè)備產(chǎn)品ID,這里是0x5720
	0x00, 0x01,                 // bcdDevice: 設(shè)備版本號,這里是1.0
	0x01,                       // iManufacturer: USB設(shè)備制造商字符串描述符的索引值,這里是1
	0x02,                       // iProduct: USB設(shè)備產(chǎn)品字符串描述符的索引值,這里是2
	0x03,                       // iSerialNumber: USB設(shè)備序列號字符串描述符的索引值,這里是3
	0x01                        // bNumConfigurations: USB設(shè)備支持的配置數(shù)量,這里是1
}

const uint8_t HID_Keyboard_ConfigDescriptor[41] =
{
    /************** 配置描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x02                      // bDescriptorType: 描述符類型,表示該描述符的類型為Configuration Descriptor,固定為2
	0x29 
	0x00                      // wTotalLength: 該配置描述符及其所包含的所有描述符的總長度,單位為字節(jié)
	0x01                      // bNumInterfaces: 該配置所包含的接口數(shù)量
	0x01                      // bConfigurationValue: 該配置的值,用于選擇設(shè)備的配置
	0x00                      // iConfiguration: 該配置的字符串描述符的索引,如果不存在則為0
	0xA0                      // bmAttributes: 該配置的屬性,包括供電方式和遠(yuǎn)程喚醒功能等
	0x32                      // bMaxPower: 該配置所需的最大電流,單位為2mA
    /************** 接口描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x04                      // bDescriptorType: 描述符類型,表示該描述符的類型為Interface Descriptor,固定為4
	0x00                      // bInterfaceNumber: 該接口的編號
	0x00                      // bAlternateSetting: 備用設(shè)置的編號,用于支持多種設(shè)置
	0x02                      // bNumEndpoints: 該接口所包含的端點(diǎn)數(shù)量
	0x03                      // bInterfaceClass: 該接口的類別,表示為Human Interface Device
	0x01                      // bInterfaceSubClass: 該接口的子類別,表示為啟動接口子類
	0x01                      // bInterfaceProtocol: 該接口的協(xié)議,表示為鍵盤協(xié)議
	0x00                      // iInterface: 該接口的字符串描述符的索引,如果不存在則為0
	/************** HID主描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x21                      // bDescriptorType: 描述符類型,表示該描述符的類型為HID Descriptor,固定為33
	0x10, 0x01,               // bcdHID:HID規(guī)范版本(1.1)
	0x00,                     // bCountryCode:國家代碼(未指定)
	0x01,                     // bNumDescriptors:支持的描述符類型數(shù)
	0x22,                     // bDescriptorType:描述符類型(報告描述符)
	0x3F, 0x00,               // wDescriptorLength:描述符長度
    /************** 端點(diǎn)描述符 ****************/
	0x07                      // bLength: 描述符長度,固定為7
	0x05                      // bDescriptorType: 描述符類型,表示該描述符的類型為Endpoint Descriptor,固定為5
	0x01                      // bEndpointAddress: 該端點(diǎn)的地址,包括端點(diǎn)方向和端點(diǎn)編號,表示為OUT端點(diǎn)1
	0x03                      // bmAttributes: 該端點(diǎn)的屬性,包括傳輸類型和數(shù)據(jù)類型等,表示為Interrup傳輸類型
	0x40 
	0x00                      // wMaxPacketSize: 該端點(diǎn)所支持的最大數(shù)據(jù)包大小64字節(jié)
	0x0A                      // bInterval: 該端點(diǎn)所需的輪詢間隔10ms
    /************** 端點(diǎn)描述符 ****************/
	0x07                      // bLength: 描述符長度,固定為7
	0x05                      // bDescriptorType: 描述符類型,表示該描述符的類型為Endpoint Descriptor,固定為5
	0x81                      // bEndpointAddress: 該端點(diǎn)的地址,包括端點(diǎn)方向和端點(diǎn)編號,表示為IN端點(diǎn)1
	0x03                      // bmAttributes: 該端點(diǎn)的屬性,包括傳輸類型和數(shù)據(jù)類型等,表示為Interrup傳輸類型
	0x40 
	0x00                      // wMaxPacketSize: 該端點(diǎn)所支持的最大數(shù)據(jù)包大小64字節(jié)
	0x0A                      // bInterval: 該端點(diǎn)所需的輪詢間隔10ms
};

以上描述符實(shí)現(xiàn)了一個HID鍵盤設(shè)備,其描述符分別指出:

  • 設(shè)備描述符:支持USB 1.1協(xié)議,支持啟動接口的HID鍵盤
  • 配置描述符:包含一個接口
  • 接口描述符:定義了設(shè)備為HID設(shè)備,支持在BIOS使用,支持鍵盤HID協(xié)議
  • HID主描述符:HID設(shè)備有兩個端點(diǎn),最大包大小為64字節(jié),最大電流為100mA,支持自供電,不支持遠(yuǎn)程喚醒。同時還指定了HID設(shè)備支持HID報文描述符,報文描述符長度為63字節(jié)
  • 備注:HID報文描述符的實(shí)現(xiàn)需要額外定義,不在配置描述符中實(shí)現(xiàn)

HID報文描述符

前面提到HID設(shè)備通過特殊的HID報文同主機(jī)進(jìn)行數(shù)據(jù)傳輸。這里的報文,指的是可變長度,指定格式的特殊數(shù)據(jù),其中:

  • 可變長度:HID報文描述符中沒有指定描述符長度,其長度由開發(fā)者定義
  • 指定格式:HID報文數(shù)據(jù)需要根據(jù)HID報文描述符中描述的格式進(jìn)行解析,才能變成有效的信息

HID報文描述符中最基本的單元是條目(Item),條目又分為長條目和短條目,長條目不經(jīng)常使用,所以此處僅討論短條目

短條目

短條目由前綴+可選的數(shù)據(jù)組成,其中:

  • 前綴:1字節(jié)的數(shù)據(jù),用于描述可選數(shù)據(jù)含義的元信息

短條目的前綴部分大小為一個字節(jié),這一個字節(jié)的八個比特位被分為三部分:第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備

  • bSize:D0~D1,占用1位,用于表示該條目的數(shù)據(jù)長度,單位為字節(jié)。0表示0字節(jié),1表示1字節(jié),2表示2字節(jié),3表示4字節(jié)
  • bType:D2~D3,占用2位,用于表示該條目的數(shù)據(jù)類型。0表示主條目,1表示全局條目,2表示局部條目
  • bTag:D4~D7,占用4位,用于表示該條目的功能。根據(jù)不同的條目類型,同樣的bTag會有不同的含義
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
  • 可選的數(shù)據(jù):可以是0字節(jié),1字節(jié),2字節(jié)或者4字節(jié)大小的數(shù)據(jù),一般使用1字節(jié)居多

可選數(shù)據(jù)不是獨(dú)立存在的,需要通過條目的前綴去解析可選數(shù)據(jù),到官方提供的HID Usage Table中查詢到對應(yīng)的意義


實(shí)際的代碼中,通常將短條目分為前綴和可選數(shù)據(jù),分別用兩位十六進(jìn)制數(shù)表示,其形式為:

//  前綴     數(shù)據(jù)
	0x81,	0x06 // 表示主條目的Input

其形式類似于鍵值對,前綴為鍵,數(shù)據(jù)為值

報文生成

通過將相關(guān)的條目進(jìn)行組合,能得到有層次結(jié)構(gòu)的HID報文描述符。基本的報文描述符結(jié)構(gòu)如下:

第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
可以看出,報文描述符分為兩部分:

  • 外層綠色部分:由Usage Page/Usage/Collection/End Collection控制符組成,被稱為集合,它描述了此報文的最基本功能,定義了報文的使用頁面,使用類型和字段組合方式。值得注意的是,最外層并不一定就包含了此報文的所有信息,復(fù)雜的報文,可能會涉及多語言設(shè)計(jì),加密,壓縮等機(jī)制,需要具體分析
  • 內(nèi)層橙色/藍(lán)色部分:由Usage Page/Usage Minimum/Usage Maximum/Logical Minimum/Logical Maximum/Input/Output等控制符組成,被稱為字段,它描述了報文數(shù)據(jù)的具體組合方式,各個元素的含義和取值范圍

HID鍵盤報文描述符實(shí)例

通過對一個HID鍵盤的基礎(chǔ)報文描述符的分析,可以很好的對以上所有的HID描述符相關(guān)概念進(jìn)行收尾

const uint8_t CustomHID_ReportDescriptor[63] ={
    0x05, 0x01,           // Usage Page (Generic Desktop)
    0x09, 0x06,           // Usage (Keyboard)
    0xA1, 0x01,           // Collection (Application)
    
    0x05, 0x07,           // Usage Page (Key Codes)
    0x19, 0xE0,           // Usage Minimum (224)
    0x29, 0xE7,           // Usage Maximum (231)
    0x15, 0x00,           // Logical Minimum (0)
    0x25, 0x01,           // Logical Maximum (1)
    0x75, 0x01,           // Report Size (1)
    0x95, 0x08,           // Report Count (8)
    0x81, 0x02,           // Input (Data, Variable, Absolute) ; Modifier byte
    0x75, 0x08,           // Report Size (8)
    0x95, 0x01,           // Report Count (1)
    0x81, 0x01,           // Input (Constant) ; Reserved byte

    0x05, 0x08,           // Usage Page (LEDs)
    0x19, 0x01,           // Usage Minimum (1)
    0x29, 0x05,           // Usage Maximum (5)
    0x75, 0x01,           // Report Size (1)
	0x95, 0x05,           // Report Count (5)
    0x91, 0x02,           // Output (Data, Variable, Absolute) ; LED report
    0x75, 0x03,           // Report Size (3)
    0x95, 0x01,           // Report Count (1)
    0x91, 0x01,           // Output (Constant) ; LED report padding

    0x05, 0x07,           // Usage Page (Key Codes)
    0x15, 0x00,           // Logical Minimum (0)
    0x25, 0x65,           // Logical Maximum (101)
    0x19, 0x00,           // Usage Minimum (0)
    0x29, 0x65,           // Usage Maximum (101)
    0x75, 0x08,           // Report Size (1)
    0x95, 0x06,           // Report Count (48)
    0x81, 0x00,           // Input (Data, Array) ; Key array (6 keys)

    0xC0                  // End Collection
};

可以看出HID報文描述符在C語言中,是通過結(jié)構(gòu)體實(shí)現(xiàn)的。其中每一行都是一個短條目,短條目由前綴+1字節(jié)數(shù)據(jù)構(gòu)成(可以參考上面說到的條目表現(xiàn)形式)。最外層的集合告知計(jì)算機(jī),要將此報文作為鍵盤數(shù)據(jù)進(jìn)行解析。最內(nèi)層的字段描述了報文數(shù)據(jù)的結(jié)構(gòu),報文數(shù)據(jù)大小為9個字節(jié),共分為3部分:

閱讀報文描述符的技巧
由于報文由條目組成,結(jié)構(gòu)上有一定的特殊性,按照正常的順序?yàn)g覽可能會比較亂,所以閱讀前先將報文合理分段,每段按照從后往前閱讀,會比較好理解

  • Modifier Keys:結(jié)合Modifier Keys段報文描述符代碼進(jìn)行單獨(dú)解析


    0x05, 0x07, // Usage Page (Key Codes)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?【表明字段的用途是表示鍵碼】
    0x19, 0xE0, // Usage Minimum (224)
    0x29, 0xE7, // Usage Maximum (231)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示鍵碼的值范圍從224~231】
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x01, // Logical Maximum (1) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示單個按鍵可存在的邏輯狀態(tài),為0釋放/1按下】
    0x75, 0x01, // Report Size (1)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示報文大小,單位比特】
    0x95, 0x08, // Report Count (8)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示報文數(shù)量】
    0x81, 0x02, // Input (Data, Variable, Absolute) ; Modifier byte 【表示該段報文的數(shù)據(jù)方向,數(shù)據(jù)類型】

    【分界線】

    0x95, 0x01, // Report Count (1)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示報文大小,單位比特】
    0x75, 0x08, // Report Size (8)? ? ? ? ? ???? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 【表示報文數(shù)量】
    0x81, 0x01, // Input (Constant) ; Reserved byte???????????????????????【表示報文的數(shù)據(jù)方向,數(shù)據(jù)類型】


    代碼可以通過【分界線】分為兩部分來看:
    前半部分:這部分定義了報文數(shù)據(jù)類型為輸入計(jì)算機(jī)的絕對值變量,用途為鍵碼,報文數(shù)據(jù)數(shù)量為8,單個報文數(shù)據(jù)大小為1bit,所以總的數(shù)據(jù)量為8x1bit=8bits=1Byte。而八個比特位能表示八個按鍵,鍵碼范圍從224~231,對應(yīng)如下圖的八個特殊按鍵(參考官方HID Usage Table)
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備八個比特位分別按照高位對大鍵碼,低位位對小鍵碼的關(guān)系一一對應(yīng),每個比特位的0/1裝袋分別表示按鍵被釋放/按下。例如0b0000 0001對應(yīng)就是LeftControl鍵按下
    后半部分:這部分定義了報文數(shù)據(jù)類型為輸入計(jì)算機(jī)的常量,沒有指明實(shí)際用途,主要起到了填充數(shù)據(jù)的作用,保持整體數(shù)據(jù)按照8bits對齊,報文數(shù)據(jù)數(shù)量為8,單個報文數(shù)據(jù)大小為1bit,所以后半部分的數(shù)據(jù)量為8x1bit=8bits=1Byte
    整體字段描述的數(shù)據(jù)的大小為2Bytes,描述的數(shù)據(jù)內(nèi)容為Modified Keys

  • LED:這部分字段定義了報文數(shù)據(jù)類型為輸出計(jì)算機(jī)的絕對值變量,用途為LED燈,報文數(shù)據(jù)數(shù)量為48,單個報文數(shù)據(jù)大小為1bit,所以總的數(shù)據(jù)量為5x1bit=5bits。五個比特位能表示五個LED燈,燈代表的含義范圍從1~5,對應(yīng)如下圖的五個LED(參考官方HID Usage Table):
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
    LED由計(jì)算機(jī)控制亮滅。這部分字段還額外帶了一個 3bits的填充數(shù)據(jù)。
    整體字段描述的數(shù)據(jù)的大小為1Bytes,描述的數(shù)據(jù)內(nèi)容為LED

  • Normal Keys:這部分字段定義了報文數(shù)據(jù)類型為輸入計(jì)算機(jī)的絕對值變量,用途為鍵碼,報文數(shù)據(jù)數(shù)量為48,單個報文數(shù)據(jù)大小為1bit,所以總的數(shù)據(jù)量為48x1bit=48bits=6Byte。而六個字節(jié)能表示四十八個按鍵,鍵碼范圍從0~101,對應(yīng)如下圖的102個特殊按鍵(參考官方HID Usage Table)
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備
    整體字段描述的數(shù)據(jù)的大小為6Bytes,描述的數(shù)據(jù)內(nèi)容為Normal Keys

報文數(shù)據(jù)大小為2+1+6=9Bytes,報文內(nèi)容如下

Byte 9 Byte 8 Byte 7 Byte 6 Byte 5 Byte 4 Byte 3 Byte 2 Byte 1 Byte 0
- - - - - - Normal Keys LED+Padding Padding Modif Keys

報文數(shù)據(jù)本身由HID鍵盤生成并放置到對應(yīng)IN端點(diǎn),等待計(jì)算機(jī)按照端點(diǎn)描述符中定義的中斷時間間隔內(nèi)來獲取。計(jì)算機(jī)取到報文數(shù)據(jù)后,自帶的HID驅(qū)動會按照HID鍵盤報文描述符解析此報文,得到鍵盤釋放/按下的消息。最終按鍵消息會轉(zhuǎn)發(fā)給操作系統(tǒng)底層,由操作系統(tǒng)執(zhí)行對應(yīng)響應(yīng)操作

總結(jié)

HID報文描述符可能是所有USB描述符中最復(fù)雜的,抽象的概念相當(dāng)多,理解起來也需要一定的時間。但是復(fù)雜的定義帶來的卻是報文易用性和靈活性,它幾乎可以描述任何形式的數(shù)據(jù),而且長度都由開發(fā)者來定義,形式也較為簡潔清晰

CDC設(shè)備

CDC設(shè)備USB協(xié)議中定義的一種通信設(shè)備(通常指電信通信設(shè)備和中速網(wǎng)絡(luò)通信設(shè)備)子類,包括調(diào)制解調(diào)器,網(wǎng)絡(luò)適配器,手機(jī),PDA等。通信設(shè)備領(lǐng)域,使用到很多種無線/有線通信協(xié)議以及各式的數(shù)據(jù)傳輸方式,CDC協(xié)議提供了對這些設(shè)備的協(xié)議和數(shù)據(jù)傳輸支持,例如常見的COM口UART協(xié)議,以太網(wǎng)口IP協(xié)議等。通過CDC協(xié)議可以將USB設(shè)備虛擬成通信設(shè)備,通過指定的傳輸協(xié)議和數(shù)據(jù)傳輸方式同USB設(shè)備進(jìn)行通信

CDC設(shè)備有以下優(yōu)點(diǎn):

  • 免驅(qū)動:使用標(biāo)準(zhǔn)的USB接口和通信協(xié)議,部署方便。例如USB虛擬COM口,無需安裝驅(qū)動即可使用
  • 支持多種通信協(xié)議:支持很多通信領(lǐng)域的通信協(xié)議,可以滿足不同行業(yè),不同場景的需求

特點(diǎn)

USB CDC協(xié)議中同樣額外規(guī)定了CDC設(shè)備/主機(jī)之間的通信格式和通信協(xié)議,以CDC-ACM設(shè)備為例,相對于標(biāo)準(zhǔn)USB設(shè)備,它實(shí)現(xiàn)上有以下的特點(diǎn):

  • 設(shè)備描述符不同,配置描述符中多出了CDC設(shè)備專用的CDC控制接口描述符,頭部功能描述符,呼叫管理描述符,抽象控制模型描述符,聯(lián)合功能描述符,CDC數(shù)據(jù)接口描述符,
    第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備

CDC設(shè)備的接口組成
不同于常見的單接口設(shè)備,CDC設(shè)備由多個接口類組成,分別是【CDC控制接口類】和【CDC數(shù)據(jù)接口類】(可選)。所以在較新的操作系統(tǒng)中需要用額外的IAD描述符將兩個接口關(guān)聯(lián)起來。其中:

  • CDC控制接口類:負(fù)責(zé)完成通信設(shè)備的配置和管理,包含了CDC控制接口,頭部功能描述符,呼叫管理功能描述符,抽象控制模型描述符,聯(lián)合功能描述符。各個描述符的作用分別為:
    【CDC控制接口】:用于設(shè)備管理/電話管理(可選),設(shè)備管理一般涉及請求(request)和通知(notification),請求一般由端點(diǎn)0進(jìn)行處理,通知需要額外配置其他端點(diǎn)進(jìn)行處理
    【頭部功能描述符】:用于表示CDC功能描述符的開始,緊跟其后的是CDC設(shè)備的其他功能描述符
    【呼叫管理功能描述符】:負(fù)責(zé)電話,AT指令相關(guān)的功能
    【抽象控制模型描述符】:PSTN(Public Switched Telephone Net)下定義的抽象控制模型。用于描述使用AT指令,或AT.25Ver指令的調(diào)制解調(diào)設(shè)備
    【聯(lián)合功能描述符】:用于告知計(jì)算機(jī),將哪幾個接口聯(lián)合起來,用來表示CDC功能。類似于IAD接口關(guān)聯(lián)描述符
  • CDC數(shù)據(jù)接口類:負(fù)責(zé)進(jìn)行數(shù)據(jù)的傳輸,包含了數(shù)據(jù)接口,數(shù)據(jù)調(diào)制解調(diào)器接口(可選),后者用于模擬調(diào)制解調(diào)設(shè)備的控制信號

接口關(guān)聯(lián)描述符和聯(lián)合功能描述符的關(guān)系
在USB協(xié)議的初期,沒有規(guī)劃好多接口設(shè)備的支持,基本上都是一個設(shè)備只使用一個接口。后來出現(xiàn)了CDC設(shè)備這樣需要使用多接口的設(shè)備,于是便專門出了聯(lián)合功能描述符用于應(yīng)對。等到后期USB協(xié)議逐漸完善,推出了接口關(guān)聯(lián)描述符這樣的用于多個接口關(guān)聯(lián)的描述符。兩者使用起來并不會沖突,在舊版操作系統(tǒng)中,會忽略接口關(guān)聯(lián)描述符,識別聯(lián)合功能描述符;在新版操作系統(tǒng)中會忽略聯(lián)合功能描述符,僅識別接口關(guān)聯(lián)描述符

CDC-ACM虛擬串口描述符實(shí)例

const uint8_t VirtualComPort_DeviceDescriptor[18] =
{
	0x12,                       // bLength: 描述符長度,固定為0x12
	0x01,                       // bDescriptorType: 描述符類型,固定為0x01,表示設(shè)備描述符
	0x00, 0x02,                 // bcdUSB: USB協(xié)議版本號,這里是2.0
	0x02,                       // bDeviceClass: 設(shè)備類別,2表示CDC設(shè)備
	0x01,                       // bDeviceSubClass: 設(shè)備子類別,1表示使用抽象控制模型
	0x01,                       // bDeviceProtocol: 設(shè)備協(xié)議,1表示使用AT指令交互 
	0x40,                       // bMaxPacketSize0: 最大數(shù)據(jù)包大小,這里是64字節(jié)
	0x83, 0x04,                 // idVendor: USB設(shè)備廠商ID,這里是0x0483
	0x20, 0x57,                 // idProduct: USB設(shè)備產(chǎn)品ID,這里是0x5720
	0x00, 0x01,                 // bcdDevice: 設(shè)備版本號,這里是1.0
	0x01,                       // iManufacturer: USB設(shè)備制造商字符串描述符的索引值,這里是1
	0x02,                       // iProduct: USB設(shè)備產(chǎn)品字符串描述符的索引值,這里是2
	0x03,                       // iSerialNumber: USB設(shè)備序列號字符串描述符的索引值,這里是3
	0x01                        // bNumConfigurations: USB設(shè)備支持的配置數(shù)量,這里是1
}

const uint8_t VirtualComPort_ConfigDescriptor[41] =
  {
    /************** 配置描述符 ****************/
	0x09                      // bLength: 描述符長度,固定為9
	0x02                      // bDescriptorType: 描述符類型,表示該描述符的類型為Configuration Descriptor,固定為2
	0x29 
	0x00                      // wTotalLength: 該配置描述符及其所包含的所有描述符的總長度,單位為字節(jié)
	0x01                      // bNumInterfaces: 該配置所包含的接口數(shù)量
	0x01                      // bConfigurationValue: 該配置的值,用于選擇設(shè)備的配置
	0x00                      // iConfiguration: 該配置的字符串描述符的索引,如果不存在則為0
	0xA0                      // bmAttributes: 該配置的屬性,包括供電方式和遠(yuǎn)程喚醒功能等
	0x32                      // bMaxPower: 該配置所需的最大電流,單位為2mA

    /************** 接口關(guān)聯(lián)描述符 ****************/
    /* 09 */
    0x08,                     // bLength:描述符長度,固定為8
    0x0B,                     // bDescriptorType:描述符類型,表示該描述符的類型為接口關(guān)聯(lián)描述符,固定為b
    0x00,                     // bFirstInterface:第一個接口描述符編號 0
    0x02,                     // bInterfaceCount:關(guān)聯(lián)接口描述符總數(shù) 2
    0x02,                     // bFunctionClass:功能類 CDC
    0x02,                     // bFunctionSubClass:功能子類
    0x01,                     // bFunctionProtocol:功能協(xié)議
    0x00,                     // iFunction: 字符串描述符編號
    /************** 控制接口描述符 ****************/
    /* 17 */
    0x09,                     // bLength:描述符長度,固定為9
    0x04,                     // bDescriptorType:描述符類型,表示該描述符的類型為接口描述符,固定為4
    0x00,                     // bInterfaceNumber:接口描述符編號
    0x00,                     // bAlternateSetting:替換設(shè)置
    0x01,                     // bNumEndpoints 包含端點(diǎn)數(shù)
    0x02,                     // bInterfaceClass: 接口類型 CDC
    0x02,                     // bInterfaceSubClass:接口子類 抽象控制模型
    0x01,                     // nInterfaceProtocol:接口協(xié)議 Common AT commands V.250
    2,                        // iInterface: 字符串描述符編號
    /************** 頭部功能描述符 ****************/
    /* 26 */
    0x05,                     // bLength:描述符長度,固定為5
    0x24,                     // bDescriptorType:描述符類型 CS_INTERFACE
    0x00,                     // bDescriptorSubtype:描述符子類 頭部功能描述符
    0x10,                     // bcdCD:CDC協(xié)議版本1.10
    0x01,
    /************** 呼叫功能描述符 ****************/
    /* 31 */
    0x05,                     // bFunctionLength:描述符長度,固定為5
    0x24,                     // bDescriptorType:描述符類型 CS_INTERFACE
    0x01,                     // bDescriptorSubtype:描述符子類 頭部功能描述符
    0x00,                     // bmCapabilities: D0+D1 */
    0x01,                     // bDataInterface: 數(shù)據(jù)描述符接口號 1 */
    /************** 抽象控制模型描述符 ****************/
    /* 36 */
    0x04,                     // bFunctionLength:描述符長度,固定為4
    0x24,                     // bDescriptorType:描述符類型 CS_INTERFACE
    0x02,                     // bDescriptorSubtype:描述符子類 頭部功能描述符
    0x02,                     // bmCapabilities */
    /************** 聯(lián)合功能描述符 ****************/
    /* 40 */
    0x05,                     // bFunctionLength:描述符長度,固定為5
    0x24,                     // bDescriptorType:描述符類型 CS_INTERFACE
    0x06,                     // bDescriptorSubtype:描述符子類 聯(lián)合功能描述符
    0x00,                     // bMasterInterface:主接口描述符描述符
    0x01,                     // bSlaveInterface:附屬接口描述符描述符
    /************** 控制端點(diǎn)描述符 ****************/
    /* 45 */
    0x07,                     // bLength:描述符長度,固定為7
    0x05,                     // bDescriptorType:描述符類型 端點(diǎn)描述符
    0x83,                     // bEndpointAddress:IN端點(diǎn)3
    0x03,                     // bmAttributes:端點(diǎn)類型 中斷
    0x40                      // wMaxPacketSize:最大數(shù)據(jù)包容量 64字節(jié) 
    0x00,
    0x02,                     // bInterval:數(shù)據(jù)獲取間隔 2ms
    /************** 數(shù)據(jù)接口描述符 ****************/
    /* 52 */
    0x09,                     // bLength:描述符長度,固定為9
    0x04,                     // bDescriptorType:描述符類型,表示該描述符的類型為接口描述符,固定為4
    0x02,                     // bInterfaceNumber:接口描述符編號
    0x00,                     // bAlternateSetting:替換設(shè)置
    0x02,                     // bNumEndpoints 包含端點(diǎn)數(shù)
    0x0A,                     // bInterfaceClass: 接口類型 CDC數(shù)據(jù)接口
    0x00,                     // bInterfaceSubClass:接口子類 未定義
    0x00,                     // nInterfaceProtocol:接口協(xié)議 未定義
    0,                        // iInterface: 字符串描述符編號
    /************** 數(shù)據(jù)端點(diǎn)描述符 ****************/
    /* 61 */
    0x07,                     // bLength:描述符長度,固定為7
    0x05,                     // bDescriptorType:描述符類型 端點(diǎn)描述符
    0x02,                     // bEndpointAddress:OUT端點(diǎn)2
    0x02,                     // bmAttributes:端點(diǎn)類型 批量
    0x40                      // wMaxPacketSize:最大數(shù)據(jù)包容量 64字節(jié) 
    0x00,
    0x00,                     // bInterval:數(shù)據(jù)獲取間隔 忽略
    /* 68 */
    0x07,                     // bLength:描述符長度,固定為7
    0x05,                     // bDescriptorType:描述符類型 端點(diǎn)描述符
    0x82,                     // bEndpointAddress:IN端點(diǎn)2
    0x02,                     // bmAttributes:端點(diǎn)類型 批量
    0x40                      // wMaxPacketSize:最大數(shù)據(jù)包容量 64字節(jié) 
    0x00,
    0x00,                     // bInterval:數(shù)據(jù)獲取間隔 忽略
    /* 75 */
  };

以上描述符實(shí)現(xiàn)了一個CDC虛擬串口設(shè)備,其描述符分別指出:

  • 設(shè)備描述符:支持USB 1.1協(xié)議,支持抽象控制模型,使用AT指令的CDC設(shè)備
  • 配置描述符:包含兩個接口,分別是CDC控制接口,CDC數(shù)據(jù)接口
  • 數(shù)據(jù)關(guān)聯(lián)描述符:實(shí)現(xiàn)多個接口對應(yīng)一個功能,例子中是CDC設(shè)備功能
  • 控制接口描述符:定義一個其他端點(diǎn),用作異步傳輸
  • 頭部功能描述符:CDC設(shè)備支持的協(xié)議版本1.10
  • 呼叫功能描述符:只有在電話功能中會使用,虛擬串口設(shè)備中沒有使用
  • 抽象控制模型描述符:表明CDC設(shè)備使用抽象控制模型進(jìn)行通信
  • 聯(lián)合功能描述符:關(guān)聯(lián)CDC設(shè)備的控制接口和數(shù)據(jù)接口
  • 控制端點(diǎn)描述符:實(shí)現(xiàn)設(shè)備控制功能,控制功能可以處理通信設(shè)備需要的請求和通知
  • 數(shù)據(jù)接口描述符:定義2個數(shù)據(jù)傳輸所使用的端點(diǎn)
  • 數(shù)據(jù)端點(diǎn)描述符:處理數(shù)據(jù)傳輸

類特定請求

相對于HID設(shè)備通過特殊的HID報文進(jìn)行數(shù)據(jù)傳輸,CDC-ACM設(shè)備直接通過端點(diǎn)發(fā)送/接收數(shù)據(jù),無需進(jìn)行其他轉(zhuǎn)換和解析。但是需要在CDC-ACM設(shè)備端實(shí)現(xiàn)CDC-ACM類的設(shè)備類特定請求SetLineCoding和GetLineCoding,這兩個請求主要實(shí)現(xiàn)了設(shè)置和獲取虛擬串口的串行通信參數(shù),包括波特率,數(shù)據(jù)傳輸位數(shù),奇偶校驗(yàn)位,停止位,具體實(shí)現(xiàn)如下:

typedef struct
{
  uint32_t bitrate;
  uint8_t  format;
  uint8_t  paritytype;
  uint8_t  datatype;
}LINE_CODING;

LINE_CODING linecoding =
{
	115200, // 波特率
	0x00,   // 停止位 1
    0x00,   // 奇偶校驗(yàn)位 無
    0x08    // 數(shù)據(jù)位數(shù) 8
};

uint8_t *Virtual_Com_Port_GetLineCoding(uint16_t Length)
{
  if (Length == 0)
  {
    pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
    return NULL;
  }
  return(uint8_t *)&linecoding;
}

// 函數(shù)等待實(shí)現(xiàn)
uint8_t *Virtual_Com_Port_SetLineCoding(uint16_t Length)
{
  if (Length == 0)
  {
    pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
    return NULL;
  }
  return(uint8_t *)&linecoding;
}

USB組合設(shè)備

在一個USB設(shè)備上實(shí)現(xiàn)多個功能,例如HID鍵盤+CDC虛擬串口。有兩種方法:

  • 組合設(shè)備:Composite Device,內(nèi)部通過組合設(shè)備描述符,以及組織多個功能的接口實(shí)現(xiàn)多功能組合。所有功能共用一套PID/VID/DID
  • 復(fù)合設(shè)備:Compound Device,內(nèi)部通過USB HUB來實(shí)現(xiàn),將多個單一功能的USB設(shè)備,通過USB HUB連接整合,每個設(shè)備有自己獨(dú)立的PID/VID/DID。這種方法復(fù)雜度相當(dāng)高,具體可以參考USB2.0協(xié)議

實(shí)現(xiàn)思路

通過以上對HID設(shè)備和CDC設(shè)備的解析。通過STM32去實(shí)現(xiàn)USB組合設(shè)備的思路就相當(dāng)清晰了:

  • 首先需要將USB的設(shè)備描述符中設(shè)備類型改為Miscellaneous Device,表示組合設(shè)備
  • 然后將HID鍵盤的配置描述符和CDC虛擬串口的配置描述符整合,主要注意處理接口關(guān)聯(lián)描述符,接口描述符,CDC控制接口描述符,CDC數(shù)據(jù)接口描述符,HID描述符的次序即可,HID報文描述符可以直接復(fù)用
  • 之后實(shí)現(xiàn)HID鍵盤的GET_REPORT/SET_REPORT設(shè)備類特定請求,以及CDC虛擬串口的GET_LINE_CODING/SET_LINE_COFING請求
  • 最后按照自己的需求完成端點(diǎn)數(shù)據(jù)的填充即可,USB主機(jī)會按照端點(diǎn)描述符要求進(jìn)行數(shù)據(jù)傳輸

代碼實(shí)例

USB組合設(shè)備代碼已上傳Github:Sinuxtm32文章來源地址http://www.zghlxwxcb.cn/news/detail-444253.html

到了這里,關(guān)于第10課【STM32 USB通訊協(xié)議實(shí)戰(zhàn)】HID鍵盤+CDC虛擬串口組合設(shè)備的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • STM32。USB HID,如何發(fā)送標(biāo)準(zhǔn)鍵盤的按鍵報告?

    STM32。USB HID,如何發(fā)送標(biāo)準(zhǔn)鍵盤的按鍵報告?

    我們要求STM32芯片的usb和windows電腦的USB接口進(jìn)行連接,然后STM32芯片發(fā)送usb數(shù)據(jù)給windows電腦,實(shí)現(xiàn)電腦上按下一個f按鍵的效果。 下面開始操作: 使用STM32CubeMX生成代碼,先選擇對應(yīng)的usb口 然后選擇第三方軟件,選擇HID 然后點(diǎn)擊生成代碼,這時候就會生成usbd_hid.c相關(guān)的代碼

    2024年02月12日
    瀏覽(23)
  • USB復(fù)合設(shè)備構(gòu)建CDC+HID鼠標(biāo)鍵盤套裝

    USB復(fù)合設(shè)備構(gòu)建CDC+HID鼠標(biāo)鍵盤套裝

    最近需要做一個小工具,要用到USB CDC+HID設(shè)備。又重新研究了一下USB協(xié)議和STM32的USB驅(qū)動庫,也踩了不少坑,因此把代碼修改過程記錄一下。 開發(fā)環(huán)境: ST-LINK v2 STM32H743開發(fā)板 PC windows 11 cubeMX v6.9.2 cubeIDE v1.13.2 cubeprogramer v2.14.0 參考資料: STMicroelectronics/stm32_mw_usb_device: Provide

    2024年02月04日
    瀏覽(26)
  • STM32CubeMX教程31 USB_DEVICE - HID外設(shè)_模擬鍵盤或鼠標(biāo)

    正點(diǎn)原子stm32f407探索者開發(fā)板V2.4 STM32CubeMX軟件(Version 6.10.0) keil μVision5 IDE(MDK-Arm) ST-LINK/V2驅(qū)動 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX軟件配置STM32F407開發(fā)板 USB_OTG_FS為工作在Human Interface Device Class (HID)(人機(jī)接口設(shè)備類)模式下的USB_DEVICE(USB從機(jī)),利用上下左右四

    2024年02月19日
    瀏覽(21)
  • STM32CubeMX學(xué)習(xí)筆記(43)——USB接口使用(CDC虛擬串口)

    STM32CubeMX學(xué)習(xí)筆記(43)——USB接口使用(CDC虛擬串口)

    USB(Universal Serial BUS)通用串行總線 ,是一個外部總線標(biāo)準(zhǔn),用于規(guī)范電腦與外部設(shè)備的連接和通訊。是應(yīng)用在 PC 領(lǐng)域的接口技術(shù)。USB 接口支持設(shè)備的即插即用和熱插拔功能。USB 是在 1994 年底由英特爾、康柏、IBM、Microsoft 等多家公司聯(lián)合提出的。 USB 發(fā)展到現(xiàn)在已經(jīng)有 US

    2024年02月02日
    瀏覽(30)
  • 【STM32】STM32F4中USB的CDC虛擬串口(VCP)使用方法

    【STM32】STM32F4中USB的CDC虛擬串口(VCP)使用方法

    最近在學(xué)習(xí)STM32的USB功能,主要是想要使用虛擬串口(VCP)功能,來解決串口傳輸速率較低的問題,達(dá)到于上位機(jī)高效通信的目的。 使用芯片:STM32F407ZGT6 使用函數(shù):HAL庫 使用工具:STM32CubeMX + Keil uVision5 串口工具:VOFA 主要配置內(nèi)容: 調(diào)試模式為Serial; 使用外部時鐘 設(shè)置為

    2024年02月21日
    瀏覽(78)
  • USB VCP虛擬串口通訊詳細(xì)配置步驟(STM32H732)

    USB VCP虛擬串口通訊詳細(xì)配置步驟(STM32H732)

    1、單片機(jī)型號:STM32H743IIT6;正點(diǎn)原子-阿波羅版 2、Keil-MDK:V5.32 3、CubeMX:6.7.0 4、HAL:STM32Cube FW_H7 V1.11.0 5、參考文章: 1.STM32 USB使用記錄:使用CDC類虛擬串口(VCP)進(jìn)行通訊 2.STM32CubeIDE 簡單配置USB虛擬串口 并實(shí)現(xiàn)printf 3.STM32Cube配置USB虛擬串口發(fā)送與接收回傳 4.STM32USB開發(fā)備

    2023年04月11日
    瀏覽(16)
  • 野火指南者(STM32F103VET6)應(yīng)用:實(shí)現(xiàn)USB虛擬串口(CDC_VPC)

    野火指南者(STM32F103VET6)應(yīng)用:實(shí)現(xiàn)USB虛擬串口(CDC_VPC)

    MCU:STM32F103VET6 開發(fā)環(huán)境:STM32CubeMX+MDK5 ? 實(shí)現(xiàn)USB的虛擬串口不需要去理解USB的底層驅(qū)動,只需要STM32CubeMX去配置生成工程即可。在野火的指南者中,是沒有這一類的視頻和示例的,博主使用這款開發(fā)板實(shí)現(xiàn)USB虛擬串口。 首先需要打開STM32CubeMX工具。輸入開發(fā)板MCU對應(yīng)型號,找

    2024年02月08日
    瀏覽(23)
  • GD32F303基于USBD庫的usb custom hid 雙向通訊實(shí)現(xiàn)

    GD32F303基于USBD庫的usb custom hid 雙向通訊實(shí)現(xiàn)

    默認(rèn)已經(jīng)建立好需要移植的GD32F303空白工程 環(huán)境:keil?? GD庫版本: V2.1.4 通訊工具: 鏈接:https://pan.baidu.com/s/1Ukuy0u52C9ufPGz9QcHONA? 提取碼:d9rf 正文開始 USBD庫植步驟: 找到GD官網(wǎng)的軟件包 本文中用的是GD32F30x_Firmware_Library_V2.1.4 將FirmwareGD32F30x_usbd_library 文件夾全部拷貝至工程

    2023年04月09日
    瀏覽(32)
  • STM32設(shè)置USB HID模式

    STM32設(shè)置USB HID模式

    使用USBHID模式與電腦、手機(jī)終端通訊,速率和準(zhǔn)確率比虛擬串口和CH340轉(zhuǎn)接速度要快。 在USB_OTG_FS中,選擇Device_Only,其它默認(rèn)。 在Middleware中的Class For FS IP中,如下選擇 在Device Descriptor中可以按需要填寫 設(shè)置USB頻率為48Mhz 在Project Manager里,修改Heap和Stack的大小 在程序里main.c中

    2024年02月11日
    瀏覽(24)
  • stm32實(shí)現(xiàn)hid鍵盤

    stm32實(shí)現(xiàn)hid鍵盤

    ?前面的cubelmx項(xiàng)目配置參考 stm32實(shí)現(xiàn)hid鼠標(biāo)-CSDN博客 https://blog.csdn.net/anlog/article/details/137814494?spm=1001.2014.3001.5502 兩個項(xiàng)目的配置完全相同。 代碼 引用 鍵盤代碼: 替換hid設(shè)備描述符 先屏蔽鼠標(biāo)設(shè)備描述符 替換為鍵盤設(shè)備描述符 修改宏定義 ?修改大小為63U ?運(yùn)行后如下圖 參

    2024年04月17日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包