STM32USB设备设计步骤: 申明:文章为原创性文章,转载请申明!!!
本文不对USB协议进行讲述,对于usb协议,我建议大家静下心好好去看下对应的资料,USB协议不是一个简单的协议,不是一两天就能弄透彻的!对usb协议零基础者,建议大家可以看《圈圈教你玩USB》这本书的前面一部分将USB协议的,去网上搜能搜到电子版的!
1. 使用CubeMX生成一个HID工程(注意不是Custom HID),默认生成的为模拟鼠标工程,我们需要在此基础上修改成我们自己的HID设备。 Cubemx配置步骤:
- System Core->RCC->High Speed Clock: Crystal/Ceramic Resonator
- System Core->SYS: Serial Wire
- Connectivity->USB_OTG_FS->Mode: Device_Only
- Middleware->USB_DEVICE->Class For FS IP: Human Interface Device Class (HID)
- 然后设置下System Core->NVIC中的USB OTG FS global interrupt 优先级
- 再配置时钟 确保USB时钟为48MHZ即可
- 之后可以生成代码了
至此,模板已经建立完成!!!!
#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 manufacturerstring*/
USBD_IDX_PRODUCT_STR,/*Index of product string*/
USBD_IDX_SERIAL_STR,/*Index of serial number string*/
USBD_MAX_NUM_CONFIGURATION/*bNumConfigurations*/
};
上面数组中使用到了的宏定义
#defineUSB_DESC_TYPE_DEVICE0x01U
#define USB_MAX_EP0_SIZE64U
#define USBD_VID1155
#define USBD_LANGID_STRING1033
#define USBD_MANUFACTURER_STRING"STMicroelectronics"
#define USBD_PID_FS22315
#define USBD_PRODUCT_STRING_FS"STM32 Human interface"
#define USBD_CONFIGURATION_STRING_FS"HID Config"
#define USBD_INTERFACE_STRING_FS"HID Interface"
#defineUSBD_IDX_MFC_STR0x01U
#defineUSBD_IDX_PRODUCT_STR0x02U
#defineUSBD_IDX_SERIAL_STR0x03U
【嵌入式开发|使用stm32配置自定义的HID设备】我们一般修改usb设备的厂家ID,也就是对应的USBD_VID为0xff,0xff应该没有哪个厂家申请吧
#define USBD_VID0xFF
厂家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_ADDR0x81U
#define HID_EPOUT_ADDR0x01U
#define HID_EPIN_SIZE64//0x05U/* 最大的包数据大小 */#define USB_HID_CONFIG_DESC_SIZ41U//34U/*usb配置描述符的大小*/
#define USB_HID_DESC_SIZ9U
#define HID_MOUSE_REPORT_DESC_SIZE31U//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来自动生成
参考
文章图片
下面是我的配置
文章图片
推荐阅读
- 嵌入式开发|一款简单好用的日志系统
- 11|【嵌入式--伺服电机】足式机器人 外转子无刷电机研究
- 嵌入式开发|STM32HAL库串口接收中断HAL_UART_Receive_IT()配置失效
- fpga开发|博客更新计划的说明
- 嵌入式开发|键盘驱动程序的修改
- 设备驱动|设备驱动开篇
- STM32F1【标准库开发】|STM32F103ZET6【标准库函数开发】------05.通用定时器TIM4四个通道输出占空比、频率可调的PWM信号
- 单片机|基于单片机的通用定时器调度器SmartTimer
- STM32笔记|(十二)STM32——NVIC中断优先级管理