一、USB简介

USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。

USB 发展到现在已经有 USB1.0/1.1/2.0/3.0 等多个版本。目前用的最多的就是 USB1.1 和 USB2.0,USB3.0 目前已经开始普及。STM32F103 自带的 USB 符合 USB2.0 规范,不过 STM32F103 的 USB 都只能用来做设备,而不能用作主机。

标准 USB 共四根线组成,除 VCC/GND 外,另外为 D+,D-; 这两根数据线采用的是差分电压的方式进行数据传输的。在 USB 主机上,D-和 D+都是接了 15K 的电阻到低的,所以在没有设备接入的时候,D+、D-均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+上接一个 1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。

STM32F103 的 MCU 自带 USB 从控制器,符合 USB 规范的通信连接;PC 主机和微控制器之间的数据传输是通过共享一专用的数据缓冲区来完成的,该数据缓冲区能被 USB 外设直接访问。这块专用数据缓冲区的大小由所使用的端点数目和每个端点最大的数据分组大小所决定,每个端点最大可使用 512 字节缓冲区(专用的 512 字节,和 CAN 共用),最多可用于 16 个单向或 8 个双向端点。USB 模块同 PC 主机通信,根据 USB 规范实现令牌分组的检测,数据发送/接收的处理,和握手分组的处理。整个传输的格式由硬件完成,其中包括 CRC 的生成和校验。

1.1 USB HID简介

USB HID类是USB设备的一个标准设备类,包括的设备非常多。HID类设备定义它属于人机交互操作的设备,用于控制计算机操作的一些方面,如USB鼠标、USB键盘、USB游戏操纵杆等。但HID设备类不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。

USB HID设备的一个好处就是操作系统自带了HID类的驱动程序,而用户无需去开发驱动程序,只要使用API系统调用即可完成通信。

官方资料:http://www.usb.org/developers/hidpage
其中包含最主要的两个说明:

  • 《Device Class Definition for human interface device (HID)》【描述了 HID 的基本组成和格式】
  • 《Universal Serial Bus HID Usage Tables》【对上面文档的补充,将各种不同的 HID 设备的基本组成列举出来】

二、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”

2. 选择 MCU 和封装

3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置

4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire

三、USB

3.1 参数配置

Connectivity 中选择 USB 设置,并勾选 Device(FS) 激活 USB 设备。

Parameter Settings 进行具体参数配置。

  • Speed: Full Speed 12MBit/s(固定为全速)
  • Low Power: 默认 Disabled(在任何不需要使用usb模块的时候,通过写控制寄存器总可以使usb模块置于低功耗模式(low power mode ,suspend模式)。在这种模式下,不产生任何静态电流消耗,同时usb时钟也会减慢或停止。通过对usb线上数据传输的检测,可以在低功耗模式下唤醒usb模块。也可以将一特定的中断输入源直接连接到唤醒引脚上,以使系统能立即恢复正常的时钟系统,并支持直接启动或停止时钟系统。)

3.2 引脚配置

USB 的 DP 引脚必须上拉 1.5K 欧的电阻,电脑才能检测到 USB,否则检测不到。

查看野火指南者开发板原理图可知,需要将 PD6 配置为低电平使能 USB。

在右边图中找到 PD6 引脚,选择 GPIO_Output

GPIO output level 中选择 Low 输出低电平。

3.3 配置时钟

选择 Clock Configuration,USB 时钟配置为 48MHz,且来源最好是外部晶振分频得到。

3.4 USB Device

USB有主机(Host)和设备(Device)之分。一般电脑的USB接口为主机接口,而键盘、鼠标、U盘等则为设备。

部分型号的STM32芯片有1~2个USB接口。像STM32F103系列的有一个USB Device接口,STM32F407系列的有2个USB接口,既可以作为HOST,又可以作为Device,还可以作为OTG接口。

Middleware 中选择 USB_DEVICE 设置,在 Class For FS IP 设备类别选择 Human Interface Device Class(HID) 人机接口设备。

参数配置保持默认。

  • HID_FS_BINTERVAL(主机读取设备数据时间间隔): 0xA(STM32将数据发送到一个缓存区,而不是直接发送到上位机,而上位机每隔一端时间会来访问缓冲区读取数据。读取时间间隔过快会导致多次数据发送,过慢会导致数据丢失)
  • USBD_MAX_NUM_INTERFACES (Maximum number of supported interfaces)(最大支持HID设备的接口数): 1(应为现在只有键盘,所以1就行,如果是需要同时键盘,鼠标,手柄啥的,根据数量选择即可)

设备描述符保持默认。

四、添加按键

4.1 GPIO配置

System Core 中选择 GPIO 设置。

在右边图中找到按键对应引脚,选择 GPIO_Input

五、生成代码

输入项目名和项目路径

选择应用的 IDE 开发环境 MDK-ARM V5

每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。

点击 GENERATE CODE 生成代码

六、修改usbd_hid.c

打开工程文件夹Middlewares/USB_Device_Libraryusbd_hid.c文件

6.1 修改接口描述符(可跳过)

HID设备的描述符除了**5个USB的标准描述符(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符)**外,还包括三个HID设备类特定的描述符:HID描述符报告描述符(Report)、实体描述符(Physical)

他们之间的层次关系如图:

打开usbd_hid.c文件,找到USBD_HID_CfgFSDesc配置全速描述符数组定义处。

  • 配置描述符
    bNumInterfaces表示这个设备有多少个接口。
    MaxPower 100 mA表示这个设备需要从总线上获取100mA电流。
/* 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 */USB_HID_CONFIG_DESC_SIZ,/* wTotalLength: Bytes returned */0x00,0x01,         /*bNumInterfaces: 1 interface*/0x01,         /*bConfigurationValue: Configuration value*/0x00,         /*iConfiguration: Index of string descriptor describingthe configuration*/0xE0,         /*bmAttributes: bus powered and Support Remote Wake-up */0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
  • 接口描述符
    bInterfaceClass的值必须是 0x03
    bInterfaceSubClass的值为 0 或 1, 为1表示HID设备是一个启动设备(BootDevice, 一般对PC机有意义,意思是BIOS启动时能识别您使用的HID设备,切只有标准鼠标或者键盘才能称为BootDevice),为0表示HID设备是操作系统启动厚才能识别使用的设备。
  /************** 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*/

这里我们将bInterfaceProtocol的值改为1:(0 — NONE,1 — Keyboard(键盘),2 — Mouse (鼠标),3~255 Reserved)

  • HID描述符
    HID描述符关联于接口描述符,因而如果一个设备只有一个接口描述符,则无论它有几个端点描述符,HID设备只有一个HID描述符。HID设备描述符主要描述HID规范的版本号, HID通信所使用的额外描述符,报告描述符的长度等。
  /******************** 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,

下表为HID描述符的结构。

偏移量 大小(Byte) 描述
0 bLength 1 数字 此描述符的长度,以字节为单位
1 bDescriptorType 1 常量 描述符种类(此处 0x21为HID类)
2 bcdHID 2 数字 HID规范版本号(BCD码),采用4个16进制的BCD格式编码
4 bCountryCode 1 数字 硬件目的国家的识别码
5 bNumDescriptors 1 数字 支持的附属描述符数目
6 bDescriptorType 1 常量 0x21-HID描述符,0x22-报告描述符,0x23-实体描述符
7 wDescriptorLength 2 数字 报告描述符的总长度
9 bDescriptorType 1 常量 用于识别描述符类型的常量,使用有一个以上描述符的设备
10 wDescriptorLength 2 数字 描述符总长度,使用在有一个以上描述符的设备
  • 端点描述符
    bEndpointAddress表示端点地址,表示当前这个接口所需要的端点资源,输入(相对于主机而言)端点最高位为1,输出(相对于主机而言)端点最高位为0。HID设备一般都是使用中断端点进行数据传输。
    wMaxPacketSize表示该端点上数据传输的数量。
    bInterval表示主机查询设备数据的时间间隔,如果设置的太长,则键盘输入延迟很高。
  /******************** 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 Byte max */0x00,HID_FS_BINTERVAL,          /*bInterval: Polling Interval *//* 34 */
};

6.2 修改报告描述符

下载 HID Descriptor Tool (DT) HID描述符工具:
官网下载:https://usb.org/sites/default/files/documents/dt2_4.zip
百度网盘:https://pan.baidu.com/s/1ayjdQtc7e9NWwYJqdp0pXA?pwd=4ghb 提取码:4ghb

打开 File——》Open...——》keybrd.hid

我们可以看到HID键盘的描述符情况:

打开usbd_hid.c文件,找到HID_MOUSE_ReportDesc数组定义处(默认生产HID设备为Mouse,这里数组名不影响,只要里面的描述符是键盘的就行)。

 0x05, 0x01, // USAGE_PAGE (Generic Desktop) //630x09, 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, 0x65, // LOGICAL_MAXIMUM (101)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)0xc0, // END_COLLECTION

6.3 修改报告描述符大小

打开usbd_hid.h文件,修改HID_MOUSE_REPORT_DESC_SIZE的值为63

七、修改main.c

添加头文件和USB设备句柄。

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usbd_hid.h"
/* USER CODE END Includes *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
extern USBD_HandleTypeDef hUsbDeviceFS;

添加一个数组变量,用于传输键盘参数的,Byte0是传控制键Byte1是保留键,不用改;Byte3~byte7都可以存放传输的按键值

/* USER CODE BEGIN PV */
/** buffer[0] - bit0: Left CTRL*           -bit1: Left SHIFT*           -bit2: Left ALT*           -bit3: Left GUI*           -bit4: Right CTRL*           -bit5: Right SHIFT*           -bit6: Right ALT*           -bit7: Right GUI * buffer[1] - Padding = Always 0x00* buffer[2] - Key 1* buffer[3] - Key 2* buffer[4] - Key 3* buffer[5] - Key 4* buffer[6] - Key 5* buffer[7] - Key 6*/
uint8_t buffer[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* USER CODE END PV */

添加按键检测及传输键值到电脑。

/*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USB_DEVICE_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//    usb_printf("\r\n****** USB-HID Keyboard Example ******\r\n\r\n");if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0){  buffer[0] = 0x02; //shiftbuffer[2] = 0x04; //aUSBD_HID_SendReport(&hUsbDeviceFS, buffer, 8); //sendHAL_Delay(15); //delaybuffer[0] = 0x00;buffer[2] = 0x00;USBD_HID_SendReport(&hUsbDeviceFS, buffer, 8);HAL_Delay(15);while(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0)HAL_Delay(15);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}


对应键值可和此文件中的HID Usage ID对应,是16进制(如字符‘a’对应键值为0x04)
USB_HIDtoKBScanCodeTranslationTable.pdf

八、查看效果

编译工程,下载到板子上,插上USB线连接到电脑上,识别出为键盘设备

注意: 如果设备带有感叹号,则参考下面十、注意事项

按下按键时在电脑上输入一个大写的‘A’。

九、工程代码

链接:https://pan.baidu.com/s/1E7wwefhBNgCRKX1tgG0kxA?pwd=agm4 提取码:agm4

十、注意事项

用户代码要加在 USER CODE BEGIN NUSER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。

如果USB端口出现感叹号设备无法启动的问题,可适当将堆改大,如0x400


• 由 Leung 写于 2022 年 10 月 26 日

• 参考:STM32F042F6P6-USB设备开发最小系统之键盘示例
    USB 协议分析之 HID 设备
    关于STM32的USB设备库DIY机械键盘
    STM32-USB学习系列(六):USB-HID键盘的实现以及键盘报文描述符的简介
    DIY一个usb数字键盘(一) 基于stm32cubemx HAL库 usb hid协议
    DIY一个usb数字键盘(二)逻辑部分 基于stm32cubemx HAL库 usb hid协议
    STM32 基础系列教程 24 - USB_HID_key

STM32CubeMX学习笔记(44)——USB接口使用(HID按键)相关推荐

  1. STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)

    一.电容按键简介 电容器(简称为电容)就是可以容纳电荷的器件,两个金属块中间隔一层绝缘体就可以构成一个最简单的电容.如图 32-1(俯视图),有两个金属片,之间有一个绝缘介质,这样就构成了一个电容.这 ...

  2. STM32CubeMX学习笔记(38)——FSMC接口使用(TFT-LCD屏显示)

    一.TFT-LCD简介 TFT-LCD(Thin Film Transistor-Liquid Crystal Display) 即薄膜晶体管液晶显示器.TFT-LCD 与无源 TN-LCD. STN ...

  3. STM32CubeMX学习笔记(9)——I2C接口使用(读写EEPROM AT24C02)

    一.I2C简介 I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线.是两条串行的总线,它由一根数据线(SDA)和一根 时钟 ...

  4. STM32CubeMX学习笔记(22)——CRC接口使用

    一.CRC简介 CRC(Cyclic Redundancy Check),即循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者 ...

  5. STM32CubeMX学习笔记(15)——电源管理(PWR)低功耗睡眠模式

    一.低功耗模式简介 系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗.由用户根据应用选择具体的低功耗模式,以在低功耗.短启动时间和可用唤醒源之间寻求最佳平衡. 睡眠模 ...

  6. STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

  7. STM32CubeMX学习笔记(16)——电源管理(PWR)低功耗停止模式

    一.低功耗模式简介 系统提供了多个低功耗模式,可在 CPU 不需要运行时(例如等待外部事件时)节省功耗.由用户根据应用选择具体的低功耗模式,以在低功耗.短启动时间和可用唤醒源之间寻求最佳平衡. 睡眠模 ...

  8. STM32CubeMX学习笔记(27)——FatFs文件系统使用(操作SD卡)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

  9. STM32CubeMX学习笔记——STM32H743_硬件I2C

    STM32CubeMX学习笔记--STM32H743_硬件I2C Github STM32CubeMX配置 Pinout配置 GPIO Clock Configuration配置 代码部分 main. ...

  10. STM32CubeMX学习笔记(28)——FreeRTOS实时操作系统使用(任务管理)

    一.FreeRTOS简介 FreeRTOS 是一个可裁剪.可剥夺型的多任务内核,而且没有任务数限制.FreeRTOS 提供了实时操作系统所需的所有功能,包括资源管理.同步.任务通信等. FreeRTO ...

最新文章

  1. CCIE实验之路由重分布之重分布的原则
  2. Linux下Poppler源码编译安装
  3. 《构架之美》阅读笔记六
  4. linux下装jdk以及failed /usr/local/jdk1.6.0_10/jre/lib/i386/client/libjvm.so,
  5. php下拉选项登录_php下拉选项的批量操作的实现代码
  6. 单纯形法求最小值的检验数_【运筹学】单纯形法(笔记和思考)
  7. seaborn绘制概率密度图
  8. php递归面包屑,php实现面包屑导航例子分享,_PHP教程
  9. vue项目部署iis后 乱码_vue项目的自动化部署
  10. HDU2019 数列有序!【入门】
  11. java版spring cloud电商源码+spring boot+redis多租户社交电子商务平台
  12. git 中怎样查看未传送(git push)到远程代码库的(git commit)提交?
  13. 硬盘IDE模式与AHCI模式的区别
  14. 自顶向下语法分析的作业
  15. 40个科研学术网站,收藏必备,予取予求!
  16. puppet的使用:ERB模板
  17. iTunes现在已在Microsoft Store中
  18. 天天学JAVA-JAVA基础(2)
  19. elf文件从原理到实现个人总结
  20. 计算机组成原理----有关数据通路

热门文章

  1. 农业动物相关数据集与算法——调研整理
  2. 更换固态,重装win10系统
  3. android 游戏语言设置在哪里设置中文版,使命召唤手游语言变更方法 怎么设置中文...
  4. Apache2 虚拟主机 详解
  5. redis恢复阿里云rdb文件
  6. java 必须是数字_[Java教程]限制只能输入数字
  7. GitLab 安全漏洞 (CVE-2016-4340)复现
  8. 教师管理系统设计报告java_Java 教师信息管理系统 简单的java课程设计范例 - 下载 - 搜珍网...
  9. java匹配任意,java有关正则表示式,我想匹配一个字串中的任意字元,怎么办?...
  10. 物联网RFID技术在高速ETC中的应用