返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[STM32F1] 基于STM32 HAL库实现鼠标键盘摇杆的USB复合设备

[复制链接]
 楼主| lilijin1995 发表于 2022-12-12 11:37 | 显示全部楼层 |阅读模式
<
本帖最后由 lilijin1995 于 2022-12-13 10:45 编辑

序:
其实这样一个设备我们在ch32v103上实现过,但移植到STM32 HAL库上面,还是发现很多问题的,现在就移植过程给大家分享一下在基于STM32 HAL库实现鼠标键盘摇杆的USB复合设备的实现过程,由于楼主水平有限,文档和视频中难免有出错和讲得不好的地方,欢迎各位读者和观众善意地提出意见和建议,谢谢!
实验目的:
我们要实现一个具备摇杆、模拟鼠标和键盘功能的USB HID,通过USB接口插入PC主机,可以在主机测试通过,但仍然会有一下bug,至于什么bug就先不剧透了。

实验材料:
使用我们自己设计的MiniGamepad板子如下图,我们这款板子是为了测试学习方便用的。
50026397e17383e32.png
软件设计:
目标是实现Joystick、Mouse和Keyboard的组合,即把三个设备组合成一个设备,通过按键SW2按下依次切换成Joystick、Mouse和Keyboard设备,而WS2812灯珠则通过红绿蓝指示切换三种不同的设备。
下面分8个步骤来实现HID的枚举。
  • 1. 准备Joystick、Mouse和Keyboard三个报表,这三个报表分别是实例Eg1_Joystick、实例Eg4_Mouse与实例Eg5_KeyBoard的报表,

  1. __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
  2. {
  3.         
  4.     0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  5.     0x09, 0x04,                    // USAGE (Joystick)
  6.     0xa1, 0x01,                    // COLLECTION (Application)
  7.     0xa1, 0x02,                    //     COLLECTION (Logical)
  8.     0x09, 0x30,                    //     USAGE (X)
  9.     0x09, 0x31,                    //     USAGE (Y)
  10.     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
  11.     0x26, 0xff, 0x00,              //     LOGICAL_MAXIMUM (255)
  12.     0x35, 0x00,                    //     PHYSICAL_MINIMUM (0)
  13.     0x46, 0xff, 0x00,              //     PHYSICAL_MAXIMUM (255)
  14.     0x75, 0x08,                    //     REPORT_SIZE (8)
  15.     0x95, 0x02,                    //     REPORT_COUNT (2)
  16.     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  17.     0x05, 0x09,                    //     USAGE_PAGE (Button)
  18.     0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
  19.     0x29, 0x08,                    //     USAGE_MAXIMUM (Button 8)
  20.     0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
  21.     0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  22.     0x95, 0x08,                    //     REPORT_COUNT (8)
  23.     0x75, 0x01,                    //     REPORT_SIZE (1)
  24.     0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  25.     0xc0,                          //     END_COLLECTION
  26.         0xc0                                                      // END_COLLECTION        
  27.         

  28. };

  29. /* USER CODE BEGIN PRIVATE_VARIABLES */
  30. __ALIGN_BEGIN static uint8_t Mouse_ReportDesc_FS[USBD_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
  31. {
  32.         0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  33.         0x09, 0x02,                    // USAGE (Mouse)
  34.         0xa1, 0x01,                    // COLLECTION (Application)
  35.         0x09, 0x01,                    //   USAGE (Pointer)
  36.         0xa1, 0x00,                    //   COLLECTION (Physical)
  37.         0x05, 0x09,                    //     USAGE_PAGE (Button)
  38.         0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
  39.         0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
  40.         0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
  41.         0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  42.         0x95, 0x03,                    //     REPORT_COUNT (3)
  43.         0x75, 0x01,                    //     REPORT_SIZE (1)
  44.         0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  45.         0x95, 0x01,                    //     REPORT_COUNT (1)
  46.         0x75, 0x05,                    //     REPORT_SIZE (5)
  47.         0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
  48.         0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
  49.         0x09, 0x30,                    //     USAGE (X)
  50.         0x09, 0x31,                    //     USAGE (Y)
  51.         0x09, 0x38,                    //     USAGE (Wheel)
  52.         0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
  53.         0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
  54.         0x75, 0x08,                    //     REPORT_SIZE (8)
  55.         0x95, 0x03,                    //     REPORT_COUNT (3)
  56.         0x81, 0x06,                    //     INPUT (Data,Var,Rel)
  57.         0xc0,                          //   END_COLLECTION
  58.         0xc0                                               // END_COLLECTION
  59. };


  60. __ALIGN_BEGIN static uint8_t KEY_ReportDesc_FS[USBD_KEY_REPORT_DESC_SIZE] __ALIGN_END =
  61. {
  62.   /* USER CODE BEGIN 0 */
  63.   0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  64.   0x09, 0x06, // USAGE (Keyboard)
  65.   0xa1, 0x01, // COLLECTION (Application)
  66.   0x05, 0x07, // USAGE_PAGE (Keyboard)
  67.   0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
  68.   0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
  69.   0x15, 0x00, // LOGICAL_MINIMUM (0)
  70.   0x25, 0x01, // LOGICAL_MAXIMUM (1)
  71.   0x75, 0x01, // REPORT_SIZE (1)
  72.   0x95, 0x08, // REPORT_COUNT (8)
  73.   0x81, 0x02, // INPUT (Data,Var,Abs)
  74.   0x95, 0x01, // REPORT_COUNT (1)
  75.   0x75, 0x08, // REPORT_SIZE (8)
  76.   0x81, 0x03, // INPUT (Cnst,Var,Abs)
  77.   0x95, 0x05, // REPORT_COUNT (5)
  78.   0x75, 0x01, // REPORT_SIZE (1)
  79.   0x05, 0x08, // USAGE_PAGE (LEDs)
  80.   0x19, 0x01, // USAGE_MINIMUM (Num Lock)
  81.   0x29, 0x05, // USAGE_MAXIMUM (Kana)
  82.   0x91, 0x02, // OUTPUT (Data,Var,Abs)
  83.   0x95, 0x01, // REPORT_COUNT (1)
  84.   0x75, 0x03, // REPORT_SIZE (3)
  85.   0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
  86.   0x95, 0x06, // REPORT_COUNT (6)
  87.   0x75, 0x08, // REPORT_SIZE (8)
  88.   0x15, 0x00, // LOGICAL_MINIMUM (0)
  89.   0x25, 0xFF, // LOGICAL_MAXIMUM (255)
  90.   0x05, 0x07, // USAGE_PAGE (Keyboard)
  91.   0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
  92.   0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
  93.   0x81, 0x00, // INPUT (Data,Ary,Abs)
  94.   /* USER CODE END 0 */
  95.   0xC0    /*     END_COLLECTION                     */

  96. };
  • 2. 修改USBD_CUSTOM_HID_ItfTypeDef结构体及其实例USBD_CustomHID_fops_FS,可以看到其实这个结构体的前三个成员其实就是指向了以上三个报表描述符。

  1. typedef struct _USBD_CUSTOM_HID_Itf
  2. {
  3.         uint8_t                  *jReport;
  4.         uint8_t                  *mReport;
  5.     uint8_t                  *kReport;
  6.     int8_t (* Init)(void);
  7.     int8_t (* DeInit)(void);
  8.     int8_t (* OutEvent)(uint8_t event_idx, uint8_t state);

  9. } USBD_CUSTOM_HID_ItfTypeDef;

  10. USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS =
  11. {
  12.   CUSTOM_HID_ReportDesc_FS,
  13.   Mouse_ReportDesc_FS,
  14.   KEY_ReportDesc_FS,        
  15.   CUSTOM_HID_Init_FS,
  16.   CUSTOM_HID_DeInit_FS,
  17.   CUSTOM_HID_OutEvent_FS
  18. };
  • 3. 修改配置描述符集合。增加接口,端点等。

  1. __ALIGN_BEGIN static uint8_t USBD_CUSTOM_HID_CfgFSDesc[USB_CUSTOM_HID_CONFIG_DESC_SIZ] __ALIGN_END =
  2. {
  3.     0x09, /* bLength: Configuration Descriptor size */
  4.     USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
  5.     USB_CUSTOM_HID_CONFIG_DESC_SIZ,
  6.     /* wTotalLength: Bytes returned */
  7.     0x00,
  8.     0x03,         /*bNumInterfaces: 1 interface*/
  9.     0x01,         /*bConfigurationValue: Configuration value*/
  10.     0x00,         /*iConfiguration: Index of string descriptor describing the configuration*/
  11.     0x80,         /*bmAttributes: bus powered */
  12.     0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

  13.     //----------- Descriptor of Joystick interface ---------------------//
  14.     /* 09 */
  15.     0x09,         /*bLength: Interface Descriptor size*/
  16.     USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  17.     0x00,         /*bInterfaceNumber: Number of Interface*/
  18.     0x00,         /*bAlternateSetting: Alternate setting*/
  19.     0x01,         /*bNumEndpoints*/
  20.     0x03,         /*bInterfaceClass: CUSTOM_HID*/
  21.     0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  22.     0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  23.     0,            /*iInterface: Index of string descriptor*/
  24.     //-----------HID Descriptor of Joystick  ---------------------//
  25.     /* 18 */
  26.     0x09,         /*bLength: CUSTOM_HID Descriptor size*/
  27.     CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/
  28.     0x11,         /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/
  29.     0x01,
  30.     0x00,         /*bCountryCode: Hardware target country*/
  31.     0x01,         /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
  32.     0x22,         /*bDescriptorType*/
  33.     USBD_CUSTOM_HID_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  34.     0x00,
  35.     //----------- Descriptor of Joystick endpoints ---------------------//
  36.     /* 27 */
  37.     0x07,          /*bLength: Endpoint Descriptor size*/
  38.     USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/

  39.     CUSTOM_HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/
  40.     0x03,          /*bmAttributes: Interrupt endpoint*/
  41.     CUSTOM_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
  42.     0x00,
  43.     CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
  44.     /* 34 */

  45.     //-----------  Descriptor of Mouse interface    ---------------------//
  46.     0x09,         /*bLength: Interface Descriptor size*/
  47.     USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  48.     0x01,         /*bInterfaceNumber: Number of Interface*/
  49.     0x00,         /*bAlternateSetting: Alternate setting*/
  50.     0x01,         /*bNumEndpoints*/
  51.     0x03,         /*bInterfaceClass: CUSTOM_HID*/
  52.     0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  53.     0x02,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  54.     0,            /*iInterface: Index of string descriptor*/
  55.     //-----------   Descriptor of Mouse CUSTOM_HID    ---------------------//
  56.     /* 43 */
  57.     0x09,         /*bLength: CUSTOM_HID Descriptor size*/
  58.     CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/
  59.     0x11,         /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/
  60.     0x01,
  61.     0x00,         /*bCountryCode: Hardware target country*/
  62.     0x01,         /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
  63.     0x22,         /*bDescriptorType*/
  64.     USBD_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  65.     0x00,
  66.     //-----------    Descriptor of Mouse endpoints    ---------------------//
  67.     /* 52 */
  68.     0x07,          /*bLength: Endpoint Descriptor size*/
  69.     USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/

  70.     MOUSE_HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/
  71.     0x03,          /*bmAttributes: Interrupt endpoint*/
  72.     MOUSE_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
  73.     0x00,
  74.     CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
  75.     /* 59 */
  76.     //-----------  Descriptor of KeyBoard interface    ---------------------//
  77.     0x09,         /*bLength: Interface Descriptor size*/
  78.     USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
  79.     0x02,         /*bInterfaceNumber: Number of Interface*/
  80.     0x00,         /*bAlternateSetting: Alternate setting*/
  81.     0x01,         /*bNumEndpoints*/
  82.     0x03,         /*bInterfaceClass: CUSTOM_HID*/
  83.     0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  84.     0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  85.     0,            /*iInterface: Index of string descriptor*/
  86.     //-----------   Descriptor of KeyBoard CUSTOM_HID    ---------------------//
  87.     /* 68 */
  88.     0x09,         /*bLength: CUSTOM_HID Descriptor size*/
  89.     CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/
  90.     0x11,         /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/
  91.     0x01,
  92.     0x00,         /*bCountryCode: Hardware target country*/
  93.     0x01,         /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/
  94.     0x22,         /*bDescriptorType*/
  95.     USBD_KEY_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  96.     0x00,
  97.     //-----------    Descriptor of KeyBoard endpoints    ---------------------//
  98.     /* 77 */
  99.     0x07,          /*bLength: Endpoint Descriptor size*/
  100.     USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/

  101.     KEY_HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/
  102.     0x03,          /*bmAttributes: Interrupt endpoint*/
  103.     KEY_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
  104.     0x00,
  105.     CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
  106.     /* 84 */
  107. };
  • 4. 在usbd_conf.h修改最大接口数量为3(这一步非常关键)

  1. #define USBD_MAX_NUM_INTERFACES     3
  • 5. 根据接口索引修改获取描述符的请求:定位到USBD_CUSTOM_HID->USBD_CUSTOM_HID_Setup在USB_REQ_GET_DESCRIPTOR请求中通过req->wIndex增加报告描述符的请求;

  1. static uint8_t  USBD_CUSTOM_HID_Setup(USBD_HandleTypeDef *pdev,
  2.                                       USBD_SetupReqTypedef *req)
  3. {
  4.   USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
  5.   uint16_t len = 0U;
  6.   uint8_t  *pbuf = NULL;
  7.   uint16_t status_info = 0U;
  8.   uint8_t ret = USBD_OK;
  9.   switch (req->bmRequest & USB_REQ_TYPE_MASK)
  10.   {
  11.     case USB_REQ_TYPE_STANDARD:
  12.       switch (req->bRequest)
  13.       {
  14.         case USB_REQ_GET_DESCRIPTOR:
  15.           if (req->wValue >> 8 == CUSTOM_HID_REPORT_DESC)
  16.           {                          
  17.                           if (req->wIndex == 0)
  18.                           {
  19.                                 len = MIN(USBD_CUSTOM_HID_REPORT_DESC_SIZE, req->wLength);
  20.                                 pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->jReport;                                 
  21.                           }else if (req->wIndex == 1){//mouse
  22.                                 len = MIN(USBD_MOUSE_REPORT_DESC_SIZE, req->wLength);
  23.                                 pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->mReport;        
  24.                           
  25.                           }else if (req->wIndex == 2){//
  26.                                 len = MIN(USBD_KEY_REPORT_DESC_SIZE, req->wLength);
  27.                                 pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->kReport;                                 
  28.                           }                                                                              
  29.           }
  30.           else
  31.           {
  32.             if (req->wValue >> 8 == CUSTOM_HID_DESCRIPTOR_TYPE)
  33.             {                                                               
  34.               pbuf = USBD_CUSTOM_HID_Desc;
  35.               len = MIN(USB_CUSTOM_HID_DESC_SIZ, req->wLength);
  36.             }
  37.           }
  38.           USBD_CtlSendData(pdev, pbuf, len);
  39.           break;
  40.   }
  41.   return ret;
  42. }
  • 6. 为端点增加PAM:定位到MX_USB_DEVICE_Init->USBD_Init->USBD_LL_Init;在USBD_LL_Init函数中找到HAL_PCDEx_PMAConfig,通过该接口为EP(端点)配置PMA(Packet Buffer Memory Area ,即USB硬件缓冲区))

  1. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x40);
  2.   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x80);

  3.   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CUSTOM_HID_EPIN_ADDR , PCD_SNG_BUF, 0xC0);
  4.   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CUSTOM_HID_EPOUT_ADDR , PCD_SNG_BUF, 0x100);
  5.   
  6.   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MOUSE_HID_EPIN_ADDR , PCD_SNG_BUF, 0x140);
  7.   HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , KEY_HID_EPIN_ADDR , PCD_SNG_BUF, 0x180);
  • 7. 打开和配置端点:定位到USBD_CUSTOM_HID->USBD_CUSTOM_HID_Init通过USBD_LL_OpenEP函数中和pdev->ep_in[EP_ADDR & 0xFU].is_used = 1U;打开并使能端点,同时将USBD_LL_PrepareReceive中第四个参数改为大(如果用到接收端点);

  1. static uint8_t  USBD_CUSTOM_HID_Init(USBD_HandleTypeDef *pdev,uint8_t cfgidx)
  2. {
  3.   uint8_t ret = 0U;
  4.   USBD_CUSTOM_HID_HandleTypeDef     *hhid;
  5.   /* Open EP IN */
  6.   USBD_LL_OpenEP(pdev, CUSTOM_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,CUSTOM_HID_EPIN_SIZE);
  7.   pdev->ep_in[CUSTOM_HID_EPIN_ADDR & 0xFU].is_used = 1U;
  8.   /* Open EP OUT */
  9.   USBD_LL_OpenEP(pdev, CUSTOM_HID_EPOUT_ADDR, USBD_EP_TYPE_INTR,CUSTOM_HID_EPOUT_SIZE);
  10.   pdev->ep_out[CUSTOM_HID_EPOUT_ADDR & 0xFU].is_used = 1U;                                 
  11.   /* Open MOUSE EP IN */
  12.   USBD_LL_OpenEP(pdev, MOUSE_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,MOUSE_HID_EPIN_SIZE);
  13.   pdev->ep_in[MOUSE_HID_EPIN_ADDR & 0xFU].is_used = 1U;        
  14.   /* Open KEY EP IN */
  15.   USBD_LL_OpenEP(pdev, KEY_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,KEY_HID_EPIN_SIZE);
  16.   pdev->ep_in[KEY_HID_EPIN_ADDR & 0xFU].is_used = 1U;        
  17.   pdev->pClassData = USBD_malloc(sizeof(USBD_CUSTOM_HID_HandleTypeDef));
  18.   if (pdev->pClassData == NULL)
  19.   {
  20.     ret = 1U;
  21.   }
  22.   else
  23.   {
  24.     hhid = (USBD_CUSTOM_HID_HandleTypeDef *) pdev->pClassData;

  25.     hhid->state = CUSTOM_HID_IDLE;
  26.     ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->Init();

  27.     /* Prepare Out endpoint to receive 1st packet */
  28.     USBD_LL_PrepareReceive(pdev, CUSTOM_HID_EPOUT_ADDR, hhid->Report_buf,
  29.                            USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
  30.   }
  31.   return ret;
  32. }
  • 8. 设置USB设备发生复位则实现端点关闭,释放内存。

  1. static uint8_t  USBD_CUSTOM_HID_DeInit(USBD_HandleTypeDef *pdev,
  2.                                        uint8_t cfgidx)
  3. {
  4.   /* Close CUSTOM_HID EP IN */
  5.   USBD_LL_CloseEP(pdev, CUSTOM_HID_EPIN_ADDR);
  6.   pdev->ep_in[CUSTOM_HID_EPIN_ADDR & 0xFU].is_used = 0U;

  7.   /* Close CUSTOM_HID EP OUT */
  8.   USBD_LL_CloseEP(pdev, CUSTOM_HID_EPOUT_ADDR);
  9.   pdev->ep_out[CUSTOM_HID_EPOUT_ADDR & 0xFU].is_used = 0U;

  10.   /* Close MOUSE_HID EP IN */
  11.   USBD_LL_CloseEP(pdev, MOUSE_HID_EPIN_ADDR);
  12.   pdev->ep_in[MOUSE_HID_EPIN_ADDR & 0xFU].is_used = 0U;        
  13.         
  14.   /* Close JOYSTICK_HID EP IN */
  15.   USBD_LL_CloseEP(pdev, KEY_HID_EPIN_ADDR);
  16.   pdev->ep_in[KEY_HID_EPIN_ADDR & 0xFU].is_used = 0U;               

  17.   /* FRee allocated memory */
  18.   if (pdev->pClassData != NULL)
  19.   {
  20.     ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->DeInit();
  21.     USBD_free(pdev->pClassData);
  22.     pdev->pClassData = NULL;
  23.   }
  24.   return USBD_OK;
  25. }
至此,插上USB已经可以枚举成三个组合的HID了。但是也仅仅是万丈高楼平地起,只是打了了基础,只是配置好了usb,仅仅是实现了usb功能,我们的应用功能还需要安排上。
  1. MultiTimer timer1;
  2. MultiTimer timer2;
  3. MultiTimer timer3;
  4. void SystemClock_Config(void);
  5. typedef enum
  6. {
  7.         DEVICE_JOYSTICK=0,
  8.         DEVICE_MOUSE,
  9.         DEVICE_KEYBOARD
  10. }DEVICE_TypeDef;
  11. DEVICE_TypeDef myHid=DEVICE_JOYSTICK;
  12. void RportTimer1Callback(MultiTimer* timer, void *userData)
  13. {
  14.         if(myHid==DEVICE_JOYSTICK)
  15.         {
  16.                 Joystick_Handle();
  17.         }else if(myHid==DEVICE_MOUSE){
  18.                 Mouse_Handle();               
  19.         }else if(myHid==DEVICE_KEYBOARD){
  20.                 Key_Board_Handle();
  21.         }   
  22.     MultiTimerStart(timer, 10, RportTimer1Callback, userData);
  23. }
  24. void WS2812BTimer2Callback(MultiTimer* timer, void *userData)
  25. {
  26.         if(myHid==DEVICE_JOYSTICK)
  27.         {
  28.                 WS_WriteAll_RGB(0xFF,0x00,0x00);
  29.         }else if(myHid==DEVICE_MOUSE){
  30.                 WS_WriteAll_RGB(0x00,0xFF,0x00);               
  31.         }else if(myHid==DEVICE_KEYBOARD){
  32.                 WS_WriteAll_RGB(0x00,0x00,0xFF);
  33.         }        
  34.     MultiTimerStart(timer, 100, WS2812BTimer2Callback, userData);
  35. }
  36. void DeviceSwitchTimer3Callback(MultiTimer* timer, void *userData)
  37. {
  38.         static u16 swtick=0;
  39.         if((UPKEY)==0)
  40.         {
  41.                 if(swtick++>300)
  42.                 {
  43.                         swtick=0;
  44.                         if(++myHid>DEVICE_KEYBOARD)
  45.                         {
  46.                                 myHid=DEVICE_JOYSTICK;
  47.                         }               
  48.                 }
  49.         }else{
  50.                 swtick=0;
  51.         }   
  52.     MultiTimerStart(timer, 10, DeviceSwitchTimer3Callback, userData);
  53. }
  54. int main(void)
  55. {
  56.     HAL_Init();
  57.     SystemClock_Config();
  58.     MultiTimerInstall(PlatformTicksGetFunc);
  59.     MX_GPIO_Init();
  60.     MX_DMA_Init();
  61.     MX_ADC1_Init();
  62.     MX_USB_DEVICE_Init();
  63.     MX_USART1_UART_Init();
  64.     MX_TIM3_Init();
  65.     Gp_ADC_Start_DMA();
  66.     MultiTimerStart(&timer1, 5, RportTimer1Callback, NULL);
  67.     MultiTimerStart(&timer2, 10, WS2812BTimer2Callback, NULL);
  68.         MultiTimerStart(&timer3, 10, DeviceSwitchTimer3Callback, NULL);
  69.     while (1)
  70.     {
  71.         MultiTimerYield();
  72.     }
  73. }
下载验证

我们把固件程序下载进去,摇动摇杆,按住SW2大于4s,可依次切换成鼠标模式成摇杆、鼠标、键盘模式,2812显示对应的红绿蓝色。在不同设备模式下摇动摇杆或轻触按键可以测试不同设备下的不同功能,而由于我们硬件条件有限,所以使用了分时复用,而如果您是自己设计了其他硬件,完全可以在我们的基础上修改,加加加,实现自己客制化的功能,毕竟现在网上有很多客制化键盘鼠标摇杆方案。具体的实现现象可以观看我们的视频;

视频教程




打赏榜单

21ic小管家 打赏了 30.00 元 2022-12-20
理由:签约作者奖励

Pretext 发表于 2022-12-12 13:57 | 显示全部楼层
?这是后面的内容没有发出来吗?
 楼主| lilijin1995 发表于 2022-12-13 11:03 | 显示全部楼层
Pretext 发表于 2022-12-12 13:57
?这是后面的内容没有发出来吗?

已更完成
Pretext 发表于 2023-1-10 17:54 | 显示全部楼层

这做的不错啊,感觉大佬是专业做教程的。
1021256354 发表于 2024-4-8 21:35 | 显示全部楼层
有工程给发一下么?3q
您需要登录后才可以回帖 登录 | 注册

本版积分规则

56

主题

165

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部