[特殊字符] USBX 移植实现虚拟串口(CDC ACM)详细步骤笔记

🎯 准备工作

  1. 获取源码:从上一节视频配套源码中复制基础工程

  2. 硬件平台:STM32H563xx系列(根据实际芯片调整)

  3. 开发环境:STM32CubeMX + Keil MDK-ARM(或其他IDE)

  4. USBX源码:从ST官方获取或已有usbx文件夹


📝 详细移植步骤

第一步:CubeMX配置USB硬件

  1. 打开现有工程和对应的.ioc CubeMX文件

  2. 配置USB模块

    • 在"Connectivity"中选择USB

    • 模式选择:Device_Only

  3. 配置NVIC中断

    • 勾选USB中断(确保中断使能)
  4. 生成代码

    • 点击"Generate Code"更新工程文件

第二步:准备USBX组件目录

  1. 找到USBX源码:定位到电脑上的usbx文件夹

  2. 移植到工程

    cs 复制代码
    源位置:任意位置/usbx
    目标位置:<工程目录>/Middlewares/Third_Party/usbx
  3. 复制app文件夹

    cs 复制代码
    源位置:程序源码/usbx/app
    目标位置:<工程目录>/Middlewares/Third_Party/usbx/app

第三步:创建工程文件结构

在MDK-ARM工程中创建四个组(Group)对应USBX四层架构:

组名 对应层级 物理路径
USBX/class_layer Class Layer Middlewares/USBX/class_layer
USBX/stack_layer Stack Layer Middlewares/USBX/stack_layer
USBX/usb_device_controller_layer Controller Layer Middlewares/USBX/usb_device_controller_layer
USBX/app Application Middlewares/USBX/app

第四步:添加各层源文件

4.1 Class Layer (CDC ACM类)
  1. 源文件位置usbx/common/usbx_device_classes/src/

  2. 添加文件

    • 添加所有以ux_device_class_cdc_acm开头的.c文件

    • 使用通配符:ux_device_class_cdc_acm*

4.2 Stack Layer (设备栈)
  1. 源文件位置usbx/common/core/src/

  2. 添加文件

    • 添加所有以ux_device_stack开头的.c文件

    • 使用通配符:ux_device_stack*

    • 注意:编译时可能会缺其他辅助文件,后续根据错误添加

4.3 Controller Layer (STM32控制器驱动)
  1. 源文件位置usbx/common/usbx_stm32_device_controllers/

  2. 添加文件:添加该目录下的所有源文件

4.4 Application Layer (应用层)
  1. 源文件位置usbx/app/(之前复制的)

  2. 添加文件:添加该目录下的所有源文件


第五步:修改usb.c文件

5.1 添加头文件
cs 复制代码
#include "ux_port.h"
#include "ux_device_descriptors.h"
#include "ux_dcd_stm32.h"
5.2 添加函数声明
cs 复制代码
UINT MX_USBX_Device_Init(void);
MX_USBX_Device_Init();
5.3 在MX_USB_DRD_FS_Init()函数中添加以下代码

电源使能

cs 复制代码
HAL_PWREx_EnableVddUSB();
HAL_PWREx_EnableUSBVoltageDetector();

端点Packet Buffer Memory配置

cs 复制代码
// 配置各个端点的缓冲区地址
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0x14);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0x54);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPINCMD_ADDR, PCD_SNG_BUF, 0x94);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPOUT_ADDR, PCD_SNG_BUF, 0xD4);
HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_CDCACM_EPIN_ADDR, PCD_SNG_BUF, 0x114);

USBX初始化和启动

cs 复制代码
// 初始化USBX的STM32设备控制器
ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS);

// 调用USBX设备初始化函数
MX_USBX_Device_Init();

// 启动PCD
HAL_PCD_Start(&hpcd_USB_DRD_FS);

第六步:创建USBX任务(独立模式)

6.1 修改app_freertos.c

添加头文件

cs 复制代码
#include "stdio.h"
#include "draw.h"
#include "ux_api.h"

在默认任务循环中添加

cs 复制代码
void StartDefaultTask(void *argument)
{
    /* 初始化代码... */
    
    for(;;)
    {
        // 运行USBX系统任务(独立模式必须定期调用)
        ux_system_tasks_run();
        
        osDelay(1);  // 适当延迟
    }
}

第七步:MDK-ARM工程配置详解

7.1 预处理宏定义配置

Options for TargetC/C++Preprocessor Symbols 中添加以下宏:

cs 复制代码
USE_HAL_DRIVER
STM32H563xx
UX_INCLUDE_USER_DEFINE_FILE

各宏作用说明:

  • USE_HAL_DRIVER:启用STM32 HAL库

  • STM32H563xx:指定芯片型号(根据实际调整)

  • UX_INCLUDE_USER_DEFINE_FILE:关键!允许USBX使用用户自定义配置文件(ux_user.h

7.2 编译器选项设置

Language / Code Generation 选项卡中:

  1. Language C :选择 c11 标准

  2. Optimization :调试时建议选 -O0,发布可选 -O1-O2

  3. 关键勾选项

    • ☑ One ELF Section per Function(便于代码优化和调试)

    • ☑ Plain Char is Signed(char默认为有符号)

7.3 头文件包含路径配置

Include Paths 中添加以下路径(注意相对路径):

cs 复制代码
./Core/Inc
./Drivers/STM32H5xx_HAL_Driver/Inc
./Drivers/STM32H5xx_HAL_Driver/Inc/Legacy
./Drivers/CMSIS/Device/ST/STM32H5xx/Include
./Drivers/CMSIS/Include
./Drivers/Module_driver
./Middlewares/Third_Party/FreeRTOS/Source/include/
./Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM33_NTZ/non_secure/
./Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/
./Middlewares/Third_Party/CMSIS/RTOS2/include/
./Middlewares/Third_Party/usbx/common/core/inc
./Middlewares/Third_Party/usbx/ports/generic/inc
./Middlewares/Third_Party/usbx/app
./Middlewares/Third_Party/usbx/common/usbx_stm32_device_controllers
./Middlewares/Third_Party/usbx/common/usbx_device_classes/inc

路径说明:

  • 前9个是原有的FreeRTOS和CMSIS路径

  • 后5个是新增的USBX相关路径,确保USBX各层头文件能被正确找到


第八步:添加USB串口测试代码

8.1 修改app_freertos.c添加发送任务

Core/Src/app_freertos.c 文件中进行以下修改:

1. 添加头文件(USER CODE BEGIN Includes段)
cs 复制代码
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "draw.h"
#include "ux_api.h"
/* USER CODE END Includes */
2. 添加USB串口发送函数声明

如果函数未在其他头文件中声明,需要在任务函数前添加:

cs 复制代码
/* 声明USB串口发送函数 */
int ux_device_cdc_acm_send(uint8_t *datas, uint32_t len, uint32_t timeout);
3. 创建SPILCD任务发送测试数据

在合适位置添加以下任务函数(或在现有任务中修改):

cs 复制代码
static void SPILCDTaskFunction(void *pvParameters)
{
    char buf[100];
    int cnt = 0;
    
    while (1)
    {
        /* 格式化测试字符串 */
        sprintf(buf, "USB Serial Send Test : %d\r\n", cnt++);
        
        /* 可选:在LCD上显示(如果LCD已初始化) */
        // Draw_String(0, 0, buf, 0x0000ff00, 0);
        
        /* 通过USB串口发送数据 */
        ux_device_cdc_acm_send((uint8_t *)buf, strlen(buf), 1000);
        
        /* 延迟1秒 */
        vTaskDelay(1000);
    }
}

第九步:编译与问题解决

首次编译常见错误及解决

错误类型 可能原因 解决方案
未找到头文件 包含路径不正确 检查第七步中的路径,确保所有路径都存在
未定义符号 源文件未添加完整 回到第四步,确保每层所需文件都已添加
内存不足 堆栈配置太小 FreeRTOSConfig.h中增大堆栈大小
链接错误 函数重复定义 检查是否重复包含了源文件

编译顺序建议

  1. 先编译基础工程:确保不带USBX时能编译通过

  2. 分层添加编译:按Controller→Stack→Class→App顺序添加文件并编译

  3. 解决依赖关系:根据错误提示逐步添加缺少的文件


第十步:烧录与测试验证

10.1 硬件连接

  1. 使用USB数据线连接开发板USB口到电脑

  2. 确保开发板供电正常

  3. 连接调试器(ST-Link/J-Link等)

10.2 烧录程序

  1. 在MDK-ARM中点击 Download 按钮

  2. 确认程序烧录成功,无错误提示

  3. 重启开发板或按下复位键

10.3 电脑端验证

设备识别检查
  1. 打开 设备管理器

  2. 查看 端口(COM和LPT) 下是否有新设备

  3. 正常识别应显示类似:USB 串行设备 (COM3)

串口通信测试
  1. 打开串口调试工具(如Putty、SecureCRT等)

  2. 选择正确的COM端口

  3. 设置参数:波特率115200、8数据位、1停止位、无校验

  4. 发送测试:在串口工具中发送任意字符

    • 观察开发板LCD是否显示发送的内容
  5. 接收测试:查看串口工具是否每秒收到测试数据:

    cs 复制代码
    USB Serial Send Test : 0
    USB Serial Send Test : 1
    USB Serial Send Test : 2
    ...

10.4 常见问题排查

现象 可能原因 排查方法
电脑无法识别 USB线问题/供电不足 更换USB线,确保D+/D-线连接正常
识别为未知设备 驱动问题/描述符错误 安装STM32 USB驱动,检查描述符配置
无法打开串口 端口被占用 关闭其他占用该端口的程序
无数据接收 发送任务未运行 检查任务是否创建,USBX任务是否定期调用
数据乱码 波特率不匹配 确认串口工具和代码中波特率一致

📋 完整配置检查清单

配置项检查

  • CubeMX中USB配置为Device_Only

  • USB中断已使能

  • 四层文件结构完整

  • 各层源文件已添加到工程

  • usb.c中的初始化和配置代码已添加

  • 头文件路径已正确配置

  • 预处理宏已定义

  • 发送任务已创建并运行

  • 接收回调函数已修改

代码检查

  • ux_system_tasks_run()在任务中定期调用

  • USB电源使能函数已调用

  • 端点缓冲区配置正确

  • 描述符配置符合CDC ACM规范

  • 内存地址无冲突


🎯 功能验证清单

功能 测试方法 预期结果
USB设备识别 查看设备管理器 出现新串口设备
数据发送 串口工具接收 每秒收到递增的测试数据
数据接收 串口工具发送 LCD显示发送的内容
稳定性 长时间运行 无断连,数据无丢失
热插拔 拔插USB线 重新连接后功能正常

🔧 调试技巧

  1. 使用调试器单步调试:在USB初始化代码处设置断点

  2. 查看USB状态寄存器:通过STM32CubeMonitor等工具监控USB状态

  3. 修改测试间隔:缩短发送间隔测试实时性

  4. 添加调试输出:通过串口打印调试信息(注意不要与虚拟串口冲突)

  5. 使用USB分析仪:如果有条件,使用USB协议分析仪抓包分析

相关推荐
LN花开富贵2 小时前
LM393的工作原理和引脚作用
笔记·单片机·嵌入式硬件·学习·嵌入式
BlackWolfSky2 小时前
鸿蒙中级课程笔记3—ArkUI进阶2—给应用添加交互(弹窗)
笔记·华为·harmonyos
解局易否结局2 小时前
学习 Flutter for OpenHarmony 的前置 Dart 语言:高级特性实战笔记(下)
笔记·学习·flutter
马猴烧酒.2 小时前
智能协图云图库学习笔记day5
java·jvm·spring boot·笔记·学习·mvc
Hammer_Hans2 小时前
DFT笔记23
笔记
爱奥尼欧2 小时前
【通信原理】信道——信道、传输特性、多径效应、噪声、带宽、信道容量(笔记总结)
笔记
夜流冰10 小时前
Motor - 电机扭矩和电机大小的关系
笔记
AI视觉网奇11 小时前
LiveTalking 部署笔记
笔记
倘若猫爱上鱼11 小时前
关于系统能检测到固态可移动硬盘(或U盘),系统资源管理器却始终无法扫描到固态可移动硬盘(或U盘)的解决办法
笔记