【STM32】USB通讯方式的学习笔记以及基于CubeMX HAL库的例程验证_stm32 usb通讯
一、USB介绍
1.概述
USB(Universal Serial Bus,通用串行总线)是一种用于计算机与外部设备连接的接口技术。它凭借高速传输、热插拔支持、多设备兼容及即插即用特性,成为现代电子设备互联的核心纽带。
2.USB发展历程
- USB 1.0:1994 年,以 Intel 为首的七家公司联合研发和制定了 USB 传输协议的第一个草案。1996 年,USB1.0 标准问世,理论速率为 1.5Mbit/s,但该版本未在市场上广泛使用。
- USB 1.1:1998 年,USB-IF 发布了 USB1.1 规范,开始逐渐占据主流市场。其高速传输速率为 12Mbit/s,低速传输速率为 1.5Mbit/s,支持热插拔、同步和异步传输并内置电源 / 低压配电装置,线缆最长 5m,最多支持 127 台设备,抗干扰能力大大增强。
- USB 2.0:2000 年,USB2.0 规范出台,传输速率达到 480Mbit/s,是半双工数据传输模式,且完全向后兼容之前的 USB 版本。2001 年,USB OTG 功能发布,使特定外部设备在没有电脑的情况下可以互相通讯。2007 年,推出了 Micro-USB 接口,增加了接口的稳定性,同时 USB 充电规格(USB BC)也在同年推出。
- USB 3.0:2008 年,Intel、Microsoft、HP 等公司组成的 USB 3.0 Promoter Group 完成了 USB 3.0(SuperSpeed USB)标准的发布,传输速率达到 5.0Gbit/s,最大输出电流 900mA,兼容 USB2.0 并支持全双工数据传输。2013 年,USB 3.1(USB SuperSpeed Gen2)标准发布,传输速率达到 10Gbit/s,供电标准提高至 20V/5A 的 100W。2017 年,USB 3.2 标准发布,在 USB Type-C 下支持双 10Gbit/s 通道,速率达 20Gbit/s。
- USB4:2019 年,USB Promoter Group 发布基于雷电 3 协议开发的 USB4 协议,最大传输率达到 40Gbit/s,具备动态带宽资源分配能力并支持 USB Power Delivery 快充协议。2022 年,推出 USB4 2.0,通过 USB Type-C 接口的传输速率到达 80Gbit/s,并扩展 USB Type-C 接口性能,与 USB3.2、USB2.0 向下兼容。
3.USB的架构
USB系统架构由几个核心组件构成,包括主机控制器、集线器、以及连接的设备等。USB系统可以被视为一个树状的拓扑结构,每个USB设备都连接到一个集线器(Hub),而集线器又连接到主机控制器,进而连接到主机计算机。
(1)主机控制器(Host Controller):这是连接USB设备与计算机系统总线的桥梁。它负责管理USB总线和处理主机与USB设备之间的通信。在USB 2.0及之前的版本中,又分为EHCI(Enhanced Host Controller Interface)和OHCI(Open Host Controller Interface)。
主机(尤其是主控制器)控制着所有通信并向设备发出指令。共有三种常见的 USB 主控制器:
1)通用主控制器接口(UHCI): 由 Intel 生产,适用于 USB 1.0 和 USB 1.1。使用 UHCI 时需要得到 Intel 的许可。该控制器支持低速模式和全速模式。
2)开放主控制器接口(OHCI): 由 Compaq、 Microsoft 和 National Semiconductor 生产, 适用于 USB 1.0 和 1.1。该控制器支持低速模式和全速模式, 并且它的效率比 UHCI 更高, 因为可以执行更多硬件功能。
3)扩展型主控制器接口(EHCI): 在 USB-IF 要求发布单一主控制器规范后,已经生产了该控制器,它适用于 USB2.0。 EHCI 仅支持高速传输,并且将低速和全速传输委托给 OHCI 或 UHCI 控制器执行。
(2)集线器(Hub):集线器允许一台主机控制器连接多个USB设备。集线器可以是物理的,也可以是虚拟的(例如在芯片内部集成)。它提供了端口的数量和位置的灵活性。
(3)USB设备(Device):连接到USB端口的各种设备,如键盘、鼠标、打印机、存储设备等。
USB设备根据其功能和通用性,可以分为不同的类别,例如大容量存储设备(Mass Storage Class)、通信设备(Communication Device Class)、音频设备(Audio Device Class)、人体学接口设备(HID - Human Interface Device Class)等等。每个类设备都遵循特定的规范,以确保与不同主机的兼容性。
USB规范定义了设备必须遵守的电气、协议和机械接口的标准。USB总线提供4线连接:电源线、地线、两条数据线(D+(DP)和D-(DM))。通过这些线上的电信号和协议,USB设备能够以高效率传输数据,并且支持热插拔。
4.USB类设备的分类与实现
(一)USB类设备的定义
USB类设备定义了设备的特定功能和行为,使设备能够被操作系统识别和驱动。每个USB类都有特定的类规范,这些规范定义了设备如何响应各种USB请求以及如何与主机通信。一些常见的USB类设备包括:
(1)大容量存储设备(Mass Storage Class, MSC):如USB闪存驱动器、外部硬盘驱动器等,它们允许用户存储和传输文件。
(2)音频设备类(Audio Device Class):包括麦克风、扬声器、耳机、声卡等音频设备。
(3)通信设备类(Communication Device Class, CDC):常用于调制解调器、ISDN终端适配器、虚拟COM端口等。
(4)人体学接口设备(Human Interface Device, HID):包括键盘、鼠标、游戏控制器等与人机交互相关的设备。
(5)图像设备类(Image Device Class):数码相机、网络摄像头等图像捕捉设备。
每个类设备通过特定的设备请求和类特定的命令集来实现它们的功能。例如,MSC设备通过SCSI透明传输(Bulk-Only Transport)协议来实现数据传输,而HID设备则通过HID类规范定义的通信接口与主机进行数据交换。
(二)STM32的USB外设实现的大致步骤
STM32的USB外设库(如STM32 USB-FS-Device)提供了实现USB类设备所需的抽象层。开发者需要通过实现回调函数来处理USB标准请求,并实现设备特定的功能。以下是实现USB类设备的一般步骤:
1)配置USB硬件 :使用STM32CubeMX配置USB接口,设置时钟、中断等参数,并生成初始化代码。
2)编写USB类驱动 :根据设备的功能,实现相应的USB类驱动代码。例如,对于HID设备,需要实现HID相关的报告描述符和数据交换函数。
3) 配置USB端点 :设置用于数据传输的端点,包括端点的大小、类型和缓冲区。
4)处理USB事件 :实现回调函数来处理USB事件,如设备挂载(attach)、断开(detach)、配置变化等。
5)调试和测试 :在开发板上下载代码,进行实际设备的连接测试和调试。
在STM32上实现USB类设备的过程中,开发者可以参考ST提供的示例代码和开发指南。对于较为复杂的类设备,如大容量存储设备,可以利用现成的库文件和模块,进行适当的裁剪和适配,以满足特定的需求。通过这种方式,开发者可以有效减少开发时间,提升开发效率。
5.USB协议栈
(一)USB 协议栈的分层结构
USB 协议栈通常分为硬件层、物理层、链路层、事务层、协议层和应用层,每层功能如下:
1. 硬件层(Hardware)
- 物理接口:USB 电缆(VCC、GND、D+、D-)、连接器(A 型、B 型、Type-C 等)。
- 控制器:主机控制器(如 xHCI)和设备控制器(如 STM32 内置 USB 模块),负责信号收发与底层协议处理。
2. 物理层(Physical Layer)
- 信号编码:使用 NRZI(非归零反向)编码,通过电平跳变表示数据(如 USB 2.0)。
- 差分信号传输:通过 D + 和 D - 的电压差(±0.3V)传输数据,抗干扰能力强。
- 速率协商:根据设备类型自动协商低速(1.5Mbps)、全速(12Mbps)、高速(480Mbps)等模式。
3. 链路层(Link Layer)
- 分组格式:将数据封装为固定格式的分组(Packet),包含同步头、地址、数据和 CRC 校验。
- 错误检测与重传:通过 CRC 校验确保数据完整性,错误时触发重传机制。
- 流量控制:使用 NAK(未准备好)、STALL(暂停)等握手信号管理数据传输。
4. 事务层(Transaction Layer)
- 事务类型:
- 控制事务:设备枚举、配置命令(如获取设备描述符)。
- 批量事务:大数据量传输(如文件拷贝),无严格实时性要求。
- 中断事务:小数据量、周期性传输(如键盘输入)。
- 同步事务:实时数据流(如音频、视频),允许少量错误。
- 事务组成:由令牌(Token)、数据(Data)和握手(Handshake)三个阶段组成。
5. 协议层(Protocol Layer)
- 设备类协议:定义设备功能和通信规则,如:
- HID(人机接口设备):键盘、鼠标等。
- MSC(海量存储设备):U 盘、移动硬盘。
- CDC(通信设备类):虚拟串口(VCP)。
- Audio(音频设备):麦克风、耳机。
- 设备描述符:设备向主机提供的元数据(如厂商 ID、产品 ID、支持的类)。
6. 应用层(Application Layer)
- 用户程序:通过操作系统 API(如 Windows 的 CreateFile、Linux 的 /dev/ttyUSB*)访问 USB 设备。
- 驱动程序:将 USB 数据转换为应用可理解的格式(如串口数据、文件流)。
(二)USB 协议栈的核心组件
1. 设备描述符(Descriptors)
- 设备描述符:包含厂商 ID、产品 ID、设备版本等基本信息。
- 配置描述符:定义设备的工作模式(如支持的接口数量)。
- 接口描述符:描述功能(如 HID 接口、音频接口)。
- 端点描述符:指定端点地址、类型(控制 / 批量 / 中断 / 同步)和最大包大小。
2. 端点(Endpoints)
- 数据传输的逻辑通道,每个端点有唯一地址和方向(IN/OUT)。
- 端点 0:固定为控制端点,用于设备枚举和配置。
3. 主机与设备的交互流程
- 设备插入:主机检测到 D + 或 D - 上拉,识别设备速率。
- 枚举过程:主机通过端点 0 获取设备描述符,分配地址。
- 配置设备:主机选择配置并激活接口。
- 数据传输:根据设备类协议进行数据交换。
(三)数据传输流程详解
1. 控制传输(以设备枚举为例)
主机 → 设备:[SETUP] 获取设备描述符设备 → 主机:[DATA0] 发送设备描述符(含厂商ID、产品ID等)主机 → 设备:[ACK] 确认接收主机 → 设备:[SETUP] 设置地址(如0x01)设备 → 主机:[ACK] 确认地址设置主机 → 设备:[SETUP] 获取配置描述符设备 → 主机:[DATA1] 发送配置描述符...
2. 批量传输(如 U 盘读写)
主机 → 设备:[OUT令牌] 发送写命令主机 → 设备:[DATA0] 发送数据块设备 → 主机:[ACK] 确认接收主机 → 设备:[IN令牌] 请求读取数据设备 → 主机:[DATA1] 发送数据块主机 → 设备:[ACK] 确认接收
3. 中断传输(如键盘输入)
主机周期性发送:[IN令牌] 请求键盘数据键盘 → 主机:[DATA0] 发送按键状态(如按下\'A\'键)主机 → 设备:[ACK] 确认接收
6.STM32-USB
STM32微控制器系列由STMicroelectronics(意法半导体公司)开发,是基于ARM Cortex-M处理器的32位微控制器。它们具有高性能、低功耗以及高集成度的特点,广泛应用于工业控制、医疗设备、通信系统等地方。STM32系列微控制器支持多种通信接口,其中USB(Universal Serial Bus,通用串行总线)因其高速和易用性成为主流的通信协议之一,也被STM32集成在硬件内。
USB主要特征:
● 符合USB2.0全速设备的技术规范
● 可配置1到8个USB端点
● CRC(循环冗余校验)生成/校验,反向不归零(NRZI)编码/解码和位填充
● 支持同步传输
● 支持批量/同步端点的双缓冲区机制
● 支持USB挂起/恢复操作
● 帧锁定时钟脉冲生成
注: USB和CAN共用一个专用的512字节的SRAM存储器用于数据的发送和接收,因此不能同时使用USB和CAN(共享的SRAM被USB和CAN模块互斥地访问)。 USB和CAN可以同时用于一个应用中但不能在同一个时间使用。
(一)硬件架构
1. 物理接口
- 数据线:D+(绿色)和 D-(白色)差分信号线,传输速率 1.5Mbps(低速)或 12Mbps(全速)
- 上拉 / 下拉电阻:
- Device 模式:D + 需通过 1.5kΩ 上拉电阻连接 VCC(全速设备)或 D - 上拉(低速设备)
- Host 模式:D + 和 D - 需通过 15kΩ 下拉电阻接地
- 电源:Vbus(红色)提供 5V 电源,GND(黑色)为地
2. 内部模块
- USB 核心控制器:
- 处理 USB 协议层(如握手、错误恢复)
- 管理端点(Endpoint)和缓冲区
- 端点缓冲区:
- 通常有 8 个端点(EP0~EP7),每个端点可配置为不同方向和类型
- 端点 0 固定为控制端点,用于设备枚举
- 收发器:
- 实现 TTL 电平和 USB 差分信号的转换
- 支持 NRZI 编码和解码
- 时钟源:
- 需 48MHz 精确时钟(通常由 PLL 提供)
从硬件接口功能上来说STM32系列MCU的USB分为 USB_FS 、 USB_OTG_FS 、 USB_OTG_HS 三种。其中的FS指的是全速(Full Speed),HS指的是高速(High Speed)。OTG指的是既可以作为Device(从设备)使用,也可以作为Host(主机)使用。
Full Speed 理论上速度为12Mbit/s,High Speed 理论上速度为480Mbit/s ,当然这都是理论速度,实际上通讯速度还依赖于所用通讯方式和设备性能。
对于STM32系列MCU而言,USB FS的使用只要使用 DM / D- 和 DP / D+ 这两个引脚就行了,最多也就加上ID、SOF、VBUS这三个引脚。而使用USB HS大多数还需要外接PHY芯片(比如USB3300),这样使用的引脚就多了,至少也要用到12个引脚。STM32系列MCU中目前只有STM32F723内置USB HS PHY功能,不需要外接PHY芯片。
(二)工作模式
1. Device 模式(最常用)
- 特性:
- 作为从设备连接到主机(如 PC、充电器)
- 支持多种设备类(Class):
- HID(Human Interface Device):键盘、鼠标、游戏手柄
- CDC(Communication Device Class):虚拟串口
- MSC(Mass Storage Class):U 盘、移动硬盘
- DFU(Device Firmware Upgrade):固件升级
- 枚举流程:
主机检测连接 → 分配地址 → 获取设备描述符 → 获取配置描述符 → 设置配置 → 数据传输
2. Host 模式
- 特性:
- 作为主机控制外部 USB 设备
- 需提供 5V 电源(通过 Vbus 引脚)
- 支持设备热插拔检测
- 典型应用:
- 读取 U 盘文件系统
- 连接 USB 键盘 / 鼠标
- 控制 USB 摄像头
3. OTG 模式(仅部分型号支持)
- 特性:
- 支持双角色(Device/Host)动态切换
- 通过 ID 引脚或软件判断当前角色
- 支持会话请求协议(SRP)和主机协商协议(HNP)
- 应用场景:
- 移动设备间直接通信(如手机与相机互传数据)
(三)端点(Endpoint)机制
1. 端点类型
2. 端点配置
每个端点需配置:
- 端点号(0~7)
- 方向(IN/OUT)
- 类型(控制 / 批量 / 中断 / 同步)
- 最大包大小(如 64 字节、512 字节)
- 缓冲区地址和大小
(四)软件架构
1. USB 协议栈
应用层 ──────────────────── 用户代码类驱动层 ────────────────── HID/CDC/MSC/DFU驱动USB设备层 ───────────────── 端点管理、数据传输USB核心层 ───────────────── 协议处理、中断管理硬件抽象层 ──────────────── 寄存器操作、底层驱动
2. STM32Cube HAL 库接口
// 初始化USB设备HAL_StatusTypeDef HAL_PCD_Init(PCD_HandleTypeDef *hpcd);// 注册类驱动void HAL_PCD_RegisterClass(PCD_HandleTypeDef *hpcd, PCD_ClassTypeDef *pclass);// 端点数据发送HAL_StatusTypeDef HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pdata, uint32_t size);// 端点数据接收HAL_StatusTypeDef HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pdata, uint32_t size);
3. 中断处理
主要中断源:
- Reset 中断:USB 总线复位
- SOF 中断:帧开始信号(1ms 周期)
- 端点中断:端点传输完成
- 错误中断:CRC 错误、位填充错误等
(五)典型应用场景
1. HID 设备(以鼠标为例)
// HID报告描述符示例(鼠标)const uint8_t HID_Mouse_ReportDesc[USB_HID_MOUSE_REPORT_DESC_SIZE] = { 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) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7F, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xC0, // END_COLLECTION 0xC0 // END_COLLECTION};
2. CDC 虚拟串口
- 工作原理:
- 通过 USB 模拟 RS232 串口通信
- 支持 AT 命令(如调制解调器)
- 应用场景:
- 调试信息输出
- 设备配置接口
- 数据透传
3. MSC 海量存储
- 工作原理:
- 模拟 U 盘设备
- 实现 SCSI 命令集(如 READ、WRITE)
- 存储介质:
- 内部 Flash
- 外部 SPI Flash
- SD 卡
(六)开发要点
1. 时钟配置
- 必须提供 48MHz 精确时钟给 USB 模块
- 通常通过 PLL 倍频得到(如 72MHz/1.5=48MHz)
2. 电源管理
- Device 模式:通过 VBUS 引脚检测主机连接
- Host 模式:需通过 Vbus 引脚向外设供电
- 支持挂起 / 唤醒功能,降低功耗
3. 数据传输优化
- 大数据量传输建议使用 DMA
- 合理设置端点缓冲区大小和数量
- 遵循 USB 协议的数据包大小限制
(七)参考资源
- 官方文档:
- STM32 参考手册(RM)中 \"USB 全速设备\" 章节
- STM32Cube HAL 库用户手册(UM)
- 固件库:
- STM32Cube FW_F1(F1 系列)
- STM32Cube FW_F4(F4 系列)
- 应用笔记:
- AN3156:USB CDC 通信实现
- AN3587:USB MSC 海量存储实现
- AN4221:USB OTG 双角色应用
通过合理配置 USB 外设,STM32 可轻松实现各种 USB 功能,为嵌入式系统提供强大的通信能力。
二、USB-CDC类虚拟串口(VCP)的例程验证
(一)STM32-VCP理论知识
STM32内置的USB,均可支持USB 2.0标准,可以支持三种传输速率:
高速模式:最高可达480 Mbps (部分型号支持,且需搭配外部芯片,不常用,同时,需要搭配外围USB PHY芯片,如USB3300,硬件成本偏高)
全速模式:最高可达12 Mbps (最常用,电路简单)
低速模式:最高可达1.5 Mbps
从机在PCB布线时,仅需把STM32的引脚PA11、PA12, 连接至USB座的DP、DM,然后,PA12(DP线)用1.5K电阻上拉至3.3V。具体如下图:
注:
为什么是上拉?
插拔检测:设备未插入时,主机端DP、DM为低电平,当发现被置高,即为有设备插入;
区分速率:DM线上拉是低速模式,DP线上拉是全速\\高速模式;
上拉电压:3.3V。USB通信电平是3.3V,而不是总线供电的5V。
USB虚拟串口,简称VPC,Virtual Port Com 的简写。但更习惯于把虚拟串口叫作: CDC,因为它是利用 USB 的 CDC类 实现的一种通信接口。利用STM32CubeMX可以快速配置并实现该功能,但是也可以使用ST提供的关于USB的设备库源码进行手动移植操作。
提示:1)Win10、Win11 已带虚拟串口驱动;2)无需安装任何驱动; Win7 要提前手动安装驱动,否则无法识别 :虚拟串口驱动 下载。
(二)使用STM32CubeMX配置生成代码
1. 打开STM32CubeMX新建工程并选择芯片
2.RCC
3.SWD
4.激活USB,使用默认配置
开启GPIO-PD6拉低使能USB,由野火指南者开发板原理图可知
5.使用STM32CubeMX集成的中间件USB_DEVICE下的CDC类-VPC,仍然使用默认配置或者按照自己的需求更改
以下是配置参数说明:
以下是对这些 STM32 USB 配置参数 的详细解释,结合 USB 协议和 STM32 USB 库(如 CubeMX 生成的配置)的作用说明:1. USBD_MAX_NUM_INTERFACES参数名:Maximum number of supported interfaces(支持的最大接口数)含义:USB 设备可以包含 多个 “接口(Interface)”,每个接口对应一种功能(如 “CDC 串口功能”“HID 键盘功能” 等)。该参数定义了你开发的 USB 设备最多能支持多少个独立的接口。范围要求:1 ~ 255(由 USB 协议地址空间决定,7 位地址理论最大 127 设备,但接口数独立限制)。典型场景:若做 复合设备(Composite Device)(如同时支持 “虚拟串口 + 自定义 HID”),需根据实际功能数调整。普通单功能设备(如仅 CDC 或仅 MSC)设为 1 即可。2. USBD_MAX_NUM_CONFIGURATION参数名:Maximum number of supported configuration(支持的最大配置数)含义:USB 设备可以有 多种 “配置(Configuration)”,不同配置可切换设备的功能组合、功耗等。该参数定义设备最多支持多少套配置。绝大多数场景下,设备只需 1 套配置(简单设备用默认配置即可)。典型场景:复杂设备可能需要 “高功耗模式(多功能全开)” 和 “低功耗模式(仅基础功能)”,这时需 2 套配置切换。3. USBD_MAX_STR_DESC_SIZ参数名:Maximum size for the string descriptors(字符串描述符的最大长度)含义:USB 设备的 字符串描述符 用于向主机报告文本信息(如厂商名、产品名、序列号等)。该参数限制单个字符串描述符的最大字节数(需包含 Unicode 编码、长度、类型等 overhead)。设为 512 bytes 属于比较充裕的配置,可容纳较长的字符串(如详细产品描述)。注意:实际字符串长度受 USB 协议限制(理论单字符串最多 126 字节有效内容,因描述符头占 2 字节),但库配置可留冗余。4. USBD_SELF_POWERED参数名:Enabled self power(启用自供电模式)含义:USB 设备供电模式分两种:总线供电(Bus-Powered):从 USB 总线取电(主机 / Hub 提供 5V),电流受限(通常 ≤500mA)。自供电(Self-Powered):设备自身有独立电源(如外接电源、电池),向总线报告 “不依赖总线供电”。设为 Enabled 表示设备是 自供电设备,主机需调整对设备的电流限制策略。典型场景:若设备外接电源(如带电源适配器的仪器),选 Self-Powered;若仅靠 USB 线供电,选 Bus-Powered。5. USBD_DEBUG_LEVEL参数名:USBD Debug Level(USB 设备库调试级别)含义:控制 STM32 USB 设备库是否输出 调试日志,方便开发时排查问题。选项:0: No debug message:关闭调试日志(发布版常用,避免日志占用资源)。1: Error:仅输出错误日志。2: Warning:输出错误 + 警告。3: Info:输出详细信息(开发阶段排障常用)。使用建议:开发时可临时设为 3 看详细流程,发布前改回 0 减少开销。6. USB CDC Rx Buffer Size参数名:USB CDC Rx Buffer Size(USB CDC 接收缓冲区大小)含义:当设备工作在 CDC(虚拟串口)类 时,该参数定义:设备端接收主机数据的缓冲区大小(即从 USB 总线收数据,暂存到 RAM 的缓冲区)。设为 1024 Bytes 表示最多一次暂存 1KB 数据,避免因主机发数据过快导致溢出。注意:若需传输大文件 / 高频数据,可适当增大;但会占用更多 RAM,需平衡。7. USB CDC Tx Buffer Size参数名:USB CDC Tx Buffer Size(USB CDC 发送缓冲区大小)含义:当设备工作在 CDC(虚拟串口)类 时,该参数定义:设备端向主机发送数据的缓冲区大小(即从用户代码取数据,暂存到 RAM 等待 USB 发送的缓冲区)。设为 1024 Bytes 表示最多一次缓存 1KB 数据,避免因 USB 发送慢导致用户数据堆积。典型场景:若设备需高频发数据(如传感器实时流),可增大缓冲区;但同样要权衡 RAM 占用。
1. Device Descriptor(设备描述符)VID (Vendor Identifier)含义:厂商识别码,由 USB-IF(USB Implementers Forum)分配,全球唯一 ,用于区分不同厂商。这里 1155 是 STMicroelectronics(意法半导体)的 VID ,主机通过它识别 “这是 ST 的设备”。LANGID_STRING (Language Identifier)含义:语言标识符,定义设备字符串描述符(厂商名、产品名等)使用的语言。这里 English(United States) 表示字符串是 “美式英语”,主机据此解析文本编码。2. Device Descriptor FS(全速设备描述符,FS=Full Speed)USB 设备可支持多种速度(如全速 12Mbps、高速 480Mbps ),Device Descriptor FS 是全速模式下的设备子描述符,补充更多细节:PID (Product Identifier)含义:产品识别码,由厂商自定义(需在 USB-IF 备案),用于区分同一厂商的不同产品。这里 22336 是 STM32 虚拟串口(Virtual ComPort)的 PID ,主机通过 VID=1155 + PID=22336 识别 “这是 STM32 的虚拟串口设备”。PRODUCT_STRING (Product Identifier)含义:产品名字符串,给用户 / 系统显示的设备名称(如在设备管理器里看到的名字 )。这里 STM32 Virtual ComPort 表示 “这是 STM32 的虚拟串口设备”。CONFIGURATION_STRING (Configuration Identifier)含义:配置名字符串,描述设备当前配置的功能(一个设备可有多套配置,切换功能 / 功耗 )。这里 CDC Config 表示当前配置是 “CDC(虚拟串口)功能配置”。INTERFACE_STRING (Interface Identifier)含义:接口名字符串,描述设备的接口功能(一个配置可包含多个接口,每个接口对应一类功能 )。这里 CDC Interface 表示该接口是 “CDC 类接口”(实现虚拟串口通信)。
6.配置时钟树
7.工程配置
(三)代码编写
main.c
/* USER CODE BEGIN Header *//** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include \"main.h\"#include \"usb_device.h\"#include \"gpio.h\"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include \"usbd_cdc_if.h\"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 *//** * @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 */uint8_t TX[] = \"abc\\r\\n\"; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_Delay(2000); CDC_Transmit_FS(TX, 5); } /* USER CODE END 3 */}/** * @brief System Clock Configuration * @retval None */void SystemClock_Config(void){ RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB; PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); }}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//** * @brief This function is executed in case of error occurrence. * @retval None */void Error_Handler(void){ /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */}#ifdef USE_FULL_ASSERT/** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */void assert_failed(uint8_t *file, uint32_t line){ /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf(\"Wrong parameters value: file %s on line %d\\r\\n\", file, line) */ /* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */
usbd_cdc_if.c
/* USER CODE BEGIN Header *//** ****************************************************************************** * @file : usbd_cdc_if.c * @version : v2.0_Cube * @brief : Usb device for Virtual Com Port. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include \"usbd_cdc_if.h\"/* USER CODE BEGIN INCLUDE *//* USER CODE END INCLUDE *//* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PV *//* Private variables ---------------------------------------------------------*//* USER CODE END PV *//** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY * @brief Usb device library. * @{ *//** @addtogroup USBD_CDC_IF * @{ *//** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions * @brief Private types. * @{ *//* USER CODE BEGIN PRIVATE_TYPES *//* USER CODE END PRIVATE_TYPES *//** * @} *//** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines * @brief Private defines. * @{ *//* USER CODE BEGIN PRIVATE_DEFINES *//* USER CODE END PRIVATE_DEFINES *//** * @} *//** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros * @brief Private macros. * @{ *//* USER CODE BEGIN PRIVATE_MACRO *//* USER CODE END PRIVATE_MACRO *//** * @} *//** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables * @brief Private variables. * @{ *//* Create buffer for reception and transmission *//* It\'s up to user to redefine and/or remove those define *//** Received data over USB are stored in this buffer */uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];/** Data to send over USB CDC are stored in this buffer */uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];/* USER CODE BEGIN PRIVATE_VARIABLES *//* USER CODE END PRIVATE_VARIABLES *//** * @} *//** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables * @brief Public variables. * @{ */extern USBD_HandleTypeDef hUsbDeviceFS;/* USER CODE BEGIN EXPORTED_VARIABLES *//* USER CODE END EXPORTED_VARIABLES *//** * @} *//** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes * @brief Private functions declaration. * @{ */static int8_t CDC_Init_FS(void);static int8_t CDC_DeInit_FS(void);static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION *//* USER CODE END PRIVATE_FUNCTIONS_DECLARATION *//** * @} */USBD_CDC_ItfTypeDef USBD_Interface_fops_FS ={ CDC_Init_FS, CDC_DeInit_FS, CDC_Control_FS, CDC_Receive_FS};/* Private functions ---------------------------------------------------------*//** * @brief Initializes the CDC media low layer over the FS USB IP * @retval USBD_OK if all operations are OK else USBD_FAIL */static int8_t CDC_Init_FS(void){ /* USER CODE BEGIN 3 */ /* Set Application Buffers */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); return (USBD_OK); /* USER CODE END 3 */}/** * @brief DeInitializes the CDC media low layer * @retval USBD_OK if all operations are OK else USBD_FAIL */static int8_t CDC_DeInit_FS(void){ /* USER CODE BEGIN 4 */ return (USBD_OK); /* USER CODE END 4 */}/** * @brief Manage the CDC class requests * @param cmd: Command code * @param pbuf: Buffer containing command data (request parameters) * @param length: Number of data to be sent (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL */static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length){ /* USER CODE BEGIN 5 */ switch(cmd) { case CDC_SEND_ENCAPSULATED_COMMAND: break; case CDC_GET_ENCAPSULATED_RESPONSE: break; case CDC_SET_COMM_FEATURE: break; case CDC_GET_COMM_FEATURE: break; case CDC_CLEAR_COMM_FEATURE: break; /*******************************************************************************/ /* Line Coding Structure */ /*-----------------------------------------------------------------------------*/ /* Offset | Field | Size | Value | Description */ /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ /* 4 | bCharFormat | 1 | Number | Stop bits */ /* 0 - 1 Stop bit */ /* 1 - 1.5 Stop bits */ /* 2 - 2 Stop bits*/ /* 5 | bParityType | 1 | Number | Parity */ /* 0 - None */ /* 1 - Odd */ /* 2 - Even */ /* 3 - Mark */ /* 4 - Space */ /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ /*******************************************************************************/ case CDC_SET_LINE_CODING: break; case CDC_GET_LINE_CODING: break; case CDC_SET_CONTROL_LINE_STATE: break; case CDC_SEND_BREAK: break; default: break; } return (USBD_OK); /* USER CODE END 5 */}/** * @brief Data received over USB OUT endpoint are sent over CDC interface * through this function. * * @note * This function will issue a NAK packet on any OUT packet received on * USB endpoint until exiting this function. If you exit this function * before transfer is complete on CDC interface (ie. using DMA controller) * it will result in receiving more data while previous ones are still * not sent. * * @param Buf: Buffer of data to be received * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL */static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len){ /* USER CODE BEGIN 6 */CDC_Transmit_FS(Buf, *Len); USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); return (USBD_OK); /* USER CODE END 6 */}/** * @brief CDC_Transmit_FS * Data to send over USB IN endpoint are sent over CDC interface * through this function. * @note * * * @param Buf: Buffer of data to be sent * @param Len: Number of data to be sent (in bytes) * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY */uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len){ uint8_t result = USBD_OK; /* USER CODE BEGIN 7 */ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; if (hcdc->TxState != 0){ return USBD_BUSY; } USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); /* USER CODE END 7 */ return result;}/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION *//* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION *//** * @} *//** * @} */
(四)实验效果
参考链接:
STM32 USB通信知识与应用详解
STM32 USB功能深入解析及应用指南
基于STM32讲USB 【正点原子STM32连载】 第六十一章 USB虚拟串口实验摘自【正点原子】STM32F103 战舰开发指南V1.2
【STM32H7】第8章 学习USB协议栈前要了解的基础知识
STM32 USB开发全面指南:从基础到应用
STM32的USB接口介绍
stm32学习记录-通讯接口-USB
硬汉嵌入式
博客园-野火指南者USB