lilijin1995 发表于 2022-12-12 11:37

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

本帖最后由 lilijin1995 于 2022-12-13 10:45 编辑

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

实验材料:
使用我们自己设计的MiniGamepad板子如下图,我们这款板子是为了测试学习方便用的。

软件设计:
目标是实现Joystick、Mouse和Keyboard的组合,即把三个设备组合成一个设备,通过按键SW2按下依次切换成Joystick、Mouse和Keyboard设备,而WS2812灯珠则通过红绿蓝指示切换三种不同的设备。
下面分8个步骤来实现HID的枚举。

[*]1. 准备Joystick、Mouse和Keyboard三个报表,这三个报表分别是实例Eg1_Joystick、实例Eg4_Mouse与实例Eg5_KeyBoard的报表,
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS __ALIGN_END =
{
      
    0x05, 0x01,                  // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                  // USAGE (Joystick)
    0xa1, 0x01,                  // COLLECTION (Application)
    0xa1, 0x02,                  //   COLLECTION (Logical)
    0x09, 0x30,                  //   USAGE (X)
    0x09, 0x31,                  //   USAGE (Y)
    0x15, 0x00,                  //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,            //   LOGICAL_MAXIMUM (255)
    0x35, 0x00,                  //   PHYSICAL_MINIMUM (0)
    0x46, 0xff, 0x00,            //   PHYSICAL_MAXIMUM (255)
    0x75, 0x08,                  //   REPORT_SIZE (8)
    0x95, 0x02,                  //   REPORT_COUNT (2)
    0x81, 0x02,                  //   INPUT (Data,Var,Abs)
    0x05, 0x09,                  //   USAGE_PAGE (Button)
    0x19, 0x01,                  //   USAGE_MINIMUM (Button 1)
    0x29, 0x08,                  //   USAGE_MAXIMUM (Button 8)
    0x15, 0x00,                  //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                  //   LOGICAL_MAXIMUM (1)
    0x95, 0x08,                  //   REPORT_COUNT (8)
    0x75, 0x01,                  //   REPORT_SIZE (1)
    0x81, 0x02,                  //   INPUT (Data,Var,Abs)
    0xc0,                        //   END_COLLECTION
      0xc0                                                      // END_COLLECTION      
      

};

/* USER CODE BEGIN PRIVATE_VARIABLES */
__ALIGN_BEGIN static uint8_t Mouse_ReportDesc_FS __ALIGN_END =
{
      0x05, 0x01,                  // USAGE_PAGE (Generic Desktop)
      0x09, 0x02,                  // USAGE (Mouse)
      0xa1, 0x01,                  // COLLECTION (Application)
      0x09, 0x01,                  //   USAGE (Pointer)
      0xa1, 0x00,                  //   COLLECTION (Physical)
      0x05, 0x09,                  //   USAGE_PAGE (Button)
      0x19, 0x01,                  //   USAGE_MINIMUM (Button 1)
      0x29, 0x03,                  //   USAGE_MAXIMUM (Button 3)
      0x15, 0x00,                  //   LOGICAL_MINIMUM (0)
      0x25, 0x01,                  //   LOGICAL_MAXIMUM (1)
      0x95, 0x03,                  //   REPORT_COUNT (3)
      0x75, 0x01,                  //   REPORT_SIZE (1)
      0x81, 0x02,                  //   INPUT (Data,Var,Abs)
      0x95, 0x01,                  //   REPORT_COUNT (1)
      0x75, 0x05,                  //   REPORT_SIZE (5)
      0x81, 0x03,                  //   INPUT (Cnst,Var,Abs)
      0x05, 0x01,                  //   USAGE_PAGE (Generic Desktop)
      0x09, 0x30,                  //   USAGE (X)
      0x09, 0x31,                  //   USAGE (Y)
      0x09, 0x38,                  //   USAGE (Wheel)
      0x15, 0x81,                  //   LOGICAL_MINIMUM (-127)
      0x25, 0x7f,                  //   LOGICAL_MAXIMUM (127)
      0x75, 0x08,                  //   REPORT_SIZE (8)
      0x95, 0x03,                  //   REPORT_COUNT (3)
      0x81, 0x06,                  //   INPUT (Data,Var,Rel)
      0xc0,                        //   END_COLLECTION
      0xc0                                             // END_COLLECTION
};


__ALIGN_BEGIN static uint8_t KEY_ReportDesc_FS __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
/* USER CODE END 0 */
0xC0    /*   END_COLLECTION                     */

};
[*]2. 修改USBD_CUSTOM_HID_ItfTypeDef结构体及其实例USBD_CustomHID_fops_FS,可以看到其实这个结构体的前三个成员其实就是指向了以上三个报表描述符。
typedef struct _USBD_CUSTOM_HID_Itf
{
      uint8_t                  *jReport;
      uint8_t                  *mReport;
    uint8_t                  *kReport;
    int8_t (* Init)(void);
    int8_t (* DeInit)(void);
    int8_t (* OutEvent)(uint8_t event_idx, uint8_t state);

} USBD_CUSTOM_HID_ItfTypeDef;

USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS =
{
CUSTOM_HID_ReportDesc_FS,
Mouse_ReportDesc_FS,
KEY_ReportDesc_FS,      
CUSTOM_HID_Init_FS,
CUSTOM_HID_DeInit_FS,
CUSTOM_HID_OutEvent_FS
};
[*]3. 修改配置描述符集合。增加接口,端点等。
__ALIGN_BEGIN static uint8_t USBD_CUSTOM_HID_CfgFSDesc __ALIGN_END =
{
    0x09, /* bLength: Configuration Descriptor size */
    USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
    USB_CUSTOM_HID_CONFIG_DESC_SIZ,
    /* wTotalLength: Bytes returned */
    0x00,
    0x03,         /*bNumInterfaces: 1 interface*/
    0x01,         /*bConfigurationValue: Configuration value*/
    0x00,         /*iConfiguration: Index of string descriptor describing the configuration*/
    0x80,         /*bmAttributes: bus powered */
    0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

    //----------- Descriptor of Joystick interface ---------------------//
    /* 09 */
    0x09,         /*bLength: Interface Descriptor size*/
    USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
    0x00,         /*bInterfaceNumber: Number of Interface*/
    0x00,         /*bAlternateSetting: Alternate setting*/
    0x01,         /*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*/
    //-----------HID Descriptor of Joystick---------------------//
    /* 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 Joystick 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: 2 Byte max */
    0x00,
    CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
    /* 34 */

    //-----------Descriptor of Mouse interface    ---------------------//
    0x09,         /*bLength: Interface Descriptor size*/
    USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
    0x01,         /*bInterfaceNumber: Number of Interface*/
    0x00,         /*bAlternateSetting: Alternate setting*/
    0x01,         /*bNumEndpoints*/
    0x03,         /*bInterfaceClass: CUSTOM_HID*/
    0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
    0x02,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
    0,            /*iInterface: Index of string descriptor*/
    //-----------   Descriptor of Mouse CUSTOM_HID    ---------------------//
    /* 43 */
    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_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
    0x00,
    //-----------    Descriptor of Mouse endpoints    ---------------------//
    /* 52 */
    0x07,          /*bLength: Endpoint Descriptor size*/
    USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/

    MOUSE_HID_EPIN_ADDR,   /*bEndpointAddress: Endpoint Address (IN)*/
    0x03,          /*bmAttributes: Interrupt endpoint*/
    MOUSE_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
    0x00,
    CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
    /* 59 */
    //-----------Descriptor of KeyBoard interface    ---------------------//
    0x09,         /*bLength: Interface Descriptor size*/
    USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
    0x02,         /*bInterfaceNumber: Number of Interface*/
    0x00,         /*bAlternateSetting: Alternate setting*/
    0x01,         /*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 KeyBoard CUSTOM_HID    ---------------------//
    /* 68 */
    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_KEY_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
    0x00,
    //-----------    Descriptor of KeyBoard endpoints    ---------------------//
    /* 77 */
    0x07,          /*bLength: Endpoint Descriptor size*/
    USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/

    KEY_HID_EPIN_ADDR,   /*bEndpointAddress: Endpoint Address (IN)*/
    0x03,          /*bmAttributes: Interrupt endpoint*/
    KEY_HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */
    0x00,
    CUSTOM_HID_FS_BINTERVAL,          /*bInterval: Polling Interval */
    /* 84 */
};
[*]4. 在usbd_conf.h修改最大接口数量为3(这一步非常关键)
#define USBD_MAX_NUM_INTERFACES   3
[*]5. 根据接口索引修改获取描述符的请求:定位到USBD_CUSTOM_HID->USBD_CUSTOM_HID_Setup在USB_REQ_GET_DESCRIPTOR请求中通过req->wIndex增加报告描述符的请求;
static uint8_tUSBD_CUSTOM_HID_Setup(USBD_HandleTypeDef *pdev,
                                    USBD_SetupReqTypedef *req)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassData;
uint16_t len = 0U;
uint8_t*pbuf = NULL;
uint16_t status_info = 0U;
uint8_t ret = USBD_OK;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
    case USB_REQ_TYPE_STANDARD:
      switch (req->bRequest)
      {
      case USB_REQ_GET_DESCRIPTOR:
          if (req->wValue >> 8 == CUSTOM_HID_REPORT_DESC)
          {                        
                        if (req->wIndex == 0)
                        {
                              len = MIN(USBD_CUSTOM_HID_REPORT_DESC_SIZE, req->wLength);
                              pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->jReport;                                 
                        }else if (req->wIndex == 1){//mouse
                              len = MIN(USBD_MOUSE_REPORT_DESC_SIZE, req->wLength);
                              pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->mReport;      
                        
                        }else if (req->wIndex == 2){//
                              len = MIN(USBD_KEY_REPORT_DESC_SIZE, req->wLength);
                              pbuf = ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->kReport;                                 
                        }                                                                              
          }
          else
          {
            if (req->wValue >> 8 == CUSTOM_HID_DESCRIPTOR_TYPE)
            {                                                               
            pbuf = USBD_CUSTOM_HID_Desc;
            len = MIN(USB_CUSTOM_HID_DESC_SIZ, req->wLength);
            }
          }
          USBD_CtlSendData(pdev, pbuf, len);
          break;
}
return ret;
}
[*]6. 为端点增加PAM:定位到MX_USB_DEVICE_Init->USBD_Init->USBD_LL_Init;在USBD_LL_Init函数中找到HAL_PCDEx_PMAConfig,通过该接口为EP(端点)配置PMA(Packet Buffer Memory Area ,即USB硬件缓冲区))
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x40);
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x80);

HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CUSTOM_HID_EPIN_ADDR , PCD_SNG_BUF, 0xC0);
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CUSTOM_HID_EPOUT_ADDR , PCD_SNG_BUF, 0x100);

HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MOUSE_HID_EPIN_ADDR , PCD_SNG_BUF, 0x140);
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.is_used = 1U;打开并使能端点,同时将USBD_LL_PrepareReceive中第四个参数改为大(如果用到接收端点);
static uint8_tUSBD_CUSTOM_HID_Init(USBD_HandleTypeDef *pdev,uint8_t cfgidx)
{
uint8_t ret = 0U;
USBD_CUSTOM_HID_HandleTypeDef   *hhid;
/* Open EP IN */
USBD_LL_OpenEP(pdev, CUSTOM_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,CUSTOM_HID_EPIN_SIZE);
pdev->ep_in.is_used = 1U;
/* Open EP OUT */
USBD_LL_OpenEP(pdev, CUSTOM_HID_EPOUT_ADDR, USBD_EP_TYPE_INTR,CUSTOM_HID_EPOUT_SIZE);
pdev->ep_out.is_used = 1U;                                 
/* Open MOUSE EP IN */
USBD_LL_OpenEP(pdev, MOUSE_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,MOUSE_HID_EPIN_SIZE);
pdev->ep_in.is_used = 1U;      
/* Open KEY EP IN */
USBD_LL_OpenEP(pdev, KEY_HID_EPIN_ADDR, USBD_EP_TYPE_INTR,KEY_HID_EPIN_SIZE);
pdev->ep_in.is_used = 1U;      
pdev->pClassData = USBD_malloc(sizeof(USBD_CUSTOM_HID_HandleTypeDef));
if (pdev->pClassData == NULL)
{
    ret = 1U;
}
else
{
    hhid = (USBD_CUSTOM_HID_HandleTypeDef *) pdev->pClassData;

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

    /* Prepare Out endpoint to receive 1st packet */
    USBD_LL_PrepareReceive(pdev, CUSTOM_HID_EPOUT_ADDR, hhid->Report_buf,
                           USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
}
return ret;
}
[*]8. 设置USB设备发生复位则实现端点关闭,释放内存。
static uint8_tUSBD_CUSTOM_HID_DeInit(USBD_HandleTypeDef *pdev,
                                       uint8_t cfgidx)
{
/* Close CUSTOM_HID EP IN */
USBD_LL_CloseEP(pdev, CUSTOM_HID_EPIN_ADDR);
pdev->ep_in.is_used = 0U;

/* Close CUSTOM_HID EP OUT */
USBD_LL_CloseEP(pdev, CUSTOM_HID_EPOUT_ADDR);
pdev->ep_out.is_used = 0U;

/* Close MOUSE_HID EP IN */
USBD_LL_CloseEP(pdev, MOUSE_HID_EPIN_ADDR);
pdev->ep_in.is_used = 0U;      
      
/* Close JOYSTICK_HID EP IN */
USBD_LL_CloseEP(pdev, KEY_HID_EPIN_ADDR);
pdev->ep_in.is_used = 0U;               

/* FRee allocated memory */
if (pdev->pClassData != NULL)
{
    ((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->DeInit();
    USBD_free(pdev->pClassData);
    pdev->pClassData = NULL;
}
return USBD_OK;
}至此,插上USB已经可以枚举成三个组合的HID了。但是也仅仅是万丈高楼平地起,只是打了了基础,只是配置好了usb,仅仅是实现了usb功能,我们的应用功能还需要安排上。
MultiTimer timer1;
MultiTimer timer2;
MultiTimer timer3;
void SystemClock_Config(void);
typedef enum
{
      DEVICE_JOYSTICK=0,
      DEVICE_MOUSE,
      DEVICE_KEYBOARD
}DEVICE_TypeDef;
DEVICE_TypeDef myHid=DEVICE_JOYSTICK;
void RportTimer1Callback(MultiTimer* timer, void *userData)
{
      if(myHid==DEVICE_JOYSTICK)
      {
                Joystick_Handle();
      }else if(myHid==DEVICE_MOUSE){
                Mouse_Handle();               
      }else if(myHid==DEVICE_KEYBOARD){
                Key_Board_Handle();
      }   
    MultiTimerStart(timer, 10, RportTimer1Callback, userData);
}
void WS2812BTimer2Callback(MultiTimer* timer, void *userData)
{
      if(myHid==DEVICE_JOYSTICK)
      {
                WS_WriteAll_RGB(0xFF,0x00,0x00);
      }else if(myHid==DEVICE_MOUSE){
                WS_WriteAll_RGB(0x00,0xFF,0x00);               
      }else if(myHid==DEVICE_KEYBOARD){
                WS_WriteAll_RGB(0x00,0x00,0xFF);
      }      
    MultiTimerStart(timer, 100, WS2812BTimer2Callback, userData);
}
void DeviceSwitchTimer3Callback(MultiTimer* timer, void *userData)
{
      static u16 swtick=0;
      if((UPKEY)==0)
      {
                if(swtick++>300)
                {
                        swtick=0;
                        if(++myHid>DEVICE_KEYBOARD)
                        {
                              myHid=DEVICE_JOYSTICK;
                        }               
                }
      }else{
                swtick=0;
      }   
    MultiTimerStart(timer, 10, DeviceSwitchTimer3Callback, userData);
}
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MultiTimerInstall(PlatformTicksGetFunc);
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_USB_DEVICE_Init();
    MX_USART1_UART_Init();
    MX_TIM3_Init();
    Gp_ADC_Start_DMA();
    MultiTimerStart(&timer1, 5, RportTimer1Callback, NULL);
    MultiTimerStart(&timer2, 10, WS2812BTimer2Callback, NULL);
      MultiTimerStart(&timer3, 10, DeviceSwitchTimer3Callback, NULL);
    while (1)
    {
      MultiTimerYield();
    }
}
下载验证我们把固件程序下载进去,摇动摇杆,按住SW2大于4s,可依次切换成鼠标模式成摇杆、鼠标、键盘模式,2812显示对应的红绿蓝色。在不同设备模式下摇动摇杆或轻触按键可以测试不同设备下的不同功能,而由于我们硬件条件有限,所以使用了分时复用,而如果您是自己设计了其他硬件,完全可以在我们的基础上修改,加加加,实现自己客制化的功能,毕竟现在网上有很多客制化键盘鼠标摇杆方案。具体的实现现象可以观看我们的视频;视频教程
https://www.bilibili.com/video/BV1YK41197HC/?vd_source=2bbde87de845d5220b1d8ba075c12fb0



Pretext 发表于 2022-12-12 13:57

?这是后面的内容没有发出来吗?

lilijin1995 发表于 2022-12-13 11:03

Pretext 发表于 2022-12-12 13:57
?这是后面的内容没有发出来吗?

已更完成

Pretext 发表于 2023-1-10 17:54

lilijin1995 发表于 2022-12-13 11:03
已更完成

这做的不错啊,感觉大佬是专业做教程的。

1021256354 发表于 2024-4-8 21:35

有工程给发一下么?3q
页: [1]
查看完整版本: 基于STM32 HAL库实现鼠标键盘摇杆的USB复合设备