STM32实现自定义HID复合设备

复合设备是啥,通俗讲就是一个USB物理设备可以实现多个功能,在主机端可以看到多个设备。通常实现HID复合设备有两种方式。第一种是使用同一个接口,修改报告描述符,增加一个功能集合,同时需要使用报告ID来区分哪一个设备,这样主机端和设备端需要增加报告ID处理,但只需要两个端点来实现功能,对于端口资源较少的MCU可以使用;第二种是使用两个接口,每个接口对应不同的报告描述符,不需要特意使用报告ID来区分,但不同接口使用独立的端点。
本文章使用不同接口来实现,基于stm32 cube例程开发。

  1. 开发准备
    使用官方STM32Cube_FW_F1_V1.6.0,使用STM32F103XF,因此使用
    STM32Cube_FW_F1_V1.6.0\Projects\STM3210E_EVAL\Applications\USB_Device\CustomHID_Standalone
    这个工程

  2. 移植代码
    2.1 修改控制控制USBDP上拉电阻引脚,(内部无法直接控制上下拉,因此增加此电路,否则主机不会枚举设备)
    STM32实现自定义HID复合设备_第1张图片
    2.2 增加串口1输出调试信息,main函数里添加:
    /* uart configuration */
    MX_USART1_UART_Init();
    添加如下代码实现printf功能

   PUTCHAR_PROTOTYPE
{

  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}

2.3 修改usb注册函数,main函数里修改如下代码

USBD_Init(&USBD_Device, &HID_Desc, 0);
/* Add Supported Class /
USBD_RegisterClass(&USBD_Device, &USBD_COMPOSITE);
/
Start Device Process */
USBD_Start(&USBD_Device);

2.4 修改desc
在usbd_desc.c,定义自己的desc
#define USBD_VID 0x0483
#define USBD_PID 0x5750
#define USBD_LANGID_STRING 0x409
#define USBD_MANUFACTURER_STRING “man”
#define USBD_PRODUCT_FS_STRING “HID in FS Mode”
#define USBD_CONFIGURATION_FS_STRING “HID Config”
#define USBD_INTERFACE_FS_STRING “HID Interface”
2.5 添加USBD_COMPOSITE
增加如下文件
usbd_composite.c,usbd_composite.h,usbd_customhid_if.c
usbd_customhid_if.h,usbd_keyboard.c,usbd_keyboard.h,usbd_keyboard_if.c,usbd_keyboard_if.h

usbd_composite.c具体内容如下,关键修改为USBD_Composite_CfgFSDesc。

/**
* @file        usbd_composite.c
* @author     
* @version    
* @date        
* @brief       KB + HID 复合设备
* @note
* @attention  
*/

#include "usbd_composite.h"
#include "usbd_customhid.h"
#include "usbd_customhid_if.h"
#include "usbd_keyboard.h"
#include "usbd_keyboard_hid_if.h"

static USBD_CUSTOM_HID_HandleTypeDef *pHIDData;
static USBD_CUSTOM_HID_HandleTypeDef *pKBData;


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_EP0_RxReady(USBD_HandleTypeDef *pdev);

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

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,
  USBD_Composite_DataIn,
  USBD_Composite_DataOut,
  NULL,
  NULL,
  NULL,
  NULL,
  USBD_Composite_GetFSCfgDesc,
  NULL,
  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 =
{
  0x09, /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
  USBD_COMPOSITE_DESC_SIZE,
  /* wTotalLength: Bytes returned */
  0x00,
  0x02,         /*bNumInterfaces: 2 interface*/
  0x01,         /*bConfigurationValue: Configuration value*/
  0x00,         /*iConfiguration: Index of string descriptor describing
  the configuration*/
  0xC0,         /*bmAttributes: bus powered */
  0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
  
  /************** Descriptor of CUSTOM HID interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x02,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: CUSTOM_HID*/
  0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/
  /******************** Descriptor of CUSTOM_HID *************************/
  /* 18 */
  0x09,         /*bLength: CUSTOM_HID Descriptor size*/
  CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/
  0x11,         /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  USBD_CUSTOM_HID_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,
  /******************** Descriptor of Custom HID endpoints ********************/
  /* 27 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  CUSTOM_HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  CUSTOM_HID_EPIN_SIZE, /*wMaxPacketSize: 64 Byte max */
  0x00,
  0x10,          /*bInterval: Polling Interval (20 ms)*/
  /* 34 */
  
  0x07,	         /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,	/* bDescriptorType: */
  CUSTOM_HID_EPOUT_ADDR,  /*bEndpointAddress: Endpoint Address (OUT)*/
  0x03,	/* bmAttributes: Interrupt endpoint */
  CUSTOM_HID_EPOUT_SIZE,	/* wMaxPacketSize: 64 Bytes max  */
  0x00,
  0x10,	/* bInterval: Polling Interval (20 ms) */
  
  /************** Descriptor of Keyboard interface ****************/
  /* 41 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  0x01,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x02,         /*bNumEndpoints*/
  0x03,         /*bInterfaceClass: Keyboard*/
  0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/
  /******************** Descriptor of Keyboard *************************/
  /* 50 */
  0x09,         /*bLength: Keyboard Descriptor size*/
  CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: Keyboard*/
  0x11,         /*bCUSTOM_HIDUSTOM_HID: Keyboard Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  USBD_KEYBOARD_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,
  /******************** Descriptor of Keyboard endpoints ********************/
  /* 59 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  KEYBOARD_HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  KEYBOARD_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
  0x00,
  0x10,          /*bInterval: Polling Interval (20 ms)*/
  /* 66 */
  
  0x07,	         /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,	/* bDescriptorType: */
  KEYBOARD_HID_EPOUT_ADDR,  /*bEndpointAddress: Endpoint Address (OUT)*/
  0x03,	/* bmAttributes: Interrupt endpoint */
  CUSTOM_HID_EPOUT_SIZE,	/* wMaxPacketSize: 64 Bytes max  */
  0x00,
  0x10,	/* bInterval: Polling Interval (20 ms) */
  /* 73 */
};


/* 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_CustomHID_fops;
  res +=  USBD_CUSTOM_HID.Init(pdev,cfgidx);
  pHIDData = pdev->pClassData;
  pdev->pUserData = &USBD_KEYBOARD_fops_FS;
  res +=  USBD_KEYBOARD.Init(pdev,cfgidx);
  pKBData = 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->pClassData = pHIDData;
  pdev->pUserData = &USBD_CustomHID_fops;
  res +=  USBD_CUSTOM_HID.DeInit(pdev,cfgidx);
  
  pdev->pClassData = pKBData;
  pdev->pUserData = &USBD_KEYBOARD_fops_FS;
  res +=  USBD_KEYBOARD.DeInit(pdev,cfgidx);
  
  return res;
}


static uint8_t  USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev)
{
  return USBD_CUSTOM_HID.EP0_RxReady(pdev);
}



/**
* @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 USBD_HID_DATA_INTERFACE:
      pdev->pClassData = pHIDData;
      pdev->pUserData =  &USBD_CustomHID_fops;
      return(USBD_CUSTOM_HID.Setup(pdev, req));
      
    case USBD_KB_INTERFACE:
      pdev->pClassData = pKBData;
      pdev->pUserData =  &USBD_KEYBOARD_fops_FS;
      return(USBD_KEYBOARD.Setup (pdev, req));
      
    default:
      break;
    }
    break;
    
  case USB_REQ_RECIPIENT_ENDPOINT:
    switch(req->wIndex)
    {
    case CUSTOM_HID_EPIN_ADDR:
    case CUSTOM_HID_EPOUT_ADDR:
      pdev->pClassData = pHIDData;
      pdev->pUserData =  &USBD_CustomHID_fops;
      return(USBD_CUSTOM_HID.Setup(pdev, req));
      
    case KEYBOARD_HID_EPIN_ADDR:
    case KEYBOARD_HID_EPOUT_ADDR:
      pdev->pClassData = pKBData;
      pdev->pUserData =  &USBD_KEYBOARD_fops_FS;
      return(USBD_KEYBOARD.Setup (pdev, req));
      
    default:
      break;
    }
    break;
  }
  return USBD_OK;
}




/**
* @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->pClassData = pHIDData;
    pdev->pUserData =  &USBD_CustomHID_fops;
    return(USBD_CUSTOM_HID.DataIn(pdev,epnum));
    
  case KB_INDATA_NUM:
    pdev->pClassData = pKBData;
    pdev->pUserData =  &USBD_KEYBOARD_fops_FS;
    return(USBD_KEYBOARD.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->pClassData = pHIDData;
    pdev->pUserData =  &USBD_CustomHID_fops;
    return(USBD_CUSTOM_HID.DataOut(pdev,epnum));
    
  case KB_OUTDATA_NUM:
    pdev->pClassData = pKBData;
    pdev->pUserData =  &USBD_KEYBOARD_fops_FS;
    return(USBD_KEYBOARD.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;
}


/**
* @}
*/


/**
* @}
*/


/**
* @}
*/

/************************ (C) COPYRIGHT WEYNE *****END OF FILE****/


usbd_customhid_if.c内容如下,主要修改CustomHID_ReportDesc,CustomHID_OutEvent,前者为报告描述符,后者为接受数据处理函数。

/**
  ******************************************************************************
  * @file    USB_Device/CustomHID_Standalone/Src/usbd_customhid_if.c
  * @author  MCD Application Team
  * @version V1.6.0
  * @date    12-May-2017
  * @brief   USB Device Custom HID interface file.
  ******************************************************************************
  * @attention
  *
  * 

© Copyright � 2016 STMicroelectronics International N.V. * All rights reserved.

* * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. This software, including modifications and/or derivative works of this * software, must execute solely and exclusively on microcontroller or * microprocessor devices manufactured by or for STMicroelectronics. * 5. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------ */ #include "usbd_customhid_if.h" /* Private typedef ----------------------------------------------------------- */ /* Private define ------------------------------------------------------------ */ /* Private macro ------------------------------------------------------------- */ /* Private function prototypes ----------------------------------------------- */ static int8_t CustomHID_Init(void); static int8_t CustomHID_DeInit(void); static int8_t CustomHID_OutEvent(uint8_t * data); /* Private variables --------------------------------------------------------- */ ADC_HandleTypeDef AdcHandle; uint32_t ADCConvertedValue = 0; uint32_t ADC_Prev_ConvertedValue = 0; uint8_t SendBuffer[2]; extern USBD_HandleTypeDef USBD_Device; __ALIGN_BEGIN static uint8_t CustomHID_ReportDesc[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = { /* USER CODE BEGIN 0 */ 0x06,0xA0,0xFF, //用法页(FFA0h, vendor defined) 0x09, 0x01, //用法(vendor defined) 0xA1, 0x01, //集合(Application) 0x09, 0x02 , //用法(vendor defined) 0xA1, 0x00, //集合(Physical) 0x06,0xA1,0xFF, //用法页(vendor defined) //输入报告 //0x85,0x01, 0x09, 0x03 , //用法(vendor defined) 0x09, 0x04, //用法(vendor defined) 0x15, 0x80, //逻辑最小值(0x80 or -128) 0x25, 0x7F, //逻辑最大值(0x7F or 127) 0x35, 0x00, //物理最小值(0) 0x45, 0xFF, //物理最大值(255) 0x75, 0x08, //报告长度Report size (8位) 0x95, 64, //报告数值(64 fields) 0x81, 0x02, //输入(data, variable, absolute) //输出报告 // 0x85, 0x02, 0x09, 0x05, //用法(vendor defined) 0x09, 0x06, //用法(vendor defined) 0x15, 0x80, //逻辑最小值(0x80 or -128) 0x25, 0x7F, //逻辑最大值(0x7F or 127) 0x35, 0x00, //物理最小值(0) 0x45, 0xFF, //物理最大值(255) 0x75, 0x08, //报告长度(8位) 0x95, 64, //报告数值(64 fields) 0x91, 0x02, //输出(data, variable, absolute) 0xC0, //集合结束(Physical) 0xC0, //集合结束(Physical) }; USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops = { CustomHID_ReportDesc, CustomHID_Init, CustomHID_DeInit, CustomHID_OutEvent, }; /* Private functions --------------------------------------------------------- */ /** * @brief CustomHID_Init * Initializes the CUSTOM HID media low layer * @param None * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL */ static int8_t CustomHID_Init(void) { // GPIO_InitTypeDef GPIO_InitStructure; // ADC_ChannelConfTypeDef sConfig; /* Configure the ADC peripheral */ #if 0 AdcHandle.Instance = ADCx; __HAL_RCC_ADC1_CLK_ENABLE(); AdcHandle.Init.ScanConvMode = DISABLE; AdcHandle.Init.ContinuousConvMode = ENABLE; AdcHandle.Init.DiscontinuousConvMode = DISABLE; AdcHandle.Init.NbrOfDiscConversion = 0; AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; AdcHandle.Init.NbrOfConversion = 1; HAL_ADC_Init(&AdcHandle); /* Configure ADC regular channel */ sConfig.Channel = ADCx_CHANNEL; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; HAL_ADC_ConfigChannel(&AdcHandle, &sConfig); /* Start the conversion process and enable interrupt */ HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *) & ADCConvertedValue, 1); /* Configure LED1, LED2, LED3 and LED4 */ BSP_LED_Init(LED1); BSP_LED_Init(LED2); BSP_LED_Init(LED3); BSP_LED_Init(LED4); /* Enable GPIOG clock */ __HAL_RCC_GPIOG_CLK_ENABLE(); /* Configure PG8 pin as input floating for key Button */ GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Pin = GPIO_PIN_8; HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); /* Enable and set EXTI2_TSC Interrupt to the lowest priority */ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 3, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); #endif return (0); } /** * @brief CustomHID_DeInit * DeInitializes the CUSTOM HID media low layer * @param None * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL */ static int8_t CustomHID_DeInit(void) { /* * Add your deinitialization code here */ return (0); } /** * @brief CustomHID_OutEvent * Manage the CUSTOM HID class Out Event * @param event_idx: LED Report Number * @param state: LED states (ON/OFF) */ static int8_t CustomHID_OutEvent(uint8_t * data) { printf("CustomHID_OutEvent:\r\n"); for(int i=0;i
  1. 编译下载,插入电脑,检测到两个设备,大功告成

你可能感兴趣的:(STM32实现自定义HID复合设备)