STM32 USB使用记录:HID类设备(前篇)
文章目录
- 目的
- 基础说明
- HID类演示
- 代码分析
- 总结
目的
USB是目前最流行的接口,现在很多个人用的电子设备也都是USB设备。目前大多数单片机都有USB接口,使用USB接口作为HID类设备来使用是非常常用的,比如USB鼠标、键盘都是这一类。这篇文章将简单介绍使用STM32实现相关内容。
基础说明
一些USB相关最基础的内容可以参考下面文章中 基础说明 部分:
《STM32 USB使用记录:使用CDC类虚拟串口(VCP)进行通讯》
USB设备通过一系列的描述符来描述自己,告诉主机自己是什么设备、具有什么功能等。描述符一些基本的说明如下:
- 每一个USB设备只有一个设备描述符,主要向主机说明设备类型、端点0最大包长、设备版本、配置数量等等;
- 每一个USB设备至少有一个或者多个配置描述符,但是主机同一时间只能选择某一种配置,标准配置描述符主要向主机描述当前配置下的设备属性、所需电流、支持的接口数、配置描述符集合长度等等;
- 主机在获取配置描述符集合的时候会先获取一次标准配置描述符,然后根据里面的配置描述符集合长度属性值获取配置描述符集合的所有描述符信息,配置描述符集合有标准配置描述符、接口描述符、端点描述符、HID描述符;
- 每一个USB配置下至少有一个或者多个接口描述符,接口描述符主要说明设备类型、此接口下使用的端点数(不包括0号号端点),一个接口就是实现一种功能,实现这种功能可能需要端点0就够了,可能还需要其它的端点配合;
- 每一个USB接口下至少有0个或者多个端点描述符,端点描述符用来描述符端点的各种属性;
- 端点是实现USB设备功能的物理缓冲区实体,USB主机和设备是通过端点进行数据交互的;
- 一个USB设备有一个或多个配置描述符。每个配置有一个或多个接口,每个接口有零个或多个端点;
- 字符串描述符就是用字符串描述一个设备的一些属性,描述的属性包括设备厂商名字、产品名字、产品序列号、各个配置名字、各个接口名字;
- HID描述符只有HID设备才会存在;
- HID设备至少有一个报告描述符;
- 报告描述符主要作用就是描述主机和HID设备交互的数据,向主机说明这些数据中哪些位是用来做什么用的;

HID类演示
使用 STM32CubeIDE 或者 STM32CubeMX 可以方便的建立 STM32 USB HID 的项目。这里直接进行配置演示,图中只列出最关键的内容。
启用USB接口:

启用USB设备中间件:

需要注意的是根据H750芯片数据手册中说明,这里USB时钟推荐使用48MHz,如果是使用 USB HS 外接PHY的话,时钟使用60MHz:


上面配置下默认生成的是 鼠标设备 在生产的代码中的 main.c 中添加几行代码即可测试效果:
int main(void)
{HAL_Init();MPU_Config();SystemClock_Config();MX_GPIO_Init();MX_USB_DEVICE_Init();// 默认配置生成的鼠标设备每次向电脑发送四个字节数据,这些内容是在HID设备的报告描述符中定义的// buff[0] bit0 bit1 bit2 分别代表 左键、右键、中键// buff[1] X 轴位移 (-127~127)// buff[2] Y 轴位移 (-127~127)// buff[3] Wheel 滚轮 (-127~127)uint8_t buff[4] = {0, 10, 0 ,0}; // X轴设置了位移量while (1){extern uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);extern USBD_HandleTypeDef hUsbDeviceFS;USBD_HID_SendReport(&hUsbDeviceFS, buff, 4); // 发送数据HAL_Delay(1000); // 按照buff中的值,每秒电脑上的光标将向右移动一次}
}

记住上图左边几个文件,后面会介绍其中一些内容。
编译程序下载到芯片中就可以查看效果了,每隔一秒光标会向右移动一次。
可以使用 USB Device Tree Viewer 工具来查看电脑上的USB设备:
https://www.uwe-sieber.de/usbtreeview_e.html

代码分析
这里只是简单做个介绍。
首先是 main.c 中执行的 MX_USB_DEVICE_Init() 函数,该函数在 usb_device.c 文件中,函数内容如下:
void MX_USB_DEVICE_Init(void)
{// 初始化USB设备USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) // 初始化USB设备具体类型(这里是HID设备)USBD_RegisterClass(&hUsbDeviceFS, &USBD_HID) // 启动USBUSBD_Start(&hUsbDeviceFS)
}
FS_Desc 结构体在 usbd_desc.c 文件中定义,看名字就可以了解是前面基础说明中提到的各种描述符:
USBD_DescriptorsTypeDef FS_Desc =
{USBD_FS_DeviceDescriptor
, USBD_FS_LangIDStrDescriptor
, USBD_FS_ManufacturerStrDescriptor
, USBD_FS_ProductStrDescriptor
, USBD_FS_SerialStrDescriptor
, USBD_FS_ConfigStrDescriptor
, USBD_FS_InterfaceStrDescriptor
};
USBD_HID 结构体的相关内容主要都在 usbd_hid.h / usbd_hid.c 文件中,这两个文件就是库中默认的HID鼠标设备了,其中有HID描述符和报告描述符等。
这里的配置描述符描述设备为HID的鼠标、设备电流、输入输出端点等:
/* USB HID device FS Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{0x09, /* bLength: Configuration Descriptor size */USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */USB_HID_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */0x00,0x01, /* bNumInterfaces: 1 interface */0x01, /* bConfigurationValue: Configuration value */0x00, /* iConfiguration: Index of string descriptordescribing the configuration */
#if (USBD_SELF_POWERED == 1U)0xE0, /* bmAttributes: Bus Powered according to user configuration */
#else0xA0, /* bmAttributes: Bus Powered according to user configuration */
#endif /* USBD_SELF_POWERED */USBD_MAX_POWER, /* MaxPower (mA) *//************** 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 */0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */0x02, /* 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,/******************** Descriptor of Mouse endpoint ********************//* 27 */0x07, /* bLength: Endpoint Descriptor size */USB_DESC_TYPE_ENDPOINT, /* bDescriptorType:*/HID_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */0x03, /* bmAttributes: Interrupt endpoint */HID_EPIN_SIZE, /* wMaxPacketSize: 4 Bytes max */0x00,HID_FS_BINTERVAL, /* bInterval: Polling Interval *//* 34 */
};
报告描述符就描述了设备收发数据结构信息等内容:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */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 (0x01) */0x29, 0x03, /* Usage Maximum (0x03) */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, 0x01, /* Input (Const,Array,Abs) */0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */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 */0x09, 0x3C, /* Usage (Motion Wakeup) */0x05, 0xFF, /* Usage Page (Reserved 0xFF) */0x09, 0x01, /* Usage (0x01) */0x15, 0x00, /* Logical Minimum (0) */0x25, 0x01, /* Logical Maximum (1) */0x75, 0x01, /* Report Size (1) */0x95, 0x02, /* Report Count (2) */0xB1, 0x22, /* Feature (Data,Var,Abs,NoWrp) */0x75, 0x06, /* Report Size (6) */0x95, 0x01, /* Report Count (1) */0xB1, 0x01, /* Feature (Const,Array,Abs,NoWrp) */0xC0 /* End Collection */
};
总结
这篇文章到这里先告一段落了,看似什么都没讲,因为这篇文章的目的是对 HID 整体有个印象。大部分时候实际开发中我们并不会去使用默认的鼠标类型HID设备,而是使用自定义的HID设备(Custom Human Interface Device Class)。而自定义设备中像是报告描述符等一些内容需要自行编辑,用来实现特定功能需求,比如HID设备用作双向透传等。这些内容将在下一篇文章中进行介绍。
相关文章:
STM32 USB使用记录:HID类设备(前篇)
文章目录 目的基础说明HID类演示代码分析总结 目的 USB是目前最流行的接口,现在很多个人用的电子设备也都是USB设备。目前大多数单片机都有USB接口,使用USB接口作为HID类设备来使用是非常常用的,比如USB鼠标、键盘都是这一类。这篇文章将简单…...
探索AI图像安全,助力可信AI发展
探索AI图像安全,助力可信AI发展 0. 前言1. 人工智能发展与安全挑战1.1 人工智能及其发展1.2 人工智能安全挑战 2. WAIC 2023 多模态基础大模型的可信 AI2.1 WAIC 2023 专题论坛2.2 走进合合信息 3. AI 图像安全3.1 图像篡改检测3.2 生成式图像鉴别3.3 OCR 对抗攻击技…...
vue 学习笔记 【ElementPlus】el-menu 折叠后图标不见了
项目当前版本 {"dependencies": {"element-plus/icons-vue": "^2.1.0","types/js-cookie": "^3.0.3","types/nprogress": "^0.2.0","axios": "^1.4.0","core-js": &quo…...
【JavaEE初阶】HTTP协议
文章目录 1. HTTP概述和fiddler的使用1.1 HTTP是什么1.2 抓包工具fiddler的使用1.2.1 注意事项1.2.2 fiddler的使用 2. HTTP协议格式2.1 HTTP请求格式2.1.1 基本格式2.1.2 认识URL2.1.3 方法 2.2 请求报头关键字段2.3 HTTP响应格式2.3.1 基本格式2.3.2状态码 1. HTTP概述和fidd…...
基于SaaS模式的Java基层卫生健康云HIS系统源码【运维管理+运营管理+综合监管】
云HIS综合管理平台 一、模板管理 模板分为两种:病历模板和报表模板。模板管理是运营管理的核心组成部分,是基层卫生健康云中各医疗机构定制电子病历和报表的地方,各医疗机构可根据自身特点特色定制电子病历和报表,制作的电子病历…...
effective c++ 条款2
条款2 常量(const)替换宏(#define)指针常量类成员常量 枚举(enum)替换宏(#define)模板函数(template inline)替换宏函数 尽量用const,enum,inline替换#define 总结就是: 常量(const)替换宏(#define) // uppercase names are usually for macros #define ASPECT_R…...
Python爬虫之Scrapy框架系列(23)——分布式爬虫scrapy_redis浅实战【XXTop250部分爬取】
目录: 1.实战讲解(XXTop250完整信息的爬取):1.1 使用之前做的完整的XXTOP250项目,但是设置为只爬取一页(共25个电影),便于观察1.2 配置settings文件中使用scrapy_redis的必要配置,并…...
html基于onmouse事件让元素变颜色
最近,在书写div块时,遇到一个小问题,这个小问题我搞了将近一个小时多才慢慢解决。问题是这样子的,有一个div块,我想让鼠标移上去变成蓝色,移开变成灰色,当鼠标按下去时让他变成深蓝色。于是就单…...
Linux环境PostgreSQL安装
今日一语:鲲鹏扶摇而直上九万里,雄鹰展翅高飞,这是因为鲲鹏一出世就得历劫,老鹰刚长出翅膀就会被扔下悬崖 下载安装包,解压到服务器中,然后 make && make install # 登录使用 ./psql # 切换数据库…...
Rust 数据类型 之 结构体(Struct)
目录 结构体(Struct) 定义与声明 结构体定义 结构体实例 结构体分类 单元结构体(Unit Struct) 元组结构体(Tuple Struct) 具名结构体(Named Struct) 结构体嵌套 结构体方法…...
数据结构之Queue的实现
Queue支持的方法 方法名参数功能返回Sizevoid返回链表规模(该方法由List< T>派生而来)emptyvoid返回链表是否为空(该方法由List< T>派生而来)frontvoid返回队首数据域的引用enqueueT const & e入队voiddequeuevoid出队出队的对象 code // Queue.h # pragma …...
rust声明式宏
宏 在 rust 中,我们一开始就在使用宏,例如 println!, vec!, assert_eq! 等。看起来宏和函数在使用时只是多了一个 !。实际上这些宏都是声明式宏(也叫示例宏或macro_rules!),rust 还支持过程宏,过程宏为我们…...
第二章:Learning Deep Features for Discriminative Localization ——学习用于判别定位的深度特征
0.摘要 在这项工作中,我们重新审视了在[13]中提出的全局平均池化层,并阐明了它如何明确地使卷积神经网络(CNN)具有出色的定位能力,尽管它是在图像级别标签上进行训练的。虽然这个技术之前被提出作为一种训练规范化的手…...
【CSS】box-shadow 属性
box-shadow 是 CSS 属性,用于为元素添加一个阴影效果,使元素看起来浮起或有层次感。 该属性允许设置一个或多个阴影效果,其语法如下: box-shadow: h-shadow v-shadow blur spread color inset;h-shadow:水平阴影的位…...
基于深度学习的高精度课堂人脸检测系统(PyTorch+Pyside6+YOLOv5模型)
摘要:基于深度学习的高精度课堂人脸检测系统可用于日常生活中或野外来检测与定位课堂人脸目标,利用深度学习算法可实现图片、视频、摄像头等方式的课堂人脸目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标…...
Mysql错误日志、通用查询日志、二进制日志和慢日志的介绍和查看
一.日志 1.日志和备份的必要性 日志刷新 2.mysql的日志类型 (1)错误日志 查看当前错误日志和是否记录警告设置 (2)通用查询日志 查看通用查询日志的设置 (3)二进制日志 查看二进制文件的设置&…...
【Linux】Tcp服务器的三种与客户端通信方法及守护进程化
全是干货~ 文章目录 前言一、多进程版二、多线程版三、线程池版四、Tcp服务器日志的改进五、将Tcp服务器守护进程化总结 前言 在上一篇文章中,我们实现了Tcp服务器,但是为了演示多进程和多线程的效果,我们将服务器与客户通通信写成了一下死循…...
【Spring Cloud】git 仓库新的配置是如何刷新到各个微服务的原理步骤
文章目录 1. 第一次启动时2. 后续直接在 git 修改配置时3. 参考资料 本文描述了在 git 仓库修改了配置之后,新的配置是如何刷新到各个微服务的步骤 前言: 1、假设现有有 3 个微服务,1 个是 配置中心,另外 2 个是普通微服务&#x…...
三,创建订单微服务消费者 第三章
4.3 修改pom添加依赖 <dependencies><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--监控--><dependency><groupId&g…...
【雕爷学编程】Arduino动手做(87)---ULN2003步进电机模组2
37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
