由于项目的原因,需要使用STM32F407实现USB鼠标+键盘设备+自定义HID设备
在网上找了很久发现都是以前使用stm32f103实现的,并且库函数完全不一样,对于大神来说可能移植起来比较容易,但是对我们这样的新手来说移植起来很是费劲,而且网上这方面的资料比较少,不知道如何下手,这里很感谢圈圈,他的书给我很大帮助。所以我也想把我这段时间的经验分享出来,给论坛里的新手做下参考,避免向我一样走了很多弯路。话不多说直接上代码:
本质上是基于圈圈的代码把库函数中的HID例程改成鼠标+键盘
1.首先要改的是设备描述符(usbd.desc.c)
1).PID和VID
VID:Vendor ID,供应商识别码;PID:ProductID,产品识别码
这两个在每次更改usb类的时候必须更改,因为Windows如果发现pid和vid一样的话就会将此usb设备默认成第一次驱动此vid和pid设备时的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了
|
|