上一节说到实现usb键盘,这一节准备在此基础上实现usb 鼠标+键盘, 并且使用两种方式实现一种是:鼠标和键盘使用一个接口描述符,另外一种就是鼠标和键盘分别使用不同的接口描述符。 使用两个接口的好处就是,使用一个接口作为鼠标或者键盘,另外一个接口可以作为我们的自定义通信使用,发送一些数据量不是很大的数据。因为在windows系统下,鼠标键盘属于独占设备,是不允许用户操作的,所以如果想实现鼠标键盘功能的同时还能通信的话,只能使用这种方式。 直接上代码: 一.我们先说说如何实现1个接口描述符实现鼠标+键盘 使用上一节键盘的例程: 修改起来很简单只需要修改报告描述符就可以了: 新建一个报告描述符: __ALIGN_BEGIN static uint8_tHID_KEYBOARDMOUSE_ReportDesc[HID_KEYBOARDMOUSE_REPORT_DESC_SIZE] __ALIGN_END = { //每行开始的第一字节为该条目的前缀,前缀的格式为: //D7~D4:bTag。D3~D2:bType;D1~D0:bSize。以下分别对每个条目注释。
/************************USB键盘部分报告描述符**********************/ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE (Keyboard) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, //Report ID (1) 0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29,0xe7, // USAGE_MAXIMUM (KeyboardRight GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x08, // REPORT_COUNT (8) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0xFF, // LOGICAL_MAXIMUM (255) 0x05,0x07, // USAGE_PAGE (Keyboard/Keypad) /*20x2*/ 0x19, 0x00, // USAGE_MINIMUM (Reserved (no eventindicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x05, // REPORT_COUNT (5) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 0x29, 0x05, // USAGE_MAXIMUM (Kana) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x03, // REPORT_SIZE (3) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 0xc0, // END_COLLECTION /*14x2-1*/ /************************USB鼠标部分报告描述符**********************/ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x02, //Report ID (2) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75,0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) /*20X2*/ 0x09, 0x38, // USAGE (Wheel) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x03, // REPORT_COUNT (3) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xc0,0xc0 /*7x2*/ }; 然后修改配置描述符中HID描述符中的报告描述符长度: /******************** Descriptor ofJoystick Keyboard HID ********************/ /*18 */ 0x09, /*bLength: HIDDescriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID ClassSpec release number*/ 0x01, 0x00, /*bCountryCode:Hardware target country*/ 0x01, /*bNumDescriptors:Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_KEYBOARDMOUSE_REPORT_DESC_SIZE,/*wItemLength:Totallengthof Reportdescriptor*/ 0x00,
然后修改static uint8_t USBD_HID_Setup(USBD_HandleTypeDef *pdev,USBD_SetupReqTypedef *req)函数中的报告描述符索引: case USB_REQ_GET_DESCRIPTOR: if( req->wValue >> 8 == HID_REPORT_DESC) { len = MIN(HID_KEYBOARDMOUSE_REPORT_DESC_SIZE , req->wLength); pbuf = HID_KEYBOARDMOUSE_ReportDesc; } 修改完成后,就可以通过一个端点即发送鼠标内容,又能发送是键盘内容 发送键盘消息: 根据报告描述符格式:第一个字节等于1,表示发送的是键盘消息 txbuffer[0] = 1; txbuffer[3] = 0x4; USBD_LL_Transmit (&hUsbDeviceFS, HID_EPIN_ADDR,txbuffer,9); 根据报告描述符格式:第一个字节等于2,表示发送的是鼠标消息 txbuffer[0] = 2; txbuffer[2] = 100; txbuffer[3] = 100; USBD_LL_Transmit (&hUsbDeviceFS, HID_EPIN_ADDR,txbuffer,9);
二.使用两个接口分别发送鼠标和键盘消息 首先修改配置描述符:将配置描述符修改成2 0x09, /* bLength: Configuration Descriptorsize */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_HID_CONFIG_DESC_SIZ, /*wTotalLength: Bytes returned */ 0x00, 0x02, /*bNumInterfaces: 2 interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration:Index of string descriptor describing theconfiguration*/ 0xE0, /*bmAttributes: buspowered and Support Remote Wake-up */ 0x32, /*MaxPower 100 mA:this current is used for detecting Vbus*/ 然后增加一套键盘接口的描述符包括:hid描述符,输入端点描述符,输出端点描述符
/** *\GET_DESCRIPTOR 请求 * \描述符类型及编号 * | 描述符类型 | 编号 * |:-------------------------|:---------- * | 设备描述符(DEVICE) | 1 * | 配置描述符(CONFIGURATION)| 2 * | 字符串描述符(STRING) | 3 * | 接口描述符(INTERFACE) | 4 * | 端点描述符(ENDPOINT) | 5 */
/* USB HID device Configuration Descriptor*/ __ALIGN_BEGIN static uint8_tUSBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END = { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_HID_CONFIG_DESC_SIZ, /*wTotalLength: Bytes returned */ 0x00, 0x02, /*bNumInterfaces: 2interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration:Index of string descriptor describing theconfiguration*/ 0xE0, /*bmAttributes: buspowered and Support Remote Wake-up */ 0x32, /*MaxPower 100 mA:this current is used for detecting Vbus*/
/************** Descriptor of Joystick Mouse interface ****************/ 0x09, /*bLength: InterfaceDescriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting:Alternate setting*/
0x01, /*bNumEndpoints*/
0x03, /*bInterfaceClass:HID*/
0x01, /*bInterfaceSubClass: 1=BOOT, 0=no boot*/ 0x02, /*nInterfaceProtocol : 0=none, 1=keyboard,2=mouse*/ 0, /*iInterface: Indexof string descriptor*/ /******************** Descriptor of Joystick Keyboard HID********************/ /*50*/ 0x09, /*bLength: HIDDescriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID ClassSpec release number*/ 0x01, 0x00, /*bCountryCode:Hardware target country*/ 0x01, /*bNumDescriptors:Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_MOUSE_REPORT_DESC_SIZE,,/*wItemLength: Total length of Reportdescriptor*/ 0x00, /******************** Descriptor of Keyboard input endpoint********************/ /*59 */ 0x07, /*bLength: EndpointDescriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ 0X81, /*bEndpointAddress:Endpoint Address (IN)*/ 0x03, /*bmAttributes:Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10 ms)*/ /*66*/ /*________________________________________________________*/ /************** Descriptor of Joystick Keyboard interface****************/ /*09 */ 0x09, /*bLength: InterfaceDescriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x01, /*bInterfaceNumber:Number of Interface*/ 0x00, /*bAlternateSetting:Alternate setting*/
0x02, /*bNumEndpoints*/
0x03, /*bInterfaceClass:HID*/
0x01, /*bInterfaceSubClass: 1=BOOT, 0=no boot*/ 0x01, /*nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse*/ 0, /*iInterface: Indexof string descriptor*/ /******************** Descriptor of Joystick Keyboard HID********************/ /*18 */ 0x09, /*bLength: HIDDescriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID ClassSpec release number*/ 0x01, 0x00, /*bCountryCode:Hardware target country*/ 0x01, /*bNumDescriptors:Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_KEYBOARD_REPORT_DESC_SIZE,,/*wItemLength: Total length of Reportdescriptor*/ 0x00, /******************** Descriptor of Keyboard input endpoint********************/ /*27 */ 0x07, /*bLength: EndpointDescriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ 0x82, /*bEndpointAddress:Endpoint Address (IN)*/ 0x03, /*bmAttributes:Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10 ms)*/
/******************** Descriptor of Keyboard output endpoint ********************/ /*34 */ 0x07, /*bLength: EndpointDescriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ 0x02, /*bEndpointAddress:Endpoint Address (IN)*/ 0x03, /*bmAttributes:Interrupt endpoint*/ HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10 ms)*/ /*41*/
} ; 由于增加0x82和0x02两个端点 所以需要在初始化端点函数中初始化这个端点: USBD_LL_OpenEP(pdev, 0x82, USBD_EP_TYPE_INTR, HID_EPIN_SIZE); /*Open EP OUT */ USBD_LL_OpenEP(pdev, 0x02, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
然后修改:static uint8_t USBD_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)函数 然后在增加一个发送函数
uint8_t USBD_HID_SendReportKeyboard (USBD_HandleTypeDef *pdev, uint8_t*report, uint16_t len) { USBD_HID_HandleTypeDef *hhid =(USBD_HID_HandleTypeDef*)pdev->pClassData;
if(pdev->dev_state == USBD_STATE_CONFIGURED ) { if(hhid->state == HID_IDLE) { hhid->state = HID_BUSY; USBD_LL_Transmit (pdev, HID_EPIN_ADDR, report, len); } } return USBD_OK; } uint8_t USBD_HID_SendReportMouse (USBD_HandleTypeDef *pdev, uint8_t*report, uint16_tlen) { USBD_HID_HandleTypeDef *hhid =(USBD_HID_HandleTypeDef*)pdev->pClassData;
if(pdev->dev_state == USBD_STATE_CONFIGURED ) { if(hhid->state == HID_IDLE) { hhid->state = HID_BUSY; USBD_LL_Transmit (pdev, 0x82, report, len); } } return USBD_OK; } 在main.c中定义2个数组,分别存储鼠标信息和键盘信息 uint8_tkeytxbuffer[8]={0x0,0x00,0x0,0x00,0x00,0x00,0x00,0x00}; uint8_tmousetxbuffer[4]={0x00,0x00,0x00,0x00};
keytxbuffer[2] = 0x4; USBD_HID_SendReportKeyboard (&hUsbDeviceFS,keytxbuffer,8);
mousetxbuffer[1] = 100; mousetxbuffer[2] = 100; USBD_HID_SendReportMouse (&hUsbDeviceFS,mousetxbuffer,4); 至此实现了鼠标键盘消息的分别发送。
|