赞
踩
本文主要在上一节的基础上,对相关的设备以及报文描述符配置,实现USB键盘。
这里只是汇总各个配置在哪个文件中,方便笔者后续复习时,方便查找。可先看下一部分,再回来看这。
生成后的工程文件夹如下图:(划斜线的为笔者自己创建的)
在USB_DEVICE/App路径下的usbd_desc.c及其头文件包含了设备描述符。
即配置VID信息,USB版本以及速度等信息,保持默认即可(如下图),还有一些其他描述符,具体有什么用,需了解USB协议发送的具体过程。这里笔者没深究。
usb_device.c主要写的USB初始化的相关操作,其中定义了USB的句柄,后续在main函数以及其他函数要用时需要声明(extern USBD_HandleTypeDef hUsbDeviceFS;)
usbd_custom.hid_if.c文件则是配置后续要发送报文的格式(即要送的报文代表什么含义,要发送多少个字节)。(需要修改的文件)。
在Middlewares文件夹下的usbd_customhid.c文件则包含了配置描述符(PC要对该USB口配置成什么类型,输出电流大小等信息,是否支持3.0,配置为HS、FS、或其他速度)。其头文件还定义各种报文以及缓冲区的大小。(需要修改的文件)。
打开usbd_customhid.c文件,找到如下代码,每一行配置的什么,后面都有注释详解的。
因为笔者这款芯片只支持FS模式,且在cubemx中也选择的FS模式,故修改FS这个数组,若为HS或其他速度模式,则在C文件下翻,找到对应的修改即可。
- __ALIGN_BEGIN static uint8_t USBD_CUSTOM_HID_CfgFSDesc[USB_CUSTOM_HID_CONFIG_DESC_SIZ] __ALIGN_END =
- {
- 0x09, /* bLength: Configuration Descriptor size */
- USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
- USB_CUSTOM_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*/
- 0xC0, /*bmAttributes: bus powered */
- 0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
-
- /************** Descriptor of CUSTOM HID interface ****************/
- /* 09 */
- 0x09, /*bLength: Interface Descriptor size*/
- USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
- 0x00, /*bInterfaceNumber: Number of Interface*/
- 0x00, /*bAlternateSetting: Alternate setting*/
- 0x02, /*bNumEndpoints*/
- 0x03, /*bInterfaceClass: CUSTOM_HID*/
- 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
- 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
- 0, /*iInterface: Index of string descriptor*/
- /******************** Descriptor of CUSTOM_HID *************************/
- /* 18 */
- 0x09, /*bLength: CUSTOM_HID Descriptor size*/
- CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/
- 0x11, /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/
- 0x01,
- 0x00, /*bCountryCode: Hardware target country*/
- 0x01, /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
- 0x22, /*bDescriptorType*/
- USBD_CUSTOM_HID_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
- 0x00,
- /******************** Descriptor of Custom HID endpoints ********************/
- /* 27 */
- 0x07, /*bLength: Endpoint Descriptor size*/
- USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
-
- CUSTOM_HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
- 0x03, /*bmAttributes: Interrupt endpoint*/
- CUSTOM_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
- 0x00,
- CUSTOM_HID_FS_BINTERVAL, /*bInterval: Polling Interval */
- /* 34 */
-
- 0x07, /* bLength: Endpoint Descriptor size */
- USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */
- CUSTOM_HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/
- 0x03, /* bmAttributes: Interrupt endpoint */
- CUSTOM_HID_EPOUT_SIZE, /* wMaxPacketSize: 2 Bytes max */
- 0x00,
- CUSTOM_HID_FS_BINTERVAL, /* bInterval: Polling Interval */
- /* 41 */
- };
修改此三行
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0x32表示为该口提供的最大输出电流。(0x32换算十进制即50,再×2 即100)即这里提供最大100ma输出电流。USB2.0最大提供输出500ma电流,即最大设置为0xFA;
这里使用的开发板且只有一个按键,0x32绰绰有余。若单独画PCB制作键盘,设置0xFA
0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/这里设置有无BOOT
笔者还不太了解这块,故给的0x00
0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/这里设置0x01表示键盘。
其他不变
在usbd_custom.hid_if.c这个文件中。
题外话:具体为什么这样配置,参考这篇文章:HID报文讲解_skdev的博客-CSDN博客
想做其他操作,可以配合手册和生成软件,实现其他HID类设备
具体配置:找到 __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = 这个数组
将其中内容修改为:
- __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
- {
- 0x05, 0x01, // Usage Page (Generic Desktop),
- 0x09, 0x06, // Usage (Keyboard),
- 0xA1, 0x01, // Collection (Application),
- 0x85, 0x01, // REPORT_ID (1)
- // bitmap of modifiers
- 0x75, 0x01, // Report Size (1),
- 0x95, 0x08, // Report Count (8),
- 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),
- 0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
- // bitmap of keys
- 0x95, 0x78, // Report Count (120),
- 0x75, 0x01, // Report Size (1),
- 0x15, 0x00, // Logical Minimum (0),
- 0x25, 0x01, // Logical Maximum(1),
- 0x05, 0x07, // Usage Page (Key Codes),
- 0x19, 0x00, // Usage Minimum (0),
- 0x29, 0x77, // Usage Maximum (),
- 0x81, 0x02, // Input (Data, Variable, Absolute),
- 0xC0 /* END_COLLECTION */
- };
细数一共有41个字节,故USBD_CUSTOM_HID_REPORT_DESC_SIZE这个宏定义要修改为41
即这个描述数组有多少个字节,USBD_CUSTOM_HID_REPORT_DESC_SIZE这个宏定义就必须是多少,有一点误差都会导致识别失败。
在usbd_conf.h这个头文件里面修改USBD_CUSTOM_HID_REPORT_DESC_SIZE的大小
修改为41,数字后面的U表示无符号数。
此时,我们保存编译下载到单片机。
会发现,识别到键盘设备,到此,成功一大半了。接下来进行按键发送报文。
上述报文描述符格式对应下图这种表。(已打包到资源文件)
首先单独新建一个C文件和一个头文件,写报文发送函数。
新建一个枚举体,存放要放入的HID报文数据。
(枚举体小知识点:未给初始值时,默认值由0开始,之后自加1赋值
即:下列枚举体中的RESERVED=0,则ERROR_ROLL_OVER=1,POST_FAIL=2...以此类推。)
- typedef enum
- {
- /*------------------------- HID report data -------------------------*/
- LEFT_CTRL = -8,LEFT_SHIFT = -7,LEFT_ALT = -6,LEFT_GUI = -5,
- RIGHT_CTRL = -4,RIGHT_SHIFT = -3,RIGHT_ALT = -2,RIGHT_GUI = -1,
-
- RESERVED = 0,ERROR_ROLL_OVER,POST_FAIL,ERROR_UNDEFINED,
- A,B,C,D,E,F,G,H,I,J,K,L,M,
- N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
- NUM_1/*1!*/,NUM_2/*2@*/,NUM_3/*3#*/,NUM_4/*4$*/,NUM_5/*5%*/,
- NUM_6/*6^*/,NUM_7/*7&*/,NUM_8/*8**/,NUM_9/*9(*/,NUM_0/*0)*/,
- ENTER,ESC,BACKSPACE,TAB,SPACE,
- MINUS/*-_*/,EQUAL/*=+*/,LEFT_U_BRACE/*[{*/,RIGHT_U_BRACE/*]}*/,
- BACKSLASH/*\|*/,NONE_US/**/,SEMI_COLON/*;:*/,QUOTE/*'"*/,
- GRAVE_ACCENT/*`~*/,COMMA/*,<*/,PERIOD/*.>*/,SLASH/*/?*/,
- CAP_LOCK,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,
- PRINT,SCROLL_LOCK,PAUSE,INSERT,HOME,PAGE_UP,DELETE,END,PAGE_DOWN,
- RIGHT_ARROW,LEFT_ARROW,DOWN_ARROW,UP_ARROW,PAD_NUM_LOCK,
- PAD_SLASH,PAD_ASTERISK,PAD_MINUS,PAD_PLUS,PAD_ENTER,
- PAD_NUM_1,PAD_NUM_2,PAD_NUM_3,PAD_NUM_4,PAD_NUM_5,
- PAD_NUM_6,PAD_NUM_7,PAD_NUM_8,PAD_NUM_9,PAD_NUM_0,
- PAD_PERIOD , NONUS_BACKSLASH,APPLICATION,POWER,PAD_EQUAL,
- F13,F14,F15,F16,F17,F18,F19,F20,F21,F22,F23,F24, EXECUTE,
- HELP,MENU,SELECT,STOP,AGAIN,UNDO,CUT,COPY,PASTE,FIND,MUTE,VOLUME_UP,VOLUME_DOWN,
- FN = 1000
- /*------------------------- HID report data -------------------------*/
- }KeyCode_t;
一共128个位,即16个字节(对应上文的报文描述数组)。一个位表示一个按键。接下来定义uint8_t hidbuffer[17];一个17位的数组。有17位的原因:第一个字节表示是ID号,后16个字节表示按键的状态,即128位,一位对应一个按键。(比如hidbuffer[1]=0x01,其他均为0,就表示LEFT_RIGHT这个按键被按下了。)(发送的报文: 0表示没按下,1表示没按下)
现在就可以写按键检测并发送函数了:
- uint8_t hidbuffer[17];
- extern USBD_HandleTypeDef hUsbDeviceFS;
-
- void keyboard()
- {
- memset(hidbuffer,0,17);
- hidbuffer[0] = 1;
- if((HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5))==0)
- {
- DelayUs(100);
- if((HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5))==0)
- {
- hidbuffer[3] = 0x01;
- }
- }
- USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,hidbuffer,17);
- }
memset函数在"string.h"这个头文件中,这个函数的作用是将hidbuffer这个数组全部请0。
hidbuffer【0】=1;即ID号等于1,即是键盘的ID号(在上面报文描述数组中0x85,0x01这一句设置的)。这里因为我用的开发板只用了一个按键,故我把这个按键表示为E,"E"键在枚举体中是第17个,即在hidbuffer数组中就是hidbuffer【3】的第0位。
DelayUs(100);是为了按键消抖,让hidbuffer【3】=0x01,即表示按键按下时,让对应"E"这位等于1.然后发送报文即可(利USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,hidbuffer,17);这个函数,该函数在 "usbd_customhid.h"中)
注:需要hUsbDeviceFS这个结构体不是在main中定义的,而是在USB_DEVICE.H中,故需要写 extern USBD_HandleTypeDef hUsbDeviceFS;
main函数调用即可,延时1ms表示1ms扫描一次按键。
然后编译烧录进单片机,开始测试
测试正常。至此实现完成。
发送报文数据需要及时发送。否则PC机一直读的上一次报文,导致按键一直在被打印。
将HAL_DELAY(1)改为1000,相当于1秒扫描一次,并发送报文。此时烧录进单片机,按下按键一次会发现"e"键在一直被打印,因为没有即使更新报文(即以及松开了,没发送过去)。
消抖若过久,会导致有时候按下,并没有反应。因为有可能按下这个时间,程序还在上一次消抖那里延时。
笔者曾想,按下一个按键实现给主机保送多个不同的数据,比如按下一个按键就输入了密码这种操作,但在多次发送过程中,要么乱序,要么一直发送,目前未解决。(想了下,如果一个按键就输入了全部密码,那还要密码干嘛,就没继续研究了)
附录:工程代码下载链接:https://download.csdn.net/download/qq_21566881/87078754
HID手册及配置工具下载链接:https://download.csdn.net/download/qq_21566881/87073789?spm=1001.2014.3001.5503
(审核完成后上传)
推荐下载这个软件 查看电脑接受到的报文数据,根据接受的数据来调试
软件叫BUS HOUND 几MB大小,上手很快
本文实现了STM32的USB-HID键盘的应用,下一篇文章将介绍基于稚晖君开源DIY的瀚文键盘的按键映射源码分析,看完下一篇后,便可动手画PCB板,DIY自己的一个USB键盘。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。