polarisyj86
polarisyj86
采纳率66.7%
2018-07-16 03:43 阅读 4.5k
已采纳

STM32CubeMX中两种USB HID设备类的区别?

5

我想用STM32CubeMX代码生成工具生成USB的HID设备类驱动代码,发现在USB DEVICE下拉列表框选项中,有2中HID设备类选项可以选择,分别是Custom Human Interface Device Class和Human Interface Device Class,我查了USB官网上对USB设备类的列表,发现只有Human Interface Device Class这一种标准HID类设备。那么,工具中的Custom Human Interface Device Class是什么类型的HID设备呢?是否是用户可以自定义的HID类设备,它跟标准的HID类设备有什么异同?有没有这方面的资料可供参考呢?
STM32CubeMX中所支持的USB设备类

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • 已采纳
    qq_42617330 银河China 2018-07-16 04:14

    Compound Device内嵌Hub和多个Function,每个Function都相当于一个独立的USB外设,有自己的PID/VID/DID。
    Composite Device内只有一个Function,只有一套PID/VID/DID,通过将不同的interface定义为不同的类来实现
    多个功能的组合。

    Compound Device内嵌Hub和多个Function,每个Function都相当于一个独立的USB外设,有自己的PID/VID/DID。

    Composite Device内只有一个Function,只有一套PID/VID/DID,通过将不同的interface定义为不同的类来实现多个功能的组
    合。

    很多人认为一个USB接口上实现多个设备,就是指复合设备,其实,这是不确切的,虽然USB Compound Device和USB Composite Device
    都会被百度翻译为USB复合设备。

    在一个USB接口上实现多个设备有2中方法,一种是Compound Device,就是复合设备;另一种是Composite Device,就是组合设备。

    在USB2.0的标准协议中,定义如下:

    When multiple functions are combined with a hub in a single package, they are referred to as a compound device.



    A device that has multiple interfaces controlled independently of each other is referred to as a



    composite device.
    所以,复合设备其实就是几个设备通过一个USB Hub形成的单一设备;组合设备也就是具有多个接口的设备,每个接口代表一个独立的设备。

    显然,如果是想同样的功能的话,组合设备的方法要简单很多(可以去看一下USB2.0协议中,USB2.0 Hub的复杂度)。

    STM32F103实现的USB转多路串口,属于USB Composite Device,不内嵌Hub,三个CDC设备的PID和VID都是相同。

    USB设备可以定义一个复合设备,复合设备分两种,一种是一个设备多个配置,还有一种是一个配置多个接口,在本例中采用一个配置多个接口的方式

    首先修改设备描述符,标准设备描述符和报告描述符都不需要修改,只需要修改配置描述符即可
    

    //usb配置描述符

    const u8 DinkUsbConfigDescriptor[DINK_USB_SIZ_CONFIG_DESC] = {

    /***************配置描述符***********************/

    USB_CONFIGUARTION_DESC_SIZE, //bLength字段。配置描述符的长度为9字节。

    USB_CONFIGURATION_DESCRIPTOR_TYPE, //bDescriptorType字段。配置描述符编号为0x02。

    //wTotalLength字段。配置描述符集合的总长度,

    //包括配置描述符本身、接口描述符、类描述符、端点描述符等。

    WBVAL(

    USB_CONFIGUARTION_DESC_SIZE + //配置描述符

    USB_INTERFACE_DESC_SIZE + //接口1描述符

    + //hid描述符

    USB_ENDPOINT_DESC_SIZE + //端点描述符

    USB_ENDPOINT_DESC_SIZE + //端点描述符

    USB_INTERFACE_DESC_SIZE + //接口描述符2

    USB_ENDPOINT_DESC_SIZE + //端点描述符1

    USB_ENDPOINT_DESC_SIZE //端点描述符2

    ),

    0x02, //bNumInterfaces字段。该配置包含的接口数,复合设备,两个接口。

    0x01, //bConfiguration字段。该配置的值为1。

    0x00, //iConfigurationz字段,该配置的字符串索引。这里没有,为0。

    USB_CONFIG_BUS_POWERED , //bmAttributes字段,该设备的属性

    USB_CONFIG_POWER_MA(500), //bMaxPower字段,该设备需要的最大电流量



    /*********************第一个接口描述符,hid设备**********************/

    USB_INTERFACE_DESC_SIZE, //bLength字段。接口描述符的长度为9字节。

    USB_INTERFACE_DESCRIPTOR_TYPE, //bDescriptorType字段。接口描述符的编号为0x04。

    0x00, //bInterfaceNumber字段。该接口的编号,第一个接口,编号为0。

    0x00, //bAlternateSetting字段。该接口的备用编号,为0。

    0x02, //bNumEndpoints字段。非0端点的数目。该接口有2个批量端点



    USB_DEVICE_CLASS_HUMAN_INTERFACE, //bInterfaceClass字段。该接口所使用的类。大容量存储设备接口类的代码为0x08。,



    0x00, //bInterfaceSubClass字段。该接口所使用的子类。在HID1.1协议中,

    //只规定了一种子类:支持BIOS引导启动的子类。

    //USB键盘、鼠标属于该子类,子类代码为0x01。

    //但这里我们是自定义的HID设备,所以不使用子类。



    0x00, //bInterfaceProtocol字段。如果子类为支持引导启动的子类,

    //则协议可选择鼠标和键盘。键盘代码为0x01,鼠标代码为0x02。

    //自定义的HID设备,也不使用协议。



    0x00, //iConfiguration字段。该接口的字符串索引值。这里没有,为0。



    /*********************HID报告描述符*************************/

    //bLength字段。本HID描述符下只有一个下级描述符。所以长度为9字节。

    0x09,



    //bDescriptorType字段。HID描述符的编号为0x21。

    0x21,



    //bcdHID字段。本协议使用的HID1.1协议。注意低字节在先。

    0x10,

    0x01,



    //bCountyCode字段。设备适用的国家代码,这里选择为美国,代码0x21。

    0x21,



    //bNumDescriptors字段。下级描述符的数目。我们只有一个报告描述符。

    0x01,



    //bDescriptorType字段。下级描述符的类型,为报告描述符,编号为0x22。

    0x22,



    //bDescriptorLength字段。下级描述符的长度。下级描述符为报告描述符。

    sizeof(HID_ReportDescriptor)&0xFF,

    (sizeof(HID_ReportDescriptor)>>8)&0xFF,

    /*********************端点描述符**********************************/

    /* 端点描述符 /

    USB_ENDPOINT_DESC_SIZE, //bLength字段。端点描述符长度为7字节。

    USB_ENDPOINT_DESCRIPTOR_TYPE, //bDescriptorType字段。端点描述符编号为0x05。

    USB_ENDPOINT_IN(1), //bEndpointAddress字段。端点的地址。我们使用D12的输入端点1。

    USB_ENDPOINT_TYPE_INTERRUPT, //bmAttributes字段。D1~D0为端点传输类型选择。

    WBVAL(0x0040), //wMaxPacketSize字段。该端点的最大包长。最大包长为64字节。

    0x01, //bInterval字段。端点查询的时间,端点查询的时间,此处无意义。

    /
    **********************端点描述符*******************************************/

    USB_ENDPOINT_DESC_SIZE, //bLength字段。端点描述符长度为7字节。

    USB_ENDPOINT_DESCRIPTOR_TYPE, //bDescriptorType字段。端点描述符编号为0x05。

    USB_ENDPOINT_OUT(1), //bEndpointAddress字段。端点的地址。我们使用D12的输入端点1。

    USB_ENDPOINT_TYPE_INTERRUPT, //bmAttributes字段。D1~D0为端点传输类型选择。

    WBVAL(0x0040), //wMaxPacketSize字段。该端点的最大包长。最大包长为64字节。

    0x01, //bInterval字段。端点查询的时间,端点查询的时间,此处无意义。

    /*******************第二个接口描述符 存储设备*********************/

    USB_INTERFACE_DESC_SIZE, //bLength字段。接口描述符的长度为9字节。

    USB_INTERFACE_DESCRIPTOR_TYPE, //bDescriptorType字段。接口描述符的编号为0x04。

    0x01, //bInterfaceNumber字段。该接口的编号,第二个接口,编号为1。

    0x00, //bAlternateSetting字段。该接口的备用编号,为0。

    0x02, //bNumEndpoints字段。非0端点的数目。该接口有2个批量端点



    USB_DEVICE_CLASS_STORAGE, //bInterfaceClass字段。该接口所使用的类。大容量存储设备接口类的代码为0x08。,

    MSC_SUBCLASS_SCSI, //bInterfaceSubClass字段。SCSI透明命令集的子类代码为0x06。

    MSC_PROTOCOL_BULK_ONLY, //bInterfaceProtocol字段。协议为仅批量传输,代码为0x50。

    0x04, //iConfiguration字段。该接口的字符串索引值



    /************************************* 端点描述符 *********************************************/

    USB_ENDPOINT_DESC_SIZE, //bLength字段。端点描述符长度为7字节。

    USB_ENDPOINT_DESCRIPTOR_TYPE, //bDescriptorType字段。端点描述符编号为0x05。

    USB_ENDPOINT_IN(2), //bEndpointAddress字段。端点的地址。我们使用D12的输入端点1。

    USB_ENDPOINT_TYPE_BULK, //bmAttributes字段。D1~D0为端点传输类型选择。

    WBVAL(0x0040), //wMaxPacketSize字段。该端点的最大包长。最大包长为64字节。

    0x00, //bInterval字段。端点查询的时间,端点查询的时间,此处无意义。



    /************************************端点描述符********************************************************/

    USB_ENDPOINT_DESC_SIZE, //bLength字段。端点描述符长度为7字节。

    USB_ENDPOINT_DESCRIPTOR_TYPE, //bDescriptorType字段。端点描述符编号为0x05。

    USB_ENDPOINT_OUT(2), //bEndpointAddress字段。端点的地址。我们使用D12的输入端点1。

    USB_ENDPOINT_TYPE_BULK, //bmAttributes字段。D1~D0为端点传输类型选择。

    WBVAL(0x0040), //wMaxPacketSize字段。该端点的最大包长。最大包长为64字节。

    0x00, //bInterval字段。端点查询的时间,端点查询的时间,此处无意义。

    };
    修改描述符之后要同时记得修改描述符的长度,然后修改usb_prop文件,主要是两个多出来的命令GET_MAX_LEN用来获取当前存储设备的个数,还有一个用来复位当前存储设备,如下

    RESULT DinkUsbData_Setup(u8 RequestNo)

    {

    u8 (*CopyRoutine)(u16);



    CopyRoutine = NULL;

    if ((RequestNo == GET_DESCRIPTOR)

    && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))

    && (pInformation->USBwIndex0 == 0))

    {

    //获取报告描述符

    if (pInformation->USBwValue1 == REPORT_DESCRIPTOR)

    {

    CopyRoutine = DinkUsbGetReportDescriptor;

    }

    //获取HID描述符

    else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)

    {

    CopyRoutine = DinkUsbGetHIDDescriptor;

    }



    }

    /
    ** GET_PROTOCOL ***/

    else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))

    && RequestNo == GET_PROTOCOL)

    {

    CopyRoutine = DinkUsbGetProtocolValue;//获取协议值

    }

    else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))

    && (RequestNo == GET_MAX_LUN) && (pInformation->USBwValue == 0)

    && (pInformation->USBwIndex == 0) && (pInformation->USBwLength == 0x01))

    {

    CopyRoutine = Get_Max_Lun;

    }





    if (CopyRoutine == NULL)

    {

    return USB_UNSUPPORT;

    }



    pInformation->Ctrl_Info.CopyData = CopyRoutine;

    pInformation->Ctrl_Info.Usb_wOffset = 0;

    (*CopyRoutine)(0);

    return USB_SUCCESS;

    }
    GET_MAX_LEN的函数体为

    u8 Get_Max_Lun(u16 Length)

    {

    if (Length == 0)

    {

    pInformation->Ctrl_Info.Usb_wLength = LUN_DATA_LENGTH;

    return 0;

    }

    else

    {

    return((u8
    )(&Max_Lun));

    }

    }

    点赞 评论 复制链接分享

相关推荐