使用stm32配置自定义的HID设备

STM32USB设备设计步骤:

申明:文章为原创性文章,转载请申明!!!

本文不对USB协议进行讲述,对于usb协议,我建议大家静下心好好去看下对应的资料,USB协议不是一个简单的协议,不是一两天就能弄透彻的!对usb协议零基础者,建议大家可以看《圈圈教你玩USB》这本书的前面一部分将USB协议的,去网上搜能搜到电子版的!

1. 使用CubeMX生成一个HID工程(注意不是Custom HID),默认生成的为模拟鼠标工程,我们需要在此基础上修改成我们自己的HID设备。

Cubemx配置步骤:

  1. System Core->RCC->High Speed Clock: Crystal/Ceramic Resonator
  2. System Core->SYS: Serial Wire
  3. Connectivity->USB_OTG_FS->Mode: Device_Only
  4. Middleware->USB_DEVICE->Class For FS IP: Human Interface Device Class (HID)
  5. 然后设置下System Core->NVIC中的USB OTG FS global interrupt 优先级
  6. 再配置时钟 确保USB时钟为48MHZ即可
  7. 之后可以生成代码了
    至此,模板已经建立完成!!!!

2. 打开工程,编译下载,保证你硬件没问题,插上电脑之后,在设备管理器中便可以看到多了一个USB输入设备!

3. 在main.c中添加以下应用代码:

#include "usbd_hid.h"
extern USBD_HandleTypeDef hUsbDeviceFS;

修改main函数

int main(void)
{
  struct mouseHID_t {
      uint8_t buttons;
      int8_t x;
      int8_t y;
      int8_t wheel;
  }; 
 
  struct mouseHID_t mouseHID;
  
  mouseHID.buttons = 0;
  mouseHID.x = 10;
  mouseHID.y = 0;
  mouseHID.wheel = 0;
  
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USB_DEVICE_Init();
  while (1)
  {
	 USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&mouseHID, sizeof(struct mouseHID_t));
	 HAL_Delay(1000);
  }

编译下载,然后把板子插上电脑,不动你的鼠标,你会看到鼠标每隔1s会往右边移动一点点,这就是模拟鼠标功能!
至此,我们的模板已经验证完成,接下来就是在此基础上修改成我们所需要的自定义的设备了!
为什么要该呢?
因为此模板有局限性,这是一个模拟鼠标的模板,当然也就只能实现基础的鼠标的功能,但是我们往往做成USB设备,不会只弄个鼠标,甚至有的只是借助usb来实现通讯,那么使用鼠标这个肯定是不行的,而且此模板一次只能发送4个字节的数据,4个字节怎么可能满足我们的需求!

4. 熟悉工程的结构

与usb有关的文件有如下文件:

**stm32f1xx.it.c 存放usb中断服务函数
usb_device.c USB初始化
usbd_desc.c 重点存放 USB设备描述符
usbd_conf.c 发送接收、初始化、回调函数 等等底层函数 与HAL库结合
usbd_core.c 内核相关
usbd_ctlreq.c 控制请求
usbd_ioreq.c 输入输出请求
usbd_hid.c HID配置
**
其中对于我们使用最为重要的是
usbd_desc.c
usbd_hid.c
我们主要修改这两个函数内的描述符,其他usb协议逻辑啥的我们基本不需要动

5. 修改设备描述符

usbd_desc.c文件内存放了设备描述符的数组
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
  0x12,                       /*bLength */
  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
  0x00,                       /*bcdUSB */
  0x02,
  0x00,                       /*bDeviceClass*/
  0x00,                       /*bDeviceSubClass*/
  0x00,                       /*bDeviceProtocol*/
  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
  LOBYTE(USBD_VID),           /*idVendor*/
  HIBYTE(USBD_VID),           /*idVendor*/
  LOBYTE(USBD_PID_FS),        /*idProduct*/
  HIBYTE(USBD_PID_FS),        /*idProduct*/
  0x00,                       /*bcdDevice rel. 2.00*/
  0x02,
  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
};

上面数组中使用到了的宏定义

#define  USB_DESC_TYPE_DEVICE                           0x01U
#define USB_MAX_EP0_SIZE                                64U
#define USBD_VID     									1155
#define USBD_LANGID_STRING     							1033
#define USBD_MANUFACTURER_STRING     					"STMicroelectronics"
#define USBD_PID_FS    									22315
#define USBD_PRODUCT_STRING_FS     						"STM32 Human interface"
#define USBD_CONFIGURATION_STRING_FS     				"HID Config"
#define USBD_INTERFACE_STRING_FS     					"HID Interface"
#define  USBD_IDX_MFC_STR                               0x01U
#define  USBD_IDX_PRODUCT_STR                           0x02U
#define  USBD_IDX_SERIAL_STR                            0x03U

我们一般修改usb设备的厂家ID,也就是对应的USBD_VID为0xff,0xff应该没有哪个厂家申请吧

#define USBD_VID     									0xFF

厂家ID是需要像USB协会申请的,要交保护会,有的id被别的公司申请了,如果你不小心用了别人的,电脑识别之后会自动加载别人厂家对应的驱动程序,有可能导致你的实验失败

6.修改usb_hid.c,打造我们自己的特定设备

usb_hid.c这个函数有点坑的,在这个函数中有几个配置数组实际是没有使用到的,但是你不要去删除,他被其他函数调用,别管就好了,我们需要配置只有两个数组

/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ]  __ALIGN_END =
{
	...
}

//USB 鼠标端口描述符
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
	...
}

只需要修改上述两个数组的内容就可以了,主要就是这两个数组,首先给大家看下我改成了什么样子吧


/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ]  __ALIGN_END =
{
  /****************配置描述符****************/
  0x09, /* bLength: Configuration Descriptor size 描述符长度 */
  USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration 描述符类型 配置描述符为0x02*/
  USB_HID_CONFIG_DESC_SIZ,  /* wTotalLength: Bytes returned 描述符集合长度 两个字节 低位在前 */
  0x00,
  0x01,         /*bNumInterfaces: 1 interface 配置支持的接口数量*/
  0x01,         /*bConfigurationValue: Configuration value 配置的值*/
  0x00,         /*iConfiguration: Index of string descriptor describing the configuration 字符串索引值 为0表示没有字符串*/
  0x80,         /*bmAttributes: bus ext-powered and not Support Remote Wake-up D7保留必须为1 D6为0不是自供电 D5为0不支持远程唤醒 D4-D0保留设置为0*/
  0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus 设备需要获取的电流值 单位2mA*/
  
  /****************接口描述符****************/
  /************** Descriptor of Custom device interface ****************/
  0x09,         /* bLength 描述符长度*/
  USB_DESC_TYPE_INTERFACE,/* bDescriptorType 描述符类型 接口描述符为0x04 */
  0x00,         /* bInterfaceNumber 接口的编号 从0开始 多个接口时接口编号应不一样 */
  0x00,         /* bAlternateSetting 接口备用编号 很少使用 一般为0 */
  0x02,         /* bNumEndpoints 使用的端点数(不包含端点0) */
  0x03,         /* bInterfaceClass: HID 接口使用的类 HID类为0x03*/
  0x00,         /* bInterfaceSubClass : 1=BOOT, 0=no boot 接口使用的子类 */
  0x00,         /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse 接口使用的协议 */
  0x00,         /* iInterface 接口描述字符串索引值 0表示没有字符串*/
  
  /****************HID描述符****************/
  /************** Descriptor of HID ************************************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size 描述符长度*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID 描述符类型 HID描述符为0x21*/
  0x11,         /*bcdHID: HID Class Spec release number HID使用的协议版本 1.11 */
  0x01,
  0x00,         /*bCountryCode: Hardware target country 设备适应的国家*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow 下级 HID描述符 的数量(可以是报告描述符也可以是物理描述符,但是至少有一个报告描述符,我们这个只有一个就是下面的鼠标报告描述符数组)*/
  0x22,         /*bDescriptorType 下级描述符类型 0x22代表报告描述符*/
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor 下级描述符的长度 注意大小为2个字节,所以后面有个0x00*/
  0x00,


#if 0	//此为工程模板的鼠标配置 因为我们自己写了一个所以这个我们可以不用管了,放在这参考,可供和上面的比对
  /************** Descriptor of Joystick Mouse 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: HID*/
  0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/

  /******************** Descriptor of Joystick Mouse HID ********************/
  /* 18 */
  0x09,         /*bLength: HID Descriptor size*/
  HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
  0x11,         /*bcdHID: HID Class Spec release number*/
  0x01,
  0x00,         /*bCountryCode: Hardware target country*/
  0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
  0x22,         /*bDescriptorType*/
  HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
  0x00,
#endif

  /****************端点描述符****************/
  /******************** Descriptor of Mouse endpoint ********************/
  /* 27 输入端点描述符*/ 
  0x07,          /*bLength: Endpoint Descriptor size 描述符的长度*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType: 描述符的类型 端点描述符为0x05*/
  HID_EPIN_ADDR,     /*bEndpointAddress: Endpoint Address (IN) 端点地址 D7为端点传输方向,1输入0输出 D3-D0为端点号 D6-D4保留*/
  0x03,          /*bmAttributes: Interrupt endpoint 端点属性 此处为中断传输*/
  HID_EPIN_SIZE, /*wMaxPacketSize:   端点支持的最大包长大小 长度2个字节*/
  0x00,
  HID_FS_BINTERVAL,          /*bInterval: Polling Interval 对于中断传输表示端点的查询时间,其他传输请参考协议*/
  
  /* 34 输出端点描述符*/
  0x07,          /*bLength: Endpoint Descriptor size描述符的长度 */
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:描述符的类型 端点描述符为0x05*/
  HID_EPOUT_ADDR,  /*bEndpointAddress: Endpoint Address (OUT)端点地址 D7为端点传输方向,1输入0输出 D3-D0为端点号 D6-D4保留 */
  0x03,          /*bmAttributes: Interrupt endpoint端点属性 此处为中断传输*/
  HID_EPIN_SIZE, /*wMaxPacketSize:  端点支持的最大包长大小 长度2个字节*/
  0x00,
  HID_FS_BINTERVAL,          /*bInterval: Polling Interval对于中断传输表示端点的查询时间,其他传输请参考协议 */
};


//USB 鼠标报告描述符
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
    /* note: use "HID Descriptor Tool" */

#if 0	//自定义输入设备 只具有一个输入端口
    /* Raw Data -----------------------------Item Tag(value)------------------------------------ */

	0x05, 0x0C,                           /* Usage Page (Consumer Devices)    */

	0x09, 0x01,                           /* Usage (Consumer Control)         */

	0xA1, 0x01,                           /* Collection (Application)         */

	0x09, 0x01,                           /*   Usage (Consumer Control)       */

	0x15, 0x00,                           /*   Logical Minimum (0)            */

	0x25, 0xff,                           /*   Logical Maximum (-1)           */

	0x75, 0x08,                           /*   Report Size (8)                */

	0x95, 40,                             /*   Report Count (40)              */

	0x81, 0x02,                           /*   Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)  */

	0xC0                                  /* End Collection         */
#endif
	//输入输出设备 具有一个输入端口一个输出端口
    /* note: use "HID Descriptor Tool" */
    /* Raw Data -----------------------------Item Tag(value)------------------------------------ */

	0x05, 0x0C,                           /* Usage Page (Consumer Devices)      */

	0x09, 0x01,                           /* Usage (Consumer Control)           */

	0xA1, 0x01,                           /* Collection (Application)           */

	0x09, 0x01,                           /*   Usage (Consumer Control)         */

	0x15, 0x00,                           /*   Logical Minimum (0)              */

	0x25, 0xff,                           /*   Logical Maximum (-1)             */

	0x75, 0x08,                           /*   Report Size (8)                  */

	0x95, 40,                             /*   Report Count (40)                */

	0x81, 0x02,                           /*   Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) */

	0x09, 0x01,                           /*   Usage (Consumer Control)         */

	0x15, 0x00,                           /*   Logical Minimum (0)              */

	0x25, 0xff,                           /*   Logical Maximum (-1)             */

	0x75, 0x08,                           /*   Report Size (8)                  */

	0x95, 40,                             /*   Report Count (40)                */

	0x91, 0x02,                           /* Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) */

	0xC0                                  /* End Collection                     */

//  0x05,   0x01,
//	0x09,   0x02,
//	0xA1,   0x01,
//	0x09,   0x01,

//	0xA1,   0x00,
//	0x05,   0x09,
//	0x19,   0x01,
//	0x29,   0x03,

//	0x15,   0x00,
//	0x25,   0x01,
//	0x95,   0x03,
//	0x75,   0x01,

//	0x81,   0x02,
//	0x95,   0x01,
//	0x75,   0x05,
//	0x81,   0x01,

//	0x05,   0x01,
//	0x09,   0x30,
//	0x09,   0x31,
//	0x09,   0x38,

//	0x15,   0x81,
//	0x25,   0x7F,
//	0x75,   0x08,
//	0x95,   0x03,

//	0x81,   0x06,
//	0xC0,   0x09,
//	0x3c,   0x05,
//	0xff,   0x09,

//	0x01,   0x15,
//	0x00,   0x25,
//	0x01,   0x75,
//	0x01,   0x95,

//	0x02,   0xb1,
//	0x22,   0x75,
//	0x06,   0x95,
//	0x01,   0xb1,

//	0x01,   0xc0
};

特别注意有两个申明需要修改!

/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ]  __ALIGN_END =
{
	...
}

数组中配置 的时候使用的

#define HID_EPIN_ADDR                 0x81U
#define HID_EPOUT_ADDR                0x01U
#define HID_EPIN_SIZE                 64//0x05U		/* 最大的包数据大小 */

#define USB_HID_CONFIG_DESC_SIZ       41U//34U		/*usb配置描述符的大小*/
#define USB_HID_DESC_SIZ              9U
#define HID_MOUSE_REPORT_DESC_SIZE    31U//19U//74U

USB_HID_CONFIG_DESC_SIZ用来描述usb配置描述符的大小
HID_EPIN_SIZE用来设置最大的包数据大小,特别特别注意这个,这个是用来设置端点支持的最大包长度,当我们想要设置我们一次传输的数据量有多少时,首先需要设置HID_EPIN_SIZE的大小大于*最大的一包数据的长度,然后在HID描述符中配置端点的数据大小。*

修改完配置描述符之后,还需要制作我们特定的HID报告描述符

//USB 鼠标端口描述符
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
	...
}

函数名可以不改,修改函数内部值即可,但是内部的数据怎么来呢?
这个就需要借助其他工具了,一般都是使用HID Descriptor Tool来自动生成,
软件怎么使用,大家网上查查吧,或者参考B站上的这个视频
HID怎么使用B站上的链接
,怎么配可以参考下面的照片

在这里插入图片描述
下面是我的配置
在这里插入图片描述
特别注意那个report_count的值,一定要小于我们前面说的那个HID_EPIN_SIZE
至此,我们自定义的HID设备就打造完成了,然后大家可以在main.c调用发送函数,然后把设备接在电脑上,电脑上安装一个USBlyzer监视下数据,如下所示
在这里插入图片描述
我这只发了四个数据,当然发多个数据肯定是没问题的了

设备描述符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置描述符

在这里插入图片描述
在这里插入图片描述

接口描述符

在这里插入图片描述

HID描述符(不是HID报告描述符)

在这里插入图片描述

端点描述符

在这里插入图片描述

HID报告描述符

使用HID Descriptor Tool来自动生成
参考

在这里插入图片描述
下面是我的配置
在这里插入图片描述

  • 16
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
STM32F070F6是一款STMicroelectronics的单片机芯片,支持USB自定义HID功能。 USB自定义HID(Human Interface Device)是一种USB设备类别,可以用于实现与计算机主机的交互功能。在STM32F070F6中,可以通过使用USB接口和相应的软件库来实现USB自定义HID功能。 使用USB自定义HID功能,可以将STM32F070F6作为一个外部设备连接到计算机上,并且可以通过编程来实现与计算机的双向通信。通过定义自己的报告描述符,可以实现在计算机上模拟各种输入设备,如鼠标、键盘、游戏手柄等。同时,STM32F070F6还可以接收来自计算机的命令和数据,并进行相应的操作。 在编程方面,可以使用STM32Cube软件包来快速开发应用程序。该软件包提供了针对STM32系列单片机的USB库函数,可以方便地实现USB自定义HID功能。通过配置引脚、中断和USB相关寄存器,可以初始化USB接口并设置报告描述符。然后可以利用库函数来发送和接收数据。 需要注意的是,在使用USB自定义HID功能时,需要考虑USB协议的遵循和报告描述符的定义。同时,还需要了解USB传输的相关知识,例如端点(Endpoint)、传输类型等。这些知识可以帮助开发者更好地掌握和运用STM32F070F6的USB自定义HID功能。 总之,STM32F070F6支持USB自定义HID功能,可以通过软件库和相关配置实现与计算机的交互。这为开发者提供了一种灵活和方便的方式来创建各种USB外设应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱出名的狗腿子

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值