发新帖本帖赏金 5.00元(功能说明)我要提问
返回列表
打印
[STM32F4]

基于USBLibV2.1.0实现STM32F407HID鼠标+键盘

[复制链接]
4593|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
z755924843|  楼主 | 2016-3-14 14:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
由于项目的原因,需要使用STM32F407实现USB鼠标+键盘设备+自定义HID设备
在网上找了很久发现都是以前使用stm32f103实现的,并且库函数完全不一样,对于大神来说可能移植起来比较容易,但是对我们这样的新手来说移植起来很是费劲,而且网上这方面的资料比较少,不知道如何下手,这里很感谢圈圈,他的书给我很大帮助。所以我也想把我这段时间的经验分享出来,给论坛里的新手做下参考,避免向我一样走了很多弯路。话不多说直接上代码:
本质上是基于圈圈的代码把库函数中的HID例程改成鼠标+键盘
1.首先要改的是设备描述符(usbd.desc.c)
1).PIDVID
VIDVendor ID,供应商识别码;PIDProductID,产品识别码
这两个在每次更改usb类的时候必须更改,因为Windows如果发现pidvid一样的话就会将此usb设备默认成第一次驱动此vidpid设备时的usb类型。所以提醒大家的是,在调试程序的时候发现怎么改程序都不管用不妨看看是不是应为这两个参数的问题。
__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC]__ALIGN_END =
  {
    0x12,                       /*bLength 描述符大小0x12*/
   USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType设备描述符类型0x01*/
    0x00,                       /*bcdUSB usb规范发布号*/
    0x02,
    0x00,                       /*bDeviceClass类型代码=0表示*/
    0x00,                       /*bDeviceSubClass*/
    0x00,                       /*bDeviceProtocol*/
    USB_OTG_MAX_EP0_SIZE,      /*bMaxPacketSize*/
    LOBYTE(USBD_VID),           /*idVendor*/
    HIBYTE(USBD_VID),           /*idVendor*/
    LOBYTE(USBD_PID),           /*idVendor*/
    HIBYTE(USBD_PID),           /*idVendor*/
    0x00,                       /*bcdDevice rel. 2.00*/
    0x01,
    USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
   USBD_IDX_PRODUCT_STR,      /*Index of product string*/
   USBD_IDX_SERIAL_STR,       /*Index of serial number string*/
    USBD_CFG_MAX_NUM            /*bNumConfigurations*/
  } ; /*USB_DeviceDescriptor */
具体每个字节代表什么大家自己去看USB协议吧。
2.更改配置描述符(usbd_hid_core.c
/* 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_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
  USB_HID_CONFIG_DESC_SIZ,
  /* wTotalLength: Bytesreturned */
  0x00,
  0x01,         /*bNumInterfaces: 1 interface*/
  0x01,         /*bConfigurationValue: Configurationvalue*/
  0x00,         /*iConfiguration: Index of stringdescriptor describing
  the configuration*/
  0xE0,         /*bmAttributes: bus powered andSupport Remote Wake-up */
  0x32,         /*MaxPower 100 mA: this current isused for detecting Vbus*/
  
  /**************Descriptor of Joystick Mouse interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number ofInterface*/
  0x00,         /*bAlternateSetting: Alternatesetting*/
  0x01,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: HID*/
  0x01,         /*bInterfaceSubClass : 1=BOOT, 0=noboot*/
  0x02,        /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of stringdescriptor*/
  /********************Descriptor of Joystick Mouse HID ********************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE,/*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec releasenumber*/
  0x01,
  0x00,         /*bCountryCode: Hardware targetcountry*/
  0x01,         /*bNumDescriptors: Number of HID classdescriptors to follow*/
  0x22,         /*bDescriptorType*/
HID_KEBOARD_REPORT_DESC_SIZE,/*wItemLength: Total length of Reportdescriptor*/
  0x00,
  /********************Descriptor of Mouse endpoint ********************/
  /* 27 */
  0x07,          /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
  
  HID_IN_EP,     /*bEndpointAddress: Endpoint Address(IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_IN_PACKET,/*wMaxPacketSize: 4 Byte max */
  0x00,
  0x0A,          /*bInterval: Polling Interval (10ms)*/
  /* 34 */
} ;具体每个字节代表什么大家也去看USB协议吧,不能随便更改USB协议中有严格的规定。
然后更改报告描述符
__ALIGN_BEGIN static uint8_tHID_ReportDesc[HID_REPORT_DESC_SIZE] __ALIGN_END =
{
  0x05,0x01,                //全局条目,通道数据用于桌面页
  0x09,0x06,         //局部条目,此通道用于键盘
  0xA1,0x01,                        //主条目,定义了具有上述性质的通道集合              
  0x05,0x07,                 //全局条目,用途数据为键盘
  0x19,0xe0,          //局部条目,用途最小值为左ctrl
  0x29,0xe7,          //局部条目,用途最大值为右GUI
  0x15,0x00,                 //全局条目,数据域(位域)最小值为0
  0x25,0x01,                 //全局条目,数据域(位域)最大值为1
  0x95,0x08,                 //全局条目,数据域(位域)数量为8
  0x75,0x01,                 //全局条目,数据域(位域)每个值的长度为1?
  0x81,0x02,                        //主条目,定义了输入页,具有上述属性,结构为INPUT(data,Va,abs)           
  0x95,0x01,                        //全局条目,数据域为数量为1
  0x75,0x08,                        //全局条目,数据域的每个值的长度为8
  0x81,0x03,                               //主条目,定义了输入页,具有上述性质,结构为INPUT(cnst,var,abs);         
  0x95,0x06,                        //全局条目,数据域的数量为6
  0x75,0x08,                        //全局条目,数据域的每个值的长度为8
  0x15,0x00,                        //全局条目,数据域的最小值为0
  0x25,0xff,                          //全局条目,数据域的最大值为ff
  0x05,0x07,                        //全局条目,说明用作键盘页
  0x19,0x00,                        //局部条目,用途最小值为0
  0x29,0x65,                        //局部条目,用途最导致为0x65
  0x81,0x00,                               //主条目,定义了输入页,具有上位性质,结构为INPUT(data,vry,abs)数据不可变的数组              
  0xc0                                               //主条目,用于关闭最上方定义的集合

}
//具体写法可参考圈圈代码
其实报告描述符的写法也是挺虐人的,不过大部分情况下是不用自己自己写的,照抄圈圈的就行了,但是如果想自己更改的话,需要自己研究报告描述符的写法。网上有很多,但是感觉大部分都写的不是很清楚,有时间的话我在上传一份如何写报告描述符的文档供大家参考。
修改完成后还需要最后一步就是将报告描述符传递上去。
需要修改函数
static uint8_t USBD_HID_Setup (void  *pdev,
                               USB_SETUP_REQ *req)
中的
case USB_REQ_GET_DESCRIPTOR:
      if( req->wValue>> 8 == HID_REPORT_DESC)
      {
        len = MIN(HID_REPORT_DESC_SIZE , req->wLength);
        pbuf = HID_ _ReportDesc;
      }
修改完成后重新编译,下载程序就ok了。
这只是圈圈中的第一种方法,在一个端点上实现。
圈圈中还有另外一种方法就是在新定义一个接口来实现。
其实也很简单,就是定义两个接口,两个报告描述符然后再在
case USB_REQ_GET_DESCRIPTOR:
中定义
if(req->wIndex==0){
报告描述符1                        
}
else if(req->wIndex==1){
报告描述符2
}OK



打赏榜单

xyz549040622 打赏了 5.00 元 2016-03-14
理由:原创分享!

沙发
yuangaoping| | 2016-3-14 15:32 | 只看该作者
一直用的stm32f103,留个记号,以后会用到

使用特权

评论回复
板凳
xyz549040622| | 2016-3-14 15:42 | 只看该作者
这个值得分享!分享更详细的过程和代码,有更多打赏!到时楼主记得@我!

使用特权

评论回复
地板
z755924843|  楼主 | 2016-3-14 16:08 | 只看该作者
xyz549040622 发表于 2016-3-14 15:42
这个值得分享!分享更详细的过程和代码,有更多打赏!到时楼主记得@我!

好的,谢谢打赏。:victory:

使用特权

评论回复
5
仙景| | 2016-3-14 17:07 | 只看该作者
mark,感谢分享

使用特权

评论回复
6
hxhaawt| | 2016-3-15 13:47 | 只看该作者
mark 正想搞这东西呢。。。感谢楼主分享,圈圈那本书我就看了前面一些,有空得看看了。。。

使用特权

评论回复
7
littleming1028| | 2016-3-15 14:03 | 只看该作者
路过~~~

使用特权

评论回复
8
soybeanmeal| | 2016-3-17 19:25 | 只看该作者
和usblib有什么关系呢

使用特权

评论回复
9
z755924843|  楼主 | 2016-3-17 19:42 | 只看该作者
soybeanmeal 发表于 2016-3-17 19:25
和usblib有什么关系呢

usblib 是上位机驱动开发用的,相当于一个usb驱动的函数库

使用特权

评论回复
10
wxdftd| | 2017-3-23 11:30 | 只看该作者
楼主能把源码发一下吗?wxdftd@qq.com,万分感谢

使用特权

评论回复
11
爱不孤单| | 2017-10-19 11:27 | 只看该作者
楼主,我不知道你有没有遇到这种情况,我发送报告描述符的时候,用BusHound查看,发现只发送了数组的第一个字节,
if(USBD_HID_Report_ID == 0x03)
        {
                //Report_buf[0] = 0x03;
               ///Report_buf[1] = 0x0a;
                USBD_CtlSendData (pdev, MaxTouchReport, USBD_HID_Report_LENGTH);
                //USBD_CtlSendData (pdev, Report_buf, 0x02);
        }else if(USBD_HID_Report_ID == 0x44)
        {
                USBD_CtlSendData (pdev, CustomDevFeatureReport, USBD_HID_Report_LENGTH);
        }

,不知道你有没有好的建议修改。

使用特权

评论回复
12
exxew| | 2024-1-10 15:19 | 只看该作者
膜拜

使用特权

评论回复
发新帖 本帖赏金 5.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

31

主题

260

帖子

39

粉丝