欢迎光临
我们一直在努力

STM32 单片机 USB 通讯原理与 HAL 库实战详解

一、USB 基础与 STM32 硬件架构

1.1 USB 核心概念

USB (Universal Serial Bus) 是一种主从架构的串行总线标准:

  • 主机 (Host):控制总线,发起所有传输
  • 设备 (Device):响应主机请求
  • OTG(On-The-Go):设备可在主机和设备模式间切换
  • 传输速度:STM32 支持 USB 2.0 全速 (FS, 12Mbps) 和高速 (HS, 480Mbps)
  • 端点 (Endpoint):USB 通讯的基本单元,每个设备最多 16 个 IN 端点和 16 个 OUT 端点
    • 端点 0:控制传输专用,双向,所有 USB 设备必须具备
    • 端点 1~15:批量、中断、同步传输,单向

1.2 STM32 USB 外设架构

STM32 的 USB OTG 外设主要由以下部分组成:

  • OTG 核心:处理 USB 协议底层逻辑
  • 设备控制器 (PCD):设备模式下的控制逻辑
  • 主机控制器 (HCD):主机模式下的控制逻辑
  • 端点 FIFO:每个端点有独立的 FIFO 缓冲区
  • DMA 控制器:用于高速数据传输
  • 中断控制器:处理 USB 相关中断

二、USB 传输类型详解

传输类型用途特点典型应用
控制传输 设备枚举、配置、命令控制 双向,可靠,低带宽 设备识别、驱动安装
批量传输 大量非实时数据 单向,可靠,带宽可变 U 盘、打印机
中断传输 少量实时数据 单向,低延迟,固定周期 键盘、鼠标
同步传输 实时数据流 单向,不可靠,固定带宽 音频、视频

三、STM32 USB 关键寄存器详解

3.1 全局控制与状态寄存器

  • USB_OTG_GOTGCTL:OTG 控制寄存器,控制主从模式切换
  • USB_OTG_GINTSTS:全局中断状态寄存器,指示所有中断源
  • USB_OTG_GINTMSK:全局中断屏蔽寄存器,使能 / 禁用特定中断
  • USB_OTG_GRXSTSP:接收状态弹出寄存器,读取 OUT 端点接收状态

3.2 设备模式专用寄存器

  • USB_OTG_DCFG:设备配置寄存器,设置设备速度、端点 0 最大包长
  • USB_OTG_DCTL:设备控制寄存器,控制设备复位、远程唤醒
  • USB_OTG_DSTS:设备状态寄存器,指示设备当前状态
  • USB_OTG_DAINT:设备所有端点中断寄存器,指示哪个端点产生中断

3.3 端点控制寄存器

  • USB_OTG_DIEPCTLx:设备 IN 端点 x 控制寄存器,配置端点类型、最大包长
  • USB_OTG_DOEPCTLx:设备 OUT 端点 x 控制寄存器
  • USB_OTG_DIEPTSIZx:设备 IN 端点 x 传输大小寄存器,设置要发送的字节数
  • USB_OTG_DOEPTSIZx:设备 OUT 端点 x 传输大小寄存器,设置要接收的字节数

四、STM32CubeMX USB 配置步骤

4.1 基础时钟配置 (关键!)

USB 时钟必须精确为48MHz(FS)或480MHz(HS):

  • 启用外部高速晶振 (HSE)
  • 配置 PLL:
    • 对于 HSE=8MHz:PLLM=8, PLLN=336, PLLP=2, PLLQ=7 → USB 时钟 = 48MHz
    • 对于 HSE=25MHz:PLLM=25, PLLN=336, PLLP=2, PLLQ=7 → USB 时钟 = 48MHz
  • 在 "Clock Configuration" 中确认 "USB Clock" 为 48MHz
  • 4.2 USB 外设配置

  • 在 "Pinout & Configuration" 中选择 USB_OTG_FS 或 USB_OTG_HS
  • 选择模式:
    • Device_Only:仅设备模式 (最常用)
    • Host_Only:仅主机模式
    • OTG:支持主从切换
  • 配置 GPIO:
    • USB_DM 和 USB_DP 自动配置为复用功能
    • 如需 VBUS 检测,配置 VBUS 引脚为输入模式
  • 4.3 USB 中间件配置

  • 切换到 "Middleware" 选项卡
  • 选择 "USB_DEVICE"
  • 选择设备类:
    • Communication Device Class (CDC):虚拟串口
    • Mass Storage Class (MSC):U 盘
    • Human Interface Device (HID):人机接口设备
    • Audio Class:音频设备
  • 配置设备描述符参数 (VID、PID、产品名称等)
  • 五、USB 设备状态机

    STM32 USB 设备在运行过程中会经历以下状态:

  • 连接状态 (Attached):设备物理连接到主机
  • 上电状态 (Powered):设备从 USB 总线获得电源
  • 默认状态 (Default):设备收到复位信号后
  • 地址状态 (Address):主机为设备分配唯一地址
  • 配置状态 (Configured):主机完成设备配置,设备可正常工作
  • 挂起状态 (Suspended):总线空闲超过 3ms,设备进入低功耗模式
  • 六、常用 USB 模式 HAL 库应用示例

    6.1 虚拟串口 (CDC) 模式

    应用场景:PC 与单片机之间的串口通讯,替代传统 RS232 接口

    CubeMX 配置:

    • USB_DEVICE → Class for FS IP → Communication Device Class(CDC)
    • 生成代码后,在usbd_cdc_if.c文件中实现数据收发

    发送数据示例:

    #include "usbd_cdc_if.h"

    // 发送字符串
    uint8_t tx_buffer[] = "Hello USB CDC!\\r\\n";
    CDC_Transmit_FS(tx_buffer, sizeof(tx_buffer)-1);

    // 发送二进制数据
    uint16_t adc_value = 1234;
    uint8_t data[2];
    data[0] = (adc_value >> 8) & 0xFF;
    data[1] = adc_value & 0xFF;
    CDC_Transmit_FS(data, 2);

    接收数据示例:在usbd_cdc_if.c的CDC_Receive_FS函数中添加处理代码:

    static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
    {
    // Buf: 接收到的数据缓冲区
    // Len: 接收到的数据长度

    // 回显接收到的数据
    CDC_Transmit_FS(Buf, *Len);

    // 准备下一次接收
    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);

    return (USBD_OK);
    }

    6.2 大容量存储 (MSC) 模式

    应用场景:实现 U 盘功能,可访问内部 Flash 或外部 SD 卡

    CubeMX 配置:

    • USB_DEVICE → Class for FS IP → Mass Storage Class(MSC)
    • 生成代码后,在usbd_storage_if.c文件中实现存储介质操作

    内部 Flash 模拟 U 盘示例:修改usbd_storage_if.c中的以下函数:

    #define STORAGE_LUN_NBR 1
    #define STORAGE_BLK_NBR 64 // 64个块
    #define STORAGE_BLK_SIZ 512 // 每个块512字节

    // 内部Flash地址(根据实际芯片调整)
    #define FLASH_START_ADDR 0x08020000

    int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
    uint32_t i;
    uint32_t flash_addr = FLASH_START_ADDR + blk_addr * STORAGE_BLK_SIZ;

    for(i=0; i<blk_len*STORAGE_BLK_SIZ; i++)
    {
    buf[i] = *(__IO uint8_t*)(flash_addr + i);
    }

    return (USBD_OK);
    }

    int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
    {
    uint32_t i;
    uint32_t flash_addr = FLASH_START_ADDR + blk_addr * STORAGE_BLK_SIZ;
    HAL_StatusTypeDef status;

    // 解锁Flash
    HAL_FLASH_Unlock();

    // 擦除扇区
    FLASH_EraseInitTypeDef erase_init;
    erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
    erase_init.Sector = FLASH_SECTOR_5; // 根据实际地址调整
    erase_init.NbSectors = 1;
    erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
    uint32_t sector_error;
    HAL_FLASHEx_Erase(&erase_init, &sector_error);

    // 写入数据
    for(i=0; i<blk_len*STORAGE_BLK_SIZ; i+=4)
    {
    status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
    flash_addr + i,
    *(uint32_t*)(buf + i));
    if(status != HAL_OK) break;
    }

    // 锁定Flash
    HAL_FLASH_Lock();

    return (USBD_OK);
    }

    int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
    {
    *block_num = STORAGE_BLK_NBR;
    *block_size = STORAGE_BLK_SIZ;
    return (USBD_OK);
    }

    6.3 人机接口 (HID) 模式

    应用场景:无需安装驱动的设备,如键盘、鼠标、游戏手柄

    CubeMX 配置:

    • USB_DEVICE → Class for FS IP → Human Interface Device(HID)
    • 生成代码后,在usbd_hid.c文件中修改报告描述符

    USB 鼠标示例:

  • 修改usbd_hid.c中的报告描述符:
  • __ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
    {
    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 (Buttons)
    0x19, 0x01, // Usage Minimum (0x01)
    0x29, 0x03, // Usage Maximum (0x03)
    0x15, 0x00, // Logical Minimum (0)
    0x25, 0x01, // Logical Maximum (1)
    0x75, 0x01, // Report Size (1)
    0x95, 0x03, // Report Count (3)
    0x81, 0x02, // Input (Data,Var,Abs)
    0x75, 0x05, // Report Size (5)
    0x95, 0x01, // Report Count (1)
    0x81, 0x03, // Input (Const,Var,Abs)
    0x05, 0x01, // Usage Page (Generic Desktop)
    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
    0xC0 // End Collection
    };

    2. 发送鼠标报告:

    #include "usbd_hid.h"

    // 鼠标报告结构
    typedef struct {
    uint8_t buttons; // 位0:左键, 位1:右键, 位2:中键
    int8_t x; // X轴移动(-127~127)
    int8_t y; // Y轴移动(-127~127)
    int8_t wheel; // 滚轮移动(-127~127)
    } MouseReport;

    // 移动鼠标
    MouseReport report = {0};
    report.x = 10; // 向右移动10个单位
    report.y = -5; // 向上移动5个单位
    USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&report, sizeof(report));

    // 点击左键
    report.buttons = 0x01;
    USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&report, sizeof(report));
    HAL_Delay(100);
    report.buttons = 0x00;
    USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&report, sizeof(report));

    6.4 复合设备模式

    应用场景:同时实现多个 USB 功能,如虚拟串口 + U 盘

    CubeMX 配置:

    • USB_DEVICE → Class for FS IP → Composite Device
    • 添加需要的设备类 (如 CDC 和 MSC)
    • 生成代码后,在usbd_composite.c文件中配置接口

    七、HAL 库 USB 核心函数详解

    7.1 设备控制函数

    • HAL_PCD_Init(PCD_HandleTypeDef *hpcd):初始化 USB 设备控制器
    • HAL_PCD_DeInit(PCD_HandleTypeDef *hpcd):反初始化 USB 设备控制器
    • HAL_PCD_Start(PCD_HandleTypeDef *hpcd):启动 USB 设备
    • HAL_PCD_Stop(PCD_HandleTypeDef *hpcd):停止 USB 设备
    • HAL_PCD_SetAddress(PCD_HandleTypeDef *hpcd, uint8_t address):设置设备地址

    7.2 端点操作函数

    • HAL_PCD_EP_Open(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint16_t ep_mps, uint8_t ep_type):打开端点
    • HAL_PCD_EP_Close(PCD_HandleTypeDef *hpcd, uint8_t ep_addr):关闭端点
    • HAL_PCD_EP_Transmit(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pbuf, uint32_t len):发送数据
    • HAL_PCD_EP_Receive(PCD_HandleTypeDef *hpcd, uint8_t ep_addr, uint8_t *pbuf, uint32_t len):接收数据
    • HAL_PCD_EP_SetStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr):设置端点暂停
    • HAL_PCD_EP_ClearStall(PCD_HandleTypeDef *hpcd, uint8_t ep_addr):清除端点暂停

    7.3 中断回调函数

    • HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd):USB 复位回调
    • HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd):USB 挂起回调
    • HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd):USB 恢复回调
    • HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd):USB 连接回调
    • HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd):USB 断开回调

    八、常见问题与解决方案

  • USB 枚举失败

    • 检查 USB 时钟是否精确为 48MHz
    • 检查 USB_DM 和 USB_DP 引脚是否正确连接
    • 检查设备描述符和配置描述符是否正确
    • 确保 VBUS 检测功能正常 (如果启用)
  • 数据传输不稳定

    • 增加 USB 线的屏蔽性
    • 缩短 USB 线长度
    • 检查电源稳定性
    • 调整端点 FIFO 大小
  • 驱动安装问题

    • CDC 设备:Windows 10 及以上系统自带驱动
    • HID 设备:所有系统都自带驱动
    • 自定义设备:需要使用 WinUSB 或 libusb 驱动
  • 中断冲突

    • 调整 USB 中断优先级,确保高于其他低优先级中断
    • 避免在中断服务程序中执行耗时操作
  • 赞(0)
    未经允许不得转载:171主机测评 » STM32 单片机 USB 通讯原理与 HAL 库实战详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址