STM32 USB组合设备HID+MIDI

目的:完成一个HID + MIDI的组合设备

 

准备工作:

·用CUBE生成HID工程;

·复制一份工程修改为MIDI工程;(参考之前博客已完成这两个工程)

·新建USB_User文件夹,将USB相关配置文件放到这里,并新建usbd_composite.c,usbd_composite.h文件;

STM32 USB组合设备HID+MIDI_第1张图片

STM32 USB组合设备HID+MIDI_第2张图片

 

·修改:

 

 

·分配端点号

#define HID_EPIN_ADDR                 0x81

#define HID_EPIN_SIZE                    0x40

#define HID_EPOUT_ADDR             0x01

#define HID_EPOUT_SIZE                0x40

 

#define MIDI_EPIN_ADDR                0x82

#define MIDI_EPOUT_ADDR            0x02

#define MIDI_EPIN_SIZE                   0x40

#define MIDI_EPOUT_SIZE               0x40

 

·添加usbd_composite.c,usbd_composite.h文件内容:

<>

#include "usbd_composite.h"
#include "usbd_hid_if.h"
#include "usbd_midi_if.h"

static USBD_HID_HandleTypeDef *pHIDData;
static USBD_MIDI_HandleTypeDef *pMIDIData;


static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);

static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);

static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);

static uint8_t USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev);

static uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);

static uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);

static uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length);

static uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);

USBD_ClassTypeDef  USBD_COMPOSITE =
{
  USBD_Composite_Init,
  USBD_Composite_DeInit,
  USBD_Composite_Setup,
  NULL, /*EP0_TxSent*/
  USBD_Composite_EP0_RxReady, /*EP0_RxReady*/
  USBD_Composite_DataIn,
  USBD_Composite_DataOut,
  NULL,
  NULL,
  NULL,
  USBD_Composite_GetFSCfgDesc,
  USBD_Composite_GetFSCfgDesc,
  USBD_Composite_GetFSCfgDesc,
  USBD_Composite_GetDeviceQualifierDescriptor,
};

/* USB composite device Configuration Descriptor */
/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
__ALIGN_BEGIN uint8_t USBD_Composite_CfgFSDesc[USBD_COMPOSITE_DESC_SIZE]  __ALIGN_END =
{
    /*Configuration Descriptor*/
    0x09,                        /* bLength: Configuration Descriptor size */
    USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
    USBD_COMPOSITE_DESC_SIZE,
    0x00,
    USBD_MAX_NUM_INTERFACES,   /* bNumInterfaces: 2 interface */
    0x01,   /* bConfigurationValue: Configuration value */
    0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
    0xC0,   /* bmAttributes: self powered */
    0x00,   /* MaxPower 0 mA */

    /*--HID 1-------------------------------------------------------------------------*/

    /* 9 */
    /*******************接口描述符*********************/
    //bLength字段。接口描述符的长度为9字节。
    0x09,
    //bDescriptorType字段。接口描述符的编号为0x04。
    0x04,
    //bInterfaceNumber字段。该接口的编号,第一个接口,编号为0。
    USB_INTERFACE_HID_INDEX,
    //bAlternateSetting字段。该接口的备用编号,为0。
    0x00,
    //bNumEndpoints字段。非0端点的数目。本实例需要二个
    //中断端点(一个输入一个输出),因此该值为2。
    0x02,
    //bInterfaceClass字段。该接口所使用的类。本实例是HID类,
    //HID类的编码为0x03。
    0x03,
    //bInterfaceSubClass字段。该接口所使用的子类。在HID1.1协议中,
    //只规定了一种子类:支持BIOS引导启动的子类。
    //USB键盘、鼠标属于该子类,子类代码为0x01。
    //但这里我们是自定义的HID设备,所以不使用子类。
    0x00,
    //bInterfaceProtocol字段。如果子类为支持引导启动的子类,
    //则协议可选择鼠标和键盘。键盘代码为0x01,鼠标代码为0x02。
    //自定义的HID设备,也不使用协议。
    0x00,
    //iConfiguration字段。该接口的字符串索引值。这里没有,为0。
    0x00,

    /* 18 */
    /******************HID描述符************************/
    //bLength字段。本HID描述符下只有一个下级描述符。所以长度为9字节。
    0x09,
    //bDescriptorType字段。HID描述符的编号为0x21。
    0x21,
    //bcdHID字段。本协议使用的HID1.1协议。注意低字节在先。
    0x10,
    0x01,
    //bCountyCode字段。设备适用的国家代码,这里选择为美国,代码0x21。
    0x21,
    //bNumDescriptors字段。下级描述符的数目。我们只有一个报告描述符。
    0x01,
    //bDescritporType字段。下级描述符的类型,为报告描述符,编号为0x22。
    0x22,
    //bDescriptorLength字段。下级描述符的长度。下级描述符为报告描述符。
    USBD_HID_REPORT_DESC_SIZE,
    0,

    /* 27 */
    /**********************输入端点描述符***********************/
    //bLength字段。端点描述符长度为7字节。
    0x07,
    //bDescriptorType字段。端点描述符编号为0x05。
    0x05,
    //bEndpointAddress字段。端点的地址。我们使用D12的输入端点1。
    //D7位表示数据方向,输入端点D7为1。所以输入端点1的地址为0x81。
    HID_EPIN_ADDR,//IN 1
    //bmAttributes字段。D1~D0为端点传输类型选择。
    //该端点为中断端点。中断端点的编号为3。其它位保留为0。
    0x03,
    //wMaxPacketSize字段。该端点的最大包长。端点1的最大包长为16字节。
    //注意低字节在先。
    HID_EPIN_SIZE,
    0x00,
    //bInterval字段。端点查询的时间,我们设置为10个帧时间,即1ms。
    0x01,

    /* 34 */
    /**********************输出端点描述符***********************/
    //bLength字段。端点描述符长度为7字节。
    0x07,
    //bDescriptorType字段。端点描述符编号为0x05。
    0x05,
    //bEndpointAddress字段。端点的地址。我们使用D12的输出端点1。
    //D7位表示数据方向,输出端点D7为0。所以输出端点1的地址为0x01。
    HID_EPOUT_ADDR,
    //bmAttributes字段。D1~D0为端点传输类型选择。
    //该端点为中断端点。中断端点的编号为3。其它位保留为0。
    0x03,
    //wMaxPacketSize字段。该端点的最大包长。端点1的最大包长为16字节。
    //注意低字节在先。
    HID_EPOUT_SIZE,
    0x00,
    //bInterval字段。端点查询的时间,我们设置为10个帧时间,即1ms。
    0x01,

    /* 41 */
#if 1
    /*--MIDI-------------------------------------------------------------------------*/
    /******************* Standard AC Interface Descriptor *********************/
    /* 00 */
    0x09,         /*bLength: Interface Descriptor size*/
    USB_DESC_TYPE_INTERFACE, /*bDescriptorType: Interface descriptor type*/
    USB_INTERFACE_MIDI_CONTRL_INDEX,         /*bInterfaceNumber: Number of Interface*/
    0x00,         /*bAlternateSetting: Alternate setting*/
    0x00,         /*bNumEndpoints*/
    0x01,         /*bInterfaceClass: Audio*/
    0x01,         /*bInterfaceSubClass : Audio Control*/
    0,            /*nInterfaceProtocol*/
    0,            /*iInterface: Index of string descriptor*/

    /**************** Class-specific AC Interface Descriptor ******************/
    /* 9 */
    0x09,         /*bLength: Interface Descriptor size*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x01,         /*bDescriptorSubType: Header*/
    0x00,         /*bcdADC: Revision of class specification - 1.0*/
    0x01,
    0x09,         /*wTotalLength: Total size of class specific discriptor*/
    0x00,
    0x01,         /*bInCollection: Number of streaming interfaces*/
    USB_INTERFACE_MIDI_INDEX,         /*baInterfaceNr : MIDIStreaming interface 1 belongs to 
                                this AudioControl interface*/
                                
    /******************* Standard MS Interface Descriptor *********************/
    /* 18 */
    0x09,         /*bLength: Interface Descriptor size*/
    USB_DESC_TYPE_INTERFACE, /*bDescriptorType: Interface descriptor type*/
    USB_INTERFACE_MIDI_INDEX,         /*bInterfaceNumber: Number of Interface*/
    0x00,         /*bAlternateSetting: Alternate setting*/
    0x02,         /*bNumEndpoints*/
    0x01,         /*bInterfaceClass: Audio*/
    0x03,         /*bInterfaceSubClass : MIDI Streaming*/
    0,            /*nInterfaceProtocol*/
    0,            /*iInterface: Index of string descriptor*/
    /**************** Class-specific MS Interface Descriptor ******************/
    /* 27 */
    0x07,         /*bLength: Interface Descriptor size*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x01,         /*bDescriptorSubType: MS Header*/
    0x00,         /*bcdADC: Revision of class specification*/
    0x01,
    0x41,         /*wTotalLength: Total size of class specific discriptor*/
    0x00,
    /******************* MIDI IN Jack Descriptor (Embedded) *******************/
    /* 34 */
    0x06,         /*bLength: Size of this descriptor*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x02,         /*bDescriptorSubType: MIDI IN Jack*/
    0x01,         /*bJackType: Embedded*/
    0x01,         /*bJackID: ID of this Jack*/
    0x00,         /*iJack*/
    /******************* MIDI IN Jack Descriptor (External) *******************/
    /* 40 */
    0x06,         /*bLength: Size of this descriptor*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x02,         /*bDescriptorSubType: MIDI IN Jack*/
    0x02,         /*bJackType: External*/
    0x02,         /*bJackID: ID of this Jack*/
    0x00,         /*iJack*/
    /******************* MIDI OUT Jack Descriptor (Embedded) ******************/
    /* 46 */
    0x09,         /*bLength: Size of this descriptor*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x03,         /*bDescriptorSubType: MIDI OUT Jack*/
    0x01,         /*bJackType: Embedded*/
    0x03,         /*bJackID: ID of this Jack*/
    0x01,         /*bNrInputPins: Number of Input Pins of this Jack*/
    0x02,         /*BaSourceID: ID of the Entry to which this Pin is connected*/
    0x01,         /*BaSourceID: Output Pin number of the Entry to 
                            which this Input Pin is connected*/
    0x00,         /*iJack*/
    /******************* MIDI OUT Jack Descriptor (External) ******************/
    /* 55 */
    0x09,         /*bLength: Size of this descriptor*/
    0x24,         /*bDescriptorType: Class-specific interface descriptor type*/
    0x03,         /*bDescriptorSubType: MIDI OUT Jack*/
    0x02,         /*bJackType: External*/
    0x04,         /*bJackID: ID of this Jack*/
    0x01,         /*bNrInputPins: Number of Input Pins of this Jack*/
    0x02,         /*BaSourceID: ID of the Entry to which this Pin is connected*/
    0x01,         /*BaSourceID: Output Pin number of the Entry to 
                            which this Input Pin is connected*/
    0x00,         /*iJack*/
    /****************** Standard Bulk OUT Endpoint Descriptor *****************/
    /* 64 */
    0x09,         /*bLength: Size of this descriptor*/
    USB_DESC_TYPE_ENDPOINT, /*bDescriptorType: Endpoint descriptor type*/
    MIDI_EPOUT_ADDR,         /*bEndpointAddress: OUT Endpoint 1*/
    0x02,         /*bmAttributes: Bulk, not shared.*/
    0x40,         /*wMaxPacketSize 64*/
    0x00,
    0x00,         /*bInterval*/
    0x00,         /*bRefresh*/
    0x00,         /*bSynchAddress*/
    /************* Class-specific MS Bulk OUT Endpoint Descriptor *************/
    /* 73 */
    0x05,         /*bLength: Size of this descriptor*/
    0x25,         /*bDescriptorType: Class-specific endpoint descriptor type*/
    0x01,         /*bDescriptorSubType: MS General*/
    0x01,         /*bNumEmbMIDIJack: Number of embedded MIDI IN Jack*/
    0x01,         /*BaAssocJackID: ID of the Embedded MIDI IN Jack*/
    /****************** Standard Bulk IN Endpoint Descriptor *****************/
    /* 78 */
    0x09,         /*bLength: Size of this descriptor*/
    USB_DESC_TYPE_ENDPOINT, /*bDescriptorType: Endpoint descriptor type*/
    MIDI_EPIN_ADDR,         /*bEndpointAddress: IN Endpoint 1*/
    0x02,         /*bmAttributes: Bulk, not shared.*/
    0x40,         /*wMaxPacketSize 64*/
    0x00,
    0x00,         /*bInterval*/
    0x00,         /*bRefresh*/
    0x00,         /*bSynchAddress*/
    /************* Class-specific MS Bulk OUT Endpoint Descriptor *************/
    /* 87 */
    0x05,         /*bLength: Size of this descriptor*/
    0x25,         /*bDescriptorType: Class-specific endpoint descriptor type*/
    0x01,         /*bDescriptorSubType: MS General*/
    0x01,         /*bNumEmbMIDIJack: Number of embedded MIDI OUT Jack*/
    0x03,         /*BaAssocJackID: ID of the Embedded MIDI OUT Jack*/
    /* 92 */ 
#endif
};


/* USB Standard Device Descriptor */
__ALIGN_BEGIN  uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]  __ALIGN_END =
{
  USB_LEN_DEV_QUALIFIER_DESC,
  USB_DESC_TYPE_DEVICE_QUALIFIER,
  0x00,
  0x02,
  0x00,
  0x00,
  0x00,
  0x40,
  0x01,
  0x00,
};


/**
  * @brief  USBD_Composite_Init
  *         Initialize the Composite interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
  uint8_t res = 0;

  pdev->pUserData =  &USBD_HID_fops_FS;
  res +=  USBD_HID.Init(pdev,cfgidx);
  pHIDData = pdev->pClassData;
    
  pdev->pUserData =  &USBD_MIDI_fops_FS;
  res +=  USBD_MIDI.Init(pdev,cfgidx);
  pMIDIData = pdev->pClassData;

  return res;
}

/**
  * @brief  USBD_Composite_DeInit
  *         DeInitilaize  the Composite configuration
  * @param  pdev: device instance
  * @param  cfgidx: configuration index
  * @retval status
  */
static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx)
{
    uint8_t res = 0;
    pdev->pUserData = &USBD_HID_fops_FS;
    pdev->pClassData = pHIDData;
    res +=  USBD_HID.DeInit(pdev,cfgidx);

    pdev->pUserData = &USBD_MIDI_fops_FS;
    pdev->pClassData = pMIDIData;
    res +=  USBD_MIDI.DeInit(pdev,cfgidx);

    return res;
}


/**
* @brief  USBD_Composite_Setup
*         Handle the Composite requests
* @param  pdev: device instance
* @param  req: USB request
* @retval status
*/
static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
  switch (req->bmRequest & USB_REQ_RECIPIENT_MASK)
  {
   case USB_REQ_RECIPIENT_INTERFACE:
     switch(req->wIndex)
      {
         case USB_INTERFACE_HID_INDEX:
             pdev->pUserData =  &USBD_HID_fops_FS;
             pdev->pClassData = pHIDData;
          return(USBD_HID.Setup(pdev, req));

         case USB_INTERFACE_MIDI_INDEX:
             pdev->pUserData =  &USBD_MIDI_fops_FS;
             pdev->pClassData = pMIDIData;
          return(USBD_MIDI.Setup(pdev, req));

         default:
            break;
     }
     break;

   case USB_REQ_RECIPIENT_ENDPOINT:
     switch(req->wIndex)
     {
        case HID_EPIN_ADDR:
        case HID_EPOUT_ADDR:
        pdev->pClassData = pHIDData;
         pdev->pUserData =  &USBD_HID_fops_FS;
        return(USBD_HID.Setup(pdev, req));

        case MIDI_EPIN_ADDR:
        case MIDI_EPOUT_ADDR:
        pdev->pClassData = pMIDIData;
         pdev->pUserData =  &USBD_MIDI_fops_FS;
        return(USBD_MIDI.Setup(pdev, req));

        default:
        break;
     }
     break;
  }
  return USBD_OK;
}


/**
  * @brief  USBD_HID_EP0_RxReady
  *         Handles control request data.
  * @param  pdev: device instance
  * @retval status
  */
uint8_t USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev)
{

  return USBD_HID.EP0_RxReady(pdev);
}

/**
* @brief  USBD_Composite_DataIn
*         handle data IN Stage
* @param  pdev: device instance
* @param  epnum: endpoint index
* @retval status
*/
uint8_t  USBD_Composite_DataIn(USBD_HandleTypeDef *pdev,
                              uint8_t epnum)
{
  switch(epnum)
  {
    case HID_INDATA_NUM:
    pdev->pUserData =  &USBD_HID_fops_FS;
    pdev->pClassData = pHIDData;
    return(USBD_HID.DataIn(pdev,epnum));

    case MIDI_INDATA_NUM:
    pdev->pUserData =  &USBD_MIDI_fops_FS;
    pdev->pClassData = pMIDIData;
    return(USBD_MIDI.DataIn(pdev,epnum));

    default:
    break;

  }
  return USBD_FAIL;
}


/**
* @brief  USBD_Composite_DataOut
*         handle data OUT Stage
* @param  pdev: device instance
* @param  epnum: endpoint index
* @retval status
*/
uint8_t  USBD_Composite_DataOut(USBD_HandleTypeDef *pdev,
                               uint8_t epnum)
{
  switch(epnum)
  {
    case HID_OUTDATA_NUM:
    pdev->pUserData =  &USBD_HID_fops_FS;
    pdev->pClassData = pHIDData;
    return(USBD_HID.DataOut(pdev,epnum));

    case MIDI_OUTDATA_NUM:
    pdev->pUserData =  &USBD_MIDI_fops_FS;
    pdev->pClassData = pMIDIData;
    return(USBD_MIDI.DataOut(pdev,epnum));

    default:
    break;
  }
  return USBD_FAIL;
}

/**
* @brief  USBD_Composite_GetHSCfgDesc
*         return configuration descriptor
* @param  length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length)
{
   *length = sizeof (USBD_Composite_CfgFSDesc);
   return USBD_Composite_CfgFSDesc;
}

/**
* @brief  DeviceQualifierDescriptor
*         return Device Qualifier descriptor
* @param  length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length)
{
  *length = sizeof (USBD_Composite_DeviceQualifierDesc);
  return USBD_Composite_DeviceQualifierDesc;
}

 

<>

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_COMPOSITE_H
#define __USBD_COMPOSITE_H

#ifdef __cplusplus
 extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "usbd_hid.h"
#include "usbd_midi.h"
#include "usbd_desc.h"
#include "usbd_ctlreq.h"

#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF)
#define DBVAL(x) (x & 0xFF),((x >> 8) & 0xFF),((x >> 16) & 0xFF),((x >> 24) & 0xFF)


#define USBD_COMPOSITE_DESC_SIZE            (41+92)

#define USB_INTERFACE_HID_INDEX               0
#define USB_INTERFACE_MIDI_CONTRL_INDEX       1
#define USB_INTERFACE_MIDI_INDEX            2

#define HID_INDATA_NUM                      (HID_EPIN_ADDR & 0x0F)
#define HID_OUTDATA_NUM                     (HID_EPOUT_ADDR & 0x0F)

#define MIDI_INDATA_NUM                     (MIDI_EPIN_ADDR & 0x0F)
#define MIDI_OUTDATA_NUM                    (MIDI_EPOUT_ADDR & 0x0F)

extern USBD_ClassTypeDef    USBD_COMPOSITE;

#ifdef __cplusplus
}
#endif

#endif
 

·修改usbd_device.c

void MX_USB_DEVICE_Init(void)

{

USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);

 

USBD_RegisterClass(&hUsbDeviceFS, &USBD_COMPOSITE);

 

//        USBD_HID_RegisterInterface(&hUsbDeviceFS, &USBD_HID_fops_FS);

 

USBD_Start(&hUsbDeviceFS);

}

 

 

·修改usbd_config.c

USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)

{

  /* Init USB Ip. */

  /* Link the driver to the stack. */

  hpcd_USB_FS.pData = pdev;

  pdev->pData = &hpcd_USB_FS;

 

  hpcd_USB_FS.Instance = USB;

  hpcd_USB_FS.Init.dev_endpoints = 8;

  hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;

  hpcd_USB_FS.Init.ep0_mps = DEP0CTL_MPS_8;

  hpcd_USB_FS.Init.low_power_enable = DISABLE;

  hpcd_USB_FS.Init.lpm_enable = DISABLE;

  hpcd_USB_FS.Init.battery_charging_enable = DISABLE;

  if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)

  {

    Error_Handler( );

  }

 

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , PCD_SNG_BUF, 0x98);

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0xD8);

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MIDI_EPIN_ADDR , PCD_SNG_BUF, 0x118);

  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MIDI_EPOUT_ADDR , PCD_SNG_BUF, 0x158);

 

  return USBD_OK;

}

 

·修改usbd_config.h

#define USBD_MAX_NUM_INTERFACES     3

 

·修改usbd_desc.c

#define USBD_PRODUCT_STRING_FS                             "STM32_HID+MIDI"

 

 

·修改main.c文件,

STM32 USB组合设备HID+MIDI_第3张图片

·烧录测试

识别到HID设备和MIDI设备了

STM32 USB组合设备HID+MIDI_第4张图片

MIDI数据收发OK

STM32 USB组合设备HID+MIDI_第5张图片

HID数据收发OK

STM32 USB组合设备HID+MIDI_第6张图片

参考资料:

使用STM32CubeMX编写USB复合设备        https://www.taterli.com/2355/

STM32 USB复合设备编写                   https://www.cnblogs.com/WeyneChen/p/6007049.html

 

你可能感兴趣的:(USB)