序:
其实这样一个设备我们在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[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __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_COLLECTION0xc0                                                      // END_COLLECTION        };/* USER CODE BEGIN PRIVATE_VARIABLES */__ALIGN_BEGIN static uint8_t Mouse_ReportDesc_FS[USBD_MOUSE_REPORT_DESC_SIZE] __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_COLLECTION0xc0                                               // END_COLLECTION};__ALIGN_BEGIN static uint8_t KEY_ReportDesc_FS[USBD_KEY_REPORT_DESC_SIZE] __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[USB_CUSTOM_HID_CONFIG_DESC_SIZ] __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_t  USBD_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){//mouselen = 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[EP_ADDR & 0xFU].is_used = 1U;打开并使能端点,同时将USBD_LL_PrepareReceive中第四个参数改为大(如果用到接收端点);
static uint8_t  USBD_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[CUSTOM_HID_EPIN_ADDR & 0xFU].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[CUSTOM_HID_EPOUT_ADDR & 0xFU].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[MOUSE_HID_EPIN_ADDR & 0xFU].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[KEY_HID_EPIN_ADDR & 0xFU].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_t  USBD_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[CUSTOM_HID_EPIN_ADDR & 0xFU].is_used = 0U;/* Close CUSTOM_HID EP OUT */USBD_LL_CloseEP(pdev, CUSTOM_HID_EPOUT_ADDR);pdev->ep_out[CUSTOM_HID_EPOUT_ADDR & 0xFU].is_used = 0U;/* Close MOUSE_HID EP IN */USBD_LL_CloseEP(pdev, MOUSE_HID_EPIN_ADDR);pdev->ep_in[MOUSE_HID_EPIN_ADDR & 0xFU].is_used = 0U;        /* Close JOYSTICK_HID EP IN */USBD_LL_CloseEP(pdev, KEY_HID_EPIN_ADDR);pdev->ep_in[KEY_HID_EPIN_ADDR & 0xFU].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显示对应的红绿蓝色。在不同设备模式下摇动摇杆或轻触按键可以测试不同设备下的不同功能,而由于我们硬件条件有限,所以使用了分时复用,而如果您是自己设计了其他硬件,完全可以在我们的基础上修改,加加加,实现自己客制化的功能,毕竟现在网上有很多客制化键盘鼠标摇杆方案。具体的实现现象可以观看我们的视频;!
---------------------
作者:lilijin1995
链接:https://bbs.21ic.com/icview-3272282-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

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

  1. 基于STM32 HAL库的遥控小车

    目录 前言 一.材料清单 二.系统概述 三.硬件设计 1.HC-SR04超声波模块 2.HC-05/06蓝牙模块 3.L298n电机驱动模块 四.代码 1.引脚设置 2.遥控部分 3.超声波报警部分 ...

  2. HIH8121(HIH8000系列)温湿度传感器驱动代码-基于STM32 HAL库

    HIH8121温湿度传感器代码基于STM32 HAL库 HIH8121传感器简介 驱动代码.c 驱动代码.h main函数 HIH8121传感器简介 HIH8121是霍尼韦尔公司生产的测量温湿度参数一 ...

  3. DW1000开发笔记(三)基于STM32 HAL库裸机工程移植DW1000官方驱动

    系列文章 DW1000开发笔记(一)DW1000芯片概览 DW1000开发笔记(二)使用STM32硬件SPI+STM32cubeMX+HAL库测试DW1000通信 一.官方驱动 Decawave官方提 ...

  4. 基于STM32(HAL库)的水质检测(浑浊度、PH值、温度、手机APP显示、wifi上云)

    本系统由通过wifi将浑浊度.PH值.温度采集的数据发送到手机APP,超过设定的阈值报警. 一.硬件材料清单: 1.STM32C8T6:控制器 2.OLED显示屏:显示传感器采集的数据 3.PH传感器 ...

  5. MAX6675 带冷端补偿的热电偶测温芯片驱动-基于STM32 HAL库

    MAX6675 简介 MAX6675 是一款带冷端补偿的热电偶测温芯片,通过3线SPI总线直接输出热电偶测量温度值. 引脚如下: 与单片机连接关系如下: 通信时序与数据格式如下: MAX6675 驱动 ...

  6. 移植Freemodbus到STM32(基于CubeMX,HAL库)-避坑篇

    具体Freemodbus移植到STM32步骤参考: STMC2CubeMX | STM32 HAL库移植FreeModbus详细步骤 基于STM32HAL库移植FreeModbus FreeModbu ...

  7. STM32 HAL库学习笔记1-HAL库简介

    STM32 HAL库学习笔记1-HAL库简介 HAL库 SPL 库 和 HAL 库两者相互独立,互不兼容.几种库的比较如下 目前几种库对不同芯片的支持情况如下 ST 中文官网上有一篇<关于ST库 ...

  8. (一)使用TrueSTUDIO软件新建一个基于STM32标准库工程

    一.TrueSTUDIO说明 不管是还在学习的还是已经工作的应该都很熟悉Keil和IAR这两款用来开发嵌入式的软件,在国内普遍用的这两款编译软件都是破解版的,并没有经过正规渠道授权注册,这就导致了在开 ...

  9. STM32 HAL库、标准外设库、LL库(STM32 Embedded Software)

    STM32 Embedded Software 工作以来一直使用ST的STM32系列芯片,ST为开发者提供了非常方便的开发库.到目前为止,有标准外设库(STD库).HAL库.LL库 三种.前两者都是常 ...

最新文章

  1. 【初窥javascript奥秘之事件机制】论“点透”与“鬼点击”
  2. Oracle系统表查询
  3. 暗通道优先的图像去雾算法(上)
  4. 数据结构源码笔记(C语言描述)汇总
  5. 使用docker开启nginx
  6. ByteBuf主要继承关系图
  7. 阿里P8大佬亲自讲解!朝阳java培训
  8. rstudio的数据集怎么建立和保存_这个40M的小工具助你在windows下处理数据如虎添翼...
  9. 打破10倍速软件工程师神话
  10. 人工智能、机器学习以及深度学习之间的联系是什么?
  11. 如何搭建企业大数据分析平台
  12. ie内核出现问题的解决方法
  13. 国自然的技术路线图?用PPT试试
  14. php 处理微信昵称含有特殊符号
  15. 【Python中三角函数正弦、余弦、正切的计算】
  16. PaddlePaddle 波斯顿房价预测训练结果
  17. micro-app 微前端脚手架搭建
  18. 微信小程序生成二维码方法1
  19. Android 毛小软件,安卓薅羊毛软件
  20. 【C语言笔记】【宏定义系列】 绝对值

热门文章

  1. 从TargetApi22升级到TargetApi26注意事项
  2. html+css 实现 熊猫样式
  3. Jcseg是基于mmseg算法的一个轻量级Java中文分词器
  4. DockerCompose MongoDB 副本集(集群) (客户端验证密码 - 集群内部使用mongodbKeyfile验证 ) 部署
  5. linux new date差8个小时,柚子生活-解决Docker容器new Date()时间比北京时间早八个小时问题...
  6. 大学毕业时找工作的经历
  7. c语言置字节某一位为0,C语言位操作中指定的某一位数置0、置1、取反
  8. [转]wpa_supplicant连接wifi出错
  9. 李抗强:类自然数简单幻立方的构造
  10. HTML5基础——笔记