USB HID键盘实现全键无冲解析

这篇具有很好参考价值的文章主要介绍了USB HID键盘实现全键无冲解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

设备描述符

配置描述符

配置描述符

接口描述符

HID描述符

端点描述符

HID类报表描述符

输入输出数据解析

其他


前言

        看了稚辉君的瀚文键盘的源码之后对于键盘全键无冲的实现还是存在很多疑问。1、HID报表描述符的内容到底什么意思?2、瀚文源码里的键值映射函数最终生成的报表不理解。然后就从头开始研究了一下USB。对着描述符里的每一个参数找资料,把所有描述符都对一遍。现在已经大概理解了全键无冲键盘的配置方式和报表含义。

        实践选用的是沁恒的CH573F,这颗芯片支持USB 2.0 Host和Device,支持最大64字节数据包。在官网下载他们的官方Demo,并在USB Device里面找到CompoundDev这个工程来修改我的全键无冲键盘。

设备描述符

const uint8_t MyDevDescr[0x12] = {
    0x12,            //bLenght
    0x01,            //bDescriptorType
    0x00,0x02,       //bcdUSB
    0x00,            //bDeviceClass
    0x00,            //bDeviceSubClass
    0x00,            //bDeviceProtocol
    0x40,            //bMaxPacketSize0
    0x3d,0x41,       //idVendor
    0x07,0x21,       //idProduct
    0x00,0x01,       //bcdDevice
    0x01,            //iManufacturer
    0x02,            //iProduct
    0x03,            //iSerialNumber
    0x01             //bNumConfigurations
};

bLenght--固定长度18
bDescriptorType--01:代表这段数据属于设备描述符
bcdUSB--USB2.0版本  这里是bcd编码 00 02代表2.0版本
bDeviceClass--类型代码(由USB指定)。当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的
bDeviceSubClass--子类型代码(由USB分配).如果bDeviceClass值是0,一定要设置为0.其它情况就跟据USB-IF组织定义的编码
bDeviceProtocol-- 协议代码(由USB分配).如果使用USB-IF组织定义的协议,就需要设置这里的值,否则直接设置为0。如果厂商自己定义的可以设置为FFH
bMaxPacketSize0--最大包长,芯片所支持的最大长度
idVendor--厂商ID
idProduct--产品ID
bcdDevice--版本号,自己定义 这里是bcd编码 00 01代表1.0版本
iManufacturer--厂商字符串索引(只要不为1主机就会找设备拿这个字符串
iProduct--产品字符串索引         (只要不为1主机就会找设备拿这个字符串
iSerialNumber--设备序列号字符串索引(只要不为1主机就会找设备拿这个字符串
bNumConfigurations--可能的配置数.定义设备以当前速度支持的配置数量

配置描述符

        一般CfgDescr这个集合里面会包含:配置描述符、接口描述符、HID描述符(HID

设备才需要)、端点描述符。USB主机会一次或分包拿完整个配置描述符集合。

const uint8_t MyCfgDescr[0x34] = {
    //配置描述符
    0x09,                                   //bLenght
    0x02,                                   //bDescriptorType
    0x34,0x00,                              //wTotalLength
    0x01,                                   //bNumInterfaces
    0x01,                                   //bConfigurationValue
    0x00,                                   //iConfiguration
    0xA0,                                   //bmAttributes
    0x32,                                   //MaxPower
    //接口描述符,键盘功能
    0x09,                                   //bLenght
    0x04,                                   //bDescriptorType
    0x00,                                   //bInterfaceNumber
    0x00,                                   //bAlternateSetting
    0x01,                                   //bNumbEndpoints
    0x03,                                   //bInterfaceClass
    0x01,                                   //bInterfaceSubClass
    0x01,                                   //bInterfaceProtocol
    0x00,                                   //iInterface
    //HID类描述符
    0x09,                                   //bLenght
    0x21,                                   //bDescriptorType
    0x11,0x01,                              //bcdHID
    0x00,                                   //bCountryCode
    0x01,                                   //bNumDescriptors
    0x22,                                   //bDescriptorType
    0x39,0x00,                              //wDescriptorLength
    //端点描述符
    0x07,                                   //bLenght
    0x05,                                   //bDescriptorType
    0x81,                                   //bEndpointAddress
    0x03,                                   //bmAttributes
    0x0A,0x00,                              //wMaxPacketSize
    0x01                                    //bInterval
};

配置描述符

bLenght--配置描述符的长度   9
bDescriptorType--02:代表这段数据属于配置描述符
wTotalLength--整个配置描述符集合的总长度
bNumInterfaces--指该配置配备的接口数量,也表示该配置下接口描述符数量
bConfigurationValue--作为Set Configuration的一个参数选择配置值
iConfiguration--用于描述该配置​​​​​​字符串描述符的索引
bmAttributes--供电模式选择.Bit4-0保留,D7:总线供电,D6:自供电,D5:远程唤醒.
MaxPower--设备所需电流,1代表2mA  0x32=100mA

接口描述符

bLenght--接口描述符的长度   9
bDescriptorType--03:代表这段数据属于接口描述符
bInterfaceNumber--该接口的编号
bAlternateSetting--用于为上一个字段选择可供替换的位置.即备用的接口描述符标号
bNumbEndpoints--端点0以外的端点数
bInterfaceClass--类代码  3:HID类
bInterfaceSubClass--子类代码:1是 0否 支持BIOS
bInterfaceProtocol--协议代码:00其他,01键盘,02鼠标
iInterface--字符串描述符的索引

HID描述符

bLenght--HID描述符的长度   9
bDescriptorType--0x21:代表这段数据属于HID描述符
bcdHID--HID的版本号1.11
bCountryCode--国家代码,如果不说明,该字段为0
bNumDescriptors--类别描述符数目(至少有一个报表描述符)
bDescriptorType--该类别描述符的类型
wDescriptorLength--HID报表描述符的长度

端点描述符

bLenght--端点描述符的长度   7
bDescriptorType--05:代表这段数据属于端点描述符
bEndpointAddress--USB设备的端点地址;Bit7方向1/0:IN/OUT(对于控制端点可以忽略);Bit6-4,保留;BIt3-0:端点号;
bmAttributes-- 端点属性.Bit7-2保留(同步有定义)BIt1-0:00控制,01同步,02批量,03中断
wMaxPacketSize--端点收发信息包的长度
bInterval--传输间隔   1:每1个帧    2:每2个帧    4:每4个帧    8:每8个帧

HID类报表描述符

        全键无冲的实现主要靠的就是报表描述符这里配置。

const uint8_t KeyRepDesc[KEYBOARD_HID_REPORT_DESC_SIZE] = {
        0x05, 0x01,       //   Usage Page (Generic Desktop),
        0x09, 0x06,       //   Usage (Keyboard),
        0xA1, 0x01,       //   Collection (Application),
        // bitmap of modifiers(功能按键)
        0x05, 0x07,       //   Usage Page (Keyboard),
        0x95, 0x08,       //   Report Count (8),
        0x75, 0x01,       //   Report Size  (1),
        0x15, 0x00,       //   Logical Minimum (0),
        0x25, 0x01,       //   Logical Maximum (1),
        0x19, 0xE0,       //   Usage Minimum (Keyboard LeftControl),
        0x29, 0xE7,       //   Usage Maximum (Keyboard Right GUI),
        0x81, 0x02,       //   Input (Data, Variable, Absolute),
        // bitmap of keys(普通按键)
        0x05, 0x07,       //   Usage Page (Keyboard),
        0x95, 0x78,       //   Report Count (120),
        0x75, 0x01,       //   Report Size  (1),
        0x15, 0x00,       //   Logical Minimum (0),
        0x25, 0x01,       //   Logical Maximum (1),
        0x19, 0x00,       //   Usage Minimum (0),
        0x29, 0x65,       //   Usage Maximum (101),
        0x81, 0x02,       //   Input (Data, Variable, Absolute),
        // LED output report
        0x05, 0x08,       //   Usage Page (LEDs)
        0x95, 0x03,       //   Report Count (3)
        0x75, 0x01,       //   Report Size  (1)
        0x19, 0x01,       //   Usage Minimum (Num Lock   1)
        0x29, 0x03,       //   Usage Maximum (Scroll Lock   3)
        0x91, 0x02,       //   Output (Data,Var,Abs)
        //output凑共1byte(无实际用处)
        0x95, 0x05,       //   Report Count (5)
        0x75, 0x01,       //   Report Size  (1)
        0x91, 0x01,       //   Output (Cnst,Var,Abs)

        0xC0              //   End Collection
};

0x05, 0x01,        //   Usage Page ,表示用途页为通用桌面设备
0x09, 0x06,        //   Usage ,表示用途为键盘
0xA1, 0x01,       //   Collection,表示应用集合,必须要以 END_COLLECTION 来结束它


// bitmap of modifiers(功能按键)
0x05, 0x07,       //   Usage Page (Key Codes),
0x95, 0x08,       //   Report Count (8),报告的个数为 8,即总共有 8 个 bits
0x75, 0x01,       //   Report Size  (1),定义多少个bit代表一个数据
0x15, 0x00,       //   Logical Minimum (0),逻辑的最小值
0x25, 0x01,       //   Logical Maximum (1),逻辑的最大值
0x19, 0xE0,       //   Usage Minimum (Keyboard LeftControl),用的途最小值
0x29, 0xE7,       //   Usage Maximum (Keyboard Right GUI),用的途最大值
0x81, 0x02,       //   Input (Data, Variable, Absolute), 0x81代表这是输入报告的格式,0x02代表数据格式

        0x05:可以看到首先告诉别人我是属于键盘功能,在HID Usage Tables这份文档中可以查到

        0x07对应的就是键盘,而且在下面还能查找到键盘每个按键对应的键值。

        0x95:告诉别人我的数据里一共代表了8个键值

        0x75:告诉别人我是1个bit代表一个有效数据(一个byte刚好代表8个键)

        0x15:一个数据的逻辑最小值0,键值就是按下和松开两种状态只需要0和1表示

        0x25:一个数据的逻辑最小值1

        0x19:用的途最小值意思就是第一位数据对应的第一个实际键值编号

        0x29:用的途最大值对应的最后一个键值编号

        0x81:最后是定义输入报告的数据类型

        总结:先告诉别人我这个报告的是键盘数据,上传数据里有8个键值一个bit代表一个键值,松开和按下两种状态只需要1个bit就能表示最大值是1最小值是0。然后就是定义这个8个键值分别是哪8个,第一个是左边的CTRL最后一个是右边的GUI键(具体键值序号和顺序查阅:HID Usage Tables)。基本上这样就算设置完键盘代表8个功能键的的第一个byte。

       

        同理配置剩下的15个byte(我配置输入长度是16byte除去第一个byte,普通按键有15个byte最多支持120个按键)
0x05, 0x07,       //   Usage Page (Key Codes),
0x95, 0x78,       //   Report Count (120),
0x75, 0x01,       //   Report Size  (1),
0x15, 0x00,       //   Logical Minimum (0),
0x25, 0x01,       //   Logical Maximum (1),
0x19, 0x00,       //   Usage Minimum (0),
0x29, 0x65,       //   Usage Maximum (101),
0x81, 0x02,       //   Input (Data, Variable, Absolute),

        配置到这里把程序编译烧录连接到电脑就能检测到你的设备是一个HID键盘,如果没有找到就要检查一下你的所有报表描述符。

USB HID键盘实现全键无冲解析

输入输出数据解析

输出报告处理

case UIS_TOKEN_OUT:
{
    len = R8_USB_RX_LEN;
    if(SetupReqCode == 0x09)
    {
        PRINT("[%s] Num Lock\t", (pEP0_DataBuf[0] & (1<<0)) ? "*" : " ");
        PRINT("[%s] Caps Lock\t", (pEP0_DataBuf[0] & (1<<1)) ? "*" : " ");
        PRINT("[%s] Scroll Lock\n", (pEP0_DataBuf[0] & (1<<2)) ? "*" : " ");
    }
}
break;

        CH573的CompoundDev这个Demo里的这段代码是处理LED灯的输出报告,输出报告是上面HID类报表描述符配置的。测试方法,接上你的开发板的串口打印,用其他键盘或者开发板自己上报分别按下Num Lock、Caps Lock、Scroll Lock,看看输入报告能不能正常更新指示灯的状态。(指示灯的状态并不是键盘自己记录的,每次键盘连接到电脑或者指示灯状态有更新的时候,电脑都会主动输出指示灯的状态)

输入报告

/*********************************************************************
 * @fn      DevHIDKeyReport
 *
 * @brief   上报键盘数据
 *
 * @return  none
 */
void DevHIDKeyReport(uint8_t key)
{
    HIDKey[2] = key;
    memcpy(pEP1_IN_DataBuf, HIDKey, sizeof(HIDKey));
    DevEP1_IN_Deal(sizeof(HIDKey));
}



//main
while(1)
{
    mDelaymS(1000);
    DevHIDKeyReport(0xFF);
    mDelaymS(100);
    DevHIDKeyReport(0x00);
}

        尝试一下上传普通键值,在第三个byte上传一个0xFF。测试结果如下图;对一下HID Usage Tables文件里的键盘键值表,8~15刚好对应的的就是E~L。

USB HID键盘实现全键无冲解析

        全键无冲表示普通按键的后面15个byte和第一个byte的表示方式相同。标准键盘和全键无冲第一个byte的格式是一样的。但8byte的标准键值报表最多只能支持6个普通按键,而且用一个byte来表示一个键值,两种配置的区别就在这里。到这里已经消除了我对瀚文源码里键值映射函数和上报数据格式的疑问。(我只是没想到电脑能够这么聪明,我配置6键的时候他能够理解我上传的就是键值编码,配置全键按照位置排序代替键值的时候也能够正常识别。也希望有大佬给我讲解讲解这一点)

标准的键盘报表格式(8个byte)
功能键*8 保留 key1 key2 key3 key4 key5 key6

        标准的配置方法

                优点:兼容性强(HID标准的键值报表电脑bios能识别)

                缺点:最多只能同时按下6个普通按键

        无冲的配置方法

                优点:支持同时按下多个键

                缺点:电脑只有进了系统才能正常使用、键盘和电脑要处理更多键值而增加负荷(对于如今的电脑只是九牛一毛)

其他

        键盘按键测试:键盘按键测试在线 - 键盘测试工具 - 键盘连键检测 (bmcx.com)

        USB中文网里面的USB和HID解析非常详细:USB中文网 - USB技术开发交流 (usbzh.com)

        USB学习视频: 《USB技术应用与开发》第一讲:认识USB传输_哔哩哔哩_bilibili文章来源地址https://www.toymoban.com/news/detail-493652.html

到了这里,关于USB HID键盘实现全键无冲解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第10课【STM32 USB通讯协议实战】HID键盘+CDC虚拟串口组合设备

    文章中的部分概念可参考第9课【USB协议】USB总线 接口 端点 管道 数据包 枚举 STM32_USB-FS-Device_Lib V4.1.0 USB协议中为了提供对多样设备的支持,定义了许多外部设备子类,常见的包括: 人机交互类设备HID(Human Interface Device) 通信类设备CDC(Communicate Device Class) 大容量存储设备

    2024年02月04日
    浏览(59)
  • STM32CubeMX教程31 USB_DEVICE - HID外设_模拟键盘或鼠标

    正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX软件配置STM32F407开发板 USB_OTG_FS为工作在Human Interface Device Class (HID)(人机接口设备类)模式下的USB_DEVICE(USB从机),利用上下左右四

    2024年02月19日
    浏览(40)
  • stm32 USB复合设备 cubeMX库一键生成 多路CDC串口 HID鼠标键盘 Composite Device

    最近有个需求,需要同时用usb键盘鼠标和虚拟串口等,因为平时没怎么研究过usb协议,所以自己写复合设备一直没有成功,然后正巧在github上看到了一个stm32的一个usb复合设备库,可以快速配置usb组合设备,并且支持超级多路串口 Gihub地址 https://github.com/alambe94/I-CUBE-USBD-Compo

    2024年02月09日
    浏览(63)
  • STM32:Custom HID实现USB双向通信

    本文章主要讲了使用STM32的USB Device,实现控制板和电脑通信功能。从而实现,上位机对控制板进行调试。 USB Device可以有多种类型,实现双向通信的话,推荐使用Custom HID类型。 首先使用STM32CubeMx实现功能引脚配置并且生成对应的工程文件。   Middleware设置USB_DEVICE    配置时钟

    2024年02月13日
    浏览(42)
  • stm32实现hid键盘

     前面的cubelmx项目配置参考 stm32实现hid鼠标-CSDN博客 https://blog.csdn.net/anlog/article/details/137814494?spm=1001.2014.3001.5502 两个项目的配置完全相同。 代码 引用 键盘代码: 替换hid设备描述符 先屏蔽鼠标设备描述符 替换为键盘设备描述符 修改宏定义  修改大小为63U  运行后如下图 参

    2024年04月17日
    浏览(38)
  • GD32F303基于USBD库的usb custom hid 双向通讯实现

    默认已经建立好需要移植的GD32F303空白工程 环境:keil   GD库版本: V2.1.4 通讯工具: 链接:https://pan.baidu.com/s/1Ukuy0u52C9ufPGz9QcHONA  提取码:d9rf 正文开始 USBD库植步骤: 找到GD官网的软件包 本文中用的是GD32F30x_Firmware_Library_V2.1.4 将FirmwareGD32F30x_usbd_library 文件夹全部拷贝至工程

    2023年04月09日
    浏览(42)
  • USB标准键盘按键数据包格式解析

    标准键盘一次发送8个字节,解释如下: BYTE1 – |–bit0: Left Control是否按下,按下为1 |–bit1: Left Shift 是否按下,按下为1 |–bit2: Left Alt 是否按下,按下为1 |–bit3: Left GUI 是否按下,按下为1 |–bit4: Right Control是否按下,按下为1 |–bit5: Right Shift 是否按下,按下为1 |–bit6: Right

    2024年02月01日
    浏览(43)
  • 【usb】linux内核USB键盘驱动解析--普通键值上报及转化

    建议阅读前置文章【usb】linux内核USB键盘驱动解析–特殊键值上报及转化 以Linux5.10内核中USB键盘驱动为例进行解析:https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.gz 文件路径:linux-5.10/drivers/hid/usbhid/usbkbd.c 本次我们主要分析第120~139行的这个for循环。 for循环变量i范围是

    2023年04月08日
    浏览(37)
  • Android HID设备(键盘、遥控等)功能实现流程及键值映射关系

    HID (Human Interface Device,人机接口设备)是USB设备中常用的设备类型,是直接与人交互的USB设备,例如键盘、遥控器、鼠标与游戏杆等。在USB设备中,HID设备的成本较低。     之前文章 android 键盘(遥控)键值定义大全 中整理了android中各种功能键值定义,那么从键盘按键到

    2024年02月04日
    浏览(37)
  • 【GD32F427开发板试用】+使用USBFS轻松实现HID键盘应用

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者: 不锈钢铁侠 最近有项目需要用到键盘自动输入功能,提升工作效率。故使用该开发板实现自定义输入内容并通过按键控制自动通过usb输出。 在官方GD32F4xx_Firm

    2024年02月12日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包