[STM32F4]

授人以渔 第四节:基于stm32f407实现usb鼠标键盘(2个interface

[复制链接]
6407|26
手机看帖
扫描二维码
随时随地手机跟帖
z755924843|  楼主 | 2017-3-15 22:52 | 显示全部楼层 |阅读模式
上一节说到实现usb键盘,这一节准备在此基础上实现usb 鼠标+键盘,
并且使用两种方式实现一种是:鼠标和键盘使用一个接口描述符,另外一种就是鼠标和键盘分别使用不同的接口描述符
使用两个接口的好处就是,使用一个接口作为鼠标或者键盘,另外一个接口可以作为我们的自定义通信使用,发送一些数据量不是很大的数据。因为在windows系统下,鼠标键盘属于独占设备,是不允许用户操作的,所以如果想实现鼠标键盘功能的同时还能通信的话,只能使用这种方式。
直接上代码:
一.我们先说说如何实现1个接口描述符实现鼠标+键盘
使用上一节键盘的例程:
修改起来很简单只需要修改报告描述符就可以了:
新建一个报告描述符:
__ALIGN_BEGIN static uint8_tHID_KEYBOARDMOUSE_ReportDesc[HID_KEYBOARDMOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
  //每行开始的第一字节为该条目的前缀,前缀的格式为:
//D7~D4bTagD3~D2bTypeD1~D0bSize。以下分别对每个条目注释。

/************************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*/

} ;
由于增加0x820x02两个端点
所以需要在初始化端点函数中初始化这个端点:
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)函数
1.png
然后在增加一个发送函数

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);
至此实现了鼠标键盘消息的分别发送。


snowflyin| | 2017-3-16 10:52 | 显示全部楼层
太棒了, 期待第五节, 学习了。

使用特权

评论回复
whtwhtw| | 2017-3-16 11:42 | 显示全部楼层
很好,赞一个

使用特权

评论回复
爱不孤单| | 2017-7-13 11:50 | 显示全部楼层
刚刚看了下, 发送数据的的函数 能直接调用 USBD_HID_SendReport()函数吗?(里面的 EP根据实际的写)

使用特权

评论回复
爱不孤单| | 2017-7-13 13:52 | 显示全部楼层
还有楼主,如果 在Interface Descriptor描述符中,nInterfaceProtocol 种类 如果选择了0x01,
就设置成了键盘协议,是不是应该设置为0呢?

使用特权

评论回复
混吉| | 2017-8-8 14:11 | 显示全部楼层
请问,看了您的模拟键盘。请问一直发送按键不停止如何解决?

使用特权

评论回复
z755924843|  楼主 | 2017-8-9 08:49 | 显示全部楼层
混吉 发表于 2017-8-8 14:11
请问,看了您的模拟键盘。请问一直发送按键不停止如何解决?

在发送一组0 就行了。

使用特权

评论回复
YYaiPAOFU| | 2017-9-8 16:45 | 显示全部楼层
我枚举完之后 电脑只识别到是USB Input Device  但是没有枚举成为鼠标或者键盘  我找了很久都找不到问题  楼主能帮帮我吗

使用特权

评论回复
liuxynzy| | 2017-10-31 11:18 | 显示全部楼层
话说CUB生成的代码都只有一个端子,现在改俩端子 难道不修改TXfifo吗?

使用特权

评论回复
lyliuzhiping| | 2018-5-30 16:18 | 显示全部楼层
请问楼主可以共享2个interface的usb键盘鼠标代码码?

使用特权

评论回复
wono01| | 2018-10-26 16:35 | 显示全部楼层
我高速接口可以当全速接口使用吗?

使用特权

评论回复
gaoke231| | 2018-10-26 20:45 | 显示全部楼层
写完可以出一本书了

使用特权

评论回复
gaoke231| | 2018-10-26 20:45 | 显示全部楼层
鼠标需要装驱动吗

使用特权

评论回复
gaoke231| | 2018-10-26 20:46 | 显示全部楼层
能在屏幕上显示就更厉害了

使用特权

评论回复
xuanhuanzi| | 2018-10-26 22:51 | 显示全部楼层
一个USB接口可以实现多个设备吗

使用特权

评论回复
aspoke| | 2018-10-28 21:54 | 显示全部楼层
                  

使用特权

评论回复
232321122| | 2018-10-28 21:54 | 显示全部楼层
usb鼠标很腻害。

使用特权

评论回复
ghuca| | 2018-10-28 21:54 | 显示全部楼层
需要驱动吗?            

使用特权

评论回复
soodesyt| | 2018-10-28 21:54 | 显示全部楼层
usb硬件是怎么设计的

使用特权

评论回复
mnynt121| | 2018-10-28 21:55 | 显示全部楼层
usb 鼠标+键盘很给力的设计。  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:嵌入式相关网站喜欢的朋友了解一下http://www.micropython.group

31

主题

260

帖子

39

粉丝