目录

前言

设备描述符

配置描述符

配置描述符

接口描述符

HID描述符

端点描述符

HID类报表描述符

输入输出数据解析

其他


前言

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

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

设备描述符

const uint8_t MyDevDescr[0x12] = {0x12,            //bLenght0x01,            //bDescriptorType0x00,0x02,       //bcdUSB0x00,            //bDeviceClass0x00,            //bDeviceSubClass0x00,            //bDeviceProtocol0x40,            //bMaxPacketSize00x3d,0x41,       //idVendor0x07,0x21,       //idProduct0x00,0x01,       //bcdDevice0x01,            //iManufacturer0x02,            //iProduct0x03,            //iSerialNumber0x01             //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,                                   //bLenght0x02,                                   //bDescriptorType0x34,0x00,                              //wTotalLength0x01,                                   //bNumInterfaces0x01,                                   //bConfigurationValue0x00,                                   //iConfiguration0xA0,                                   //bmAttributes0x32,                                   //MaxPower//接口描述符,键盘功能0x09,                                   //bLenght0x04,                                   //bDescriptorType0x00,                                   //bInterfaceNumber0x00,                                   //bAlternateSetting0x01,                                   //bNumbEndpoints0x03,                                   //bInterfaceClass0x01,                                   //bInterfaceSubClass0x01,                                   //bInterfaceProtocol0x00,                                   //iInterface//HID类描述符0x09,                                   //bLenght0x21,                                   //bDescriptorType0x11,0x01,                              //bcdHID0x00,                                   //bCountryCode0x01,                                   //bNumDescriptors0x22,                                   //bDescriptorType0x39,0x00,                              //wDescriptorLength//端点描述符0x07,                                   //bLenght0x05,                                   //bDescriptorType0x81,                                   //bEndpointAddress0x03,                                   //bmAttributes0x0A,0x00,                              //wMaxPacketSize0x01                                    //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 report0x05, 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键盘,如果没有找到就要检查一下你的所有报表描述符。

输入输出数据解析

输出报告处理

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。

全键无冲表示普通按键的后面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

USB HID键盘实现全键无冲解析相关推荐

  1. ikbcf87全键无冲_机械键盘开全键无冲好吗?

    什么鬼 大半夜让我刷到这个问题. 默认6键无冲 是为了兼容性.usb键盘标准协议如果我没记错的话应该是64b一个包 最前面八位是包头 接下来八位是是功能键 记录ctrl alt shift 和win有 ...

  2. 机械键盘中的六键无冲突和全键无冲突

    六键无冲突 首先所谓的6键无冲是指这款键盘最多只可以同时按六个键,超过6键电脑系统便无法识别进而产生冲突(搞不好会程序混乱,出现死机,半天反映不过来的现象). 说明: 6键无冲的键盘大多都是采用USB ...

  3. ikbcf87全键无冲_【IKBC F87 机械键盘使用总结】键帽|背光_摘要频道_什么值得买...

    IKBC F87 机械键盘使用总结(键帽|背光) ikbc F87黑色红轴机械键盘表达出了cherry红轴轻触即发.无段落感.回弹迅速的特点.全键手感一致性良好.用习惯了pbt键帽的我用abs键帽的F ...

  4. 六键无冲和全键无冲哪个好_机械键盘6键无冲突和全无冲突的差别

    展开全部 一.同时有效按键的最多个数区别:机械键盘的按键冲突是指用户在32313133353236313431303231363533e59b9ee7ad9431333431356132使用电脑机械键 ...

  5. STM32 keyboard USB HID键盘功能的实现

    参考地址:https://blog.csdn.net/a65135793/article/details/80287250 相关文章 ·1.STM32完成USB_Keyboard的实验总结----ht ...

  6. USB HID转蓝牙鼠键宏指纹解锁

    USB-HID-BLER 将有线鼠标键盘游戏手柄等USB HID转换为蓝牙设备,附带鼠键宏和指纹解锁功能. 硬件开源地址  前作 主要功能 使用esp32-c3的GPIO模拟USB HOST,识别低速 ...

  7. android usb hid键盘键值,avr模拟电脑USBHID键盘,键值对应关系问题,和ASCII表对应符不符?请教!...

    原帖:http://www.ourdev.cn/bbs/bbs_content_all.jsp?bbs_sn=3253865 上面是用attiny45模拟usb键盘,定时发送CapsLocker(大写 ...

  8. 机械键盘和薄膜键盘哪个耐用 机械键盘和薄膜键哪个手感好

    两者原理基本一致, 每个键就是一个开关, 按下导通, 松开断开.就是这个"开关"设计的不一样. 电脑用机械键盘还是薄膜键盘这些点很重要看过你就懂了 http://www.adian ...

  9. STM32自定义键盘(二)STM32单片机的USB接口-HID键盘

    STM32自定义键盘(二)STM32单片机的USB接口-HID键盘 HID描述符 生成HID键盘工程模板 修改HID报告描述符 键值数据发送 USB HID 键盘键值表 HID描述符 请参考这位博主的 ...

最新文章

  1. HTML在网页设计中是什么作用?
  2. OpenCV卡尔曼滤波介绍与代码演示
  3. Xampp安装时需注意的事项
  4. 北工大计算机学院教授,北工大计算机学院计算机科学与技术导师介绍:周艺华...
  5. android alertdialog 背景透明,Android Alertdialog弹出框设置半透明背景
  6. 检测性异常VS非检测性异常
  7. OBJECT_ID()的使用方法
  8. 借个iPad玩玩,越狱4.2.1成功
  9. java cassandra连接池_Cassandra Java驱动程序的最佳设置只能写入本地数据中心
  10. TensorFlow模型保存和提取方法
  11. BFS和DFS的java实现
  12. 计算机组成原理:最详细笔记
  13. 计算机财务管理财务模型实验报告,《计算机财务管理》课程介绍
  14. 【使用最新版本的cef,编译libcef_dll_wrapper】
  15. 1.用 perf report 分析四个for进程
  16. 金山云直播问答解决方案来了!让客户一天上线
  17. PgRGGmiCst
  18. android 系统后台进程数限制
  19. FPGA学习日记(八)SDRAM的读写测试
  20. 第十部分 项目风险管理

热门文章

  1. 2021.12.20(第二周) 实习周记lzhuan
  2. 计算机入门基础知识大全
  3. FindPic 找图
  4. java数组希尔排序及时间复杂度
  5. TM1814 WRGB的一种驱动方法:UART
  6. 找不到合适好用的redis客户端工具?试试官方的客户端工具RedisInsight
  7. 如何查看备份记录及删除之前的备份记录
  8. AMESim与Matlab/Simulink联合仿真步骤(最新软件版本!)
  9. STM32CubeMX学习之旅1:点亮一个LED灯
  10. Ubuntu 下面的aMule 的 Kad 或者 Ed2k 连不上