当前位置: 首页 > news >正文

立创开源:基于STM32F103RCT6的三合一USB读卡器,支持拖拽文件升级与WS2812灯带控制

手把手教你打造三合一USB读卡器:STM32F103实现拖拽升级与灯带控制

最近在做一个需要频繁更新固件的项目,每次都要插上ST-Link烧录,实在麻烦。后来看到立创开源社区有个项目,用STM32F103做了一个支持U盘拖拽升级的三合一USB读卡器,还能控制WS2812灯带,这不正是我需要的吗?研究了一番,发现这个项目设计得很巧妙,特别适合想学习USB复合设备和BootLoader的朋友。

今天我就把这个项目拆开揉碎了讲给你听,从硬件设计到软件实现,一步步带你理解怎么用STM32F103RCT6实现MSC(U盘)、HID(多媒体控制)和CDC(虚拟串口)三种USB设备,以及如何实现拖拽文件就能升级固件的“懒人”功能。无论你是想复刻这个项目,还是想学习其中的技术点,这篇文章都能帮到你。

1. 项目整体介绍:这到底是个啥设备?

简单来说,这是一个基于STM32F103RCT6的多功能USB设备。你可以把它理解成一个“瑞士军刀”式的开发板,集成了好几种实用功能。

1.1 核心功能:三合一USB设备

这个设备最厉害的地方在于,它通过一个USB接口,同时模拟了三种不同的USB设备:

  • MSC设备(U盘读卡器):把插在设备上的SD卡变成一个U盘,电脑可以直接读写里面的文件。这是实现拖拽升级的基础。
  • HID设备(多媒体键盘):设备上有个滚轮和按键,可以控制电脑的音量、播放/暂停、上一曲/下一曲。想象一下,把它放在桌面上,手一滚就能调音量,多方便。
  • CDC设备(虚拟串口):在电脑上生成一个串口,可以通过串口工具发送命令给设备。里面还移植了LetterShell这个开源命令行工具,让你可以像在Linux终端里一样操作设备。

注意:目前CDC虚拟串口有个小bug,会不定时重启,作者说后续会修复。不过不影响主要功能的使用。

1.2 特色功能:拖拽升级与灯带控制

除了三合一USB,还有两个很酷的功能:

拖拽文件升级固件这是我最喜欢的功能。传统的STM32开发,改完代码要编译、连接烧录器、点击下载……一套流程下来挺费时间。而这个设备,你只需要按住滚轮按键再上电,它就会进入BootLoader模式,在电脑上显示为一个U盘。然后把编译好的.bin文件拖进去,它就自动更新了!更新完自动重启运行新程序。对于需要频繁调试的项目,这能省下大量时间。

WS2812灯带控制器板子上自带两颗WS2812灯珠,还留出了接口可以外接灯带。WS2812是一种智能RGB灯珠,每个灯珠都可以单独控制颜色,只需要一根信号线。你可以用它做氛围灯、状态指示,或者任何你能想到的光效。

1.3 硬件概览:主控与关键部件

咱们来看看这个设备的硬件核心:

部件型号/参数作用说明
主控芯片STM32F103RCT6ARM Cortex-M3内核,72MHz主频,256KB Flash,48KB RAM。其中64KB专门给BootLoader用,剩下192KB给用户程序
显示屏1.3寸OLED (SSD1306/SH1106)显示设备状态、菜单等信息。两种驱动芯片都支持
外部FlashW25Q64 (8MB)存储待升级的APP程序文件。原来想用内部Flash存,但空间不够分
灯珠WS2812 × 2RGB彩灯,可外接灯带扩展
存储卡标准SD卡模拟U盘的存储介质

整个硬件分成了顶板和底板两部分。顶板主要是OLED屏幕、滚轮编码器和WS2812灯珠;底板是主控、SD卡槽、外部Flash和USB接口。这种模块化设计方便调试和维修。

2. 硬件设计详解:看懂原理图

要理解这个项目,得先看看硬件是怎么连接的。我根据原理图整理了几个关键部分。

2.1 主控引脚分配

STM32F103RCT6有64个引脚,这个项目用到了其中大部分。下面是一些关键外设的引脚连接:

USB相关引脚

  • PA11- USB DM (数据负)
  • PA12- USB DP (数据正)
  • 这两个引脚专门用于USB通信,STM32的USB外设是内置的,不需要额外芯片

SD卡接口(SPI模式)

  • PA4- SD_CS (片选)
  • PA5- SD_SCK (时钟)
  • PA6- SD_MISO (主入从出)
  • PA7- SD_MOSI (主出从入)
  • SD卡通过SPI接口连接,相比SDIO模式接线简单,虽然速度慢些,但对于这个应用足够了

外部Flash W25Q64(也是SPI)

  • PB12- FLASH_CS (片选)
  • PB13- FLASH_SCK (时钟)
  • PB14- FLASH_MISO
  • PB15- FLASH_MOSI
  • 注意:SD卡和Flash共用SPI1,但是用不同的片选引脚,所以可以同时连接

WS2812控制

  • PB1- WS2812_DATA
  • WS2812只需要一根数据线,但时序要求很严格,需要用PWM+DMA或者定时器精确控制

OLED屏幕(I2C接口)

  • PB6- OLED_SCL (时钟)
  • PB7- OLED_SDA (数据)
  • I2C接口只需要两根线,节省引脚

滚轮编码器

  • PA0- ENCODER_A
  • PA1- ENCODER_B
  • PA8- ENCODER_KEY (按键)
  • 编码器用于音量控制/曲目切换,按键用于静音/播放暂停

2.2 电源与USB供电

这个设备完全由USB供电,不需要外部电源。USB的5V经过一个LDO(低压差线性稳压器)降到3.3V,给整个系统供电。这种设计很简洁,插上电脑就能用。

提示:焊接时要注意,原理图上有几个测试电阻是不需要焊的,比如顶板的R7、R8,底板的BOOT0_TEST和R_RESERVE1。别多焊了零件。

2.3 第一次使用的烧录接口

板子上留了一个排针接口,在SD卡槽下方。这个接口有两个作用:

  1. 第一次烧录BootLoader:用ST-Link或DAP-Link通过SWD接口烧录
  2. 调试接口:保留了SWD和串口1,方便二次开发

重要:BootLoader烧录成功后,这个排针就可以拆掉了,以后都用拖拽方式升级。当然,如果你想保留调试功能,也可以不拆。

3. 软件架构:BootLoader与APP的双重奏

这个项目的软件设计采用了经典的BootLoader + APP架构。理解这个架构是理解整个项目的关键。

3.1 Flash空间分配

STM32F103RCT6有256KB的Flash,被划分成了三个区域:

地址范围大小用途
0x0800 0000 - 0x0800 FFFF64KBBootLoader程序
0x0801 0000 - 0x0803 FFFF192KB用户APP程序
(外部Flash) W25Q648MBAPP程序文件临时存储

为什么要用64KB给BootLoader?因为BootLoader要实现USB MSC设备、文件系统操作、CRC校验、程序跳转等功能,代码量不小。192KB给用户程序,对于大多数应用来说足够了。

3.2 BootLoader工作流程

BootLoader就像是设备的“引导程序”,它负责检查有没有新程序要更新,有的话就更新,没有就直接跳转到APP运行。具体流程如下:

  1. 上电启动:芯片从0x0800 0000开始执行(BootLoader地址)
  2. 检查升级模式:检测按键是否按下,决定进入哪种模式
  3. 正常模式:直接跳转到APP(0x0801 0000)执行
  4. 升级模式:模拟U盘,等待用户拖入.bin文件
  5. 文件处理:将.bin文件从SD卡读到外部Flash,校验CRC
  6. 程序更新:将外部Flash中的程序写入到APP Flash区域
  7. 跳转执行:重启或直接跳转到新程序

进入BootLoader升级模式的方法很简单:按住滚轮按键,然后给设备上电。这时电脑会识别出一个名为“BOOT”的U盘。

3.3 APP程序结构

APP程序就是用户实际运行的功能程序,包含三合一USB设备、OLED界面、灯带控制等所有功能。APP工程基于一个开源的OLED UI框架——WouoUIPage,作者说之后会更新到2.0版本。

APP需要编译成.bin文件,并且在文件末尾附加整个文件的CRC32校验值。这是为了确保文件在传输过程中没有出错。

4. 关键代码解析:看看具体怎么实现

光讲原理不够,咱们得看看代码是怎么写的。我挑几个关键部分讲讲。

4.1 进入BootLoader升级模式的检测

检测按键决定是否进入升级模式,这个逻辑在BootLoader的main函数开头:

int main(void) { // 初始化系统时钟、GPIO等 SystemInit(); GPIO_Init(); // 检查按键是否按下(PA8引脚) if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == 0) // 按键按下为低电平 { // 进入USB MSC模式,模拟U盘 Enter_USB_MSC_Mode(); } else { // 检查APP是否有效(CRC校验) if (Check_APP_Valid()) { // 跳转到APP执行 JumpTo_APP(); } else { // APP无效,也进入升级模式 Enter_USB_MSC_Mode(); } } // 正常情况下不会执行到这里 while(1); }

4.2 三合一USB设备的配置

实现三种USB设备同时工作,需要配置USB复合设备描述符。这是USB协议栈的核心:

// USB设备描述符 const uint8_t USBD_DeviceDesc[] = { 0x12, // 描述符长度 0x01, // 设备描述符类型 0x00, 0x02, // USB协议版本 (2.00) 0xEF, // 设备类 (Miscellaneous) 0x02, // 设备子类 0x01, // 设备协议 0x40, // 最大包大小 (64字节) // ... 其他字段 }; // 配置描述符 - 包含三个接口 const uint8_t USBD_ConfigDesc[] = { // 配置描述符头 0x09, // 长度 0x02, // 类型(配置) // ... 总长度等字段 // 接口0: MSC (U盘) 0x09, // 接口描述符长度 0x04, // 接口描述符类型 0x00, // 接口编号 0x00, // 备用设置 0x02, // 端点数量 0x08, // 接口类 (Mass Storage) 0x06, // 接口子类 (SCSI) 0x50, // 接口协议 (Bulk-Only) 0x00, // 接口描述符索引 // 端点描述符 (Bulk-IN, Bulk-OUT) // ... // 接口1: HID (多媒体控制) 0x09, // 接口描述符长度 0x04, // 接口描述符类型 0x01, // 接口编号 0x00, // 备用设置 0x01, // 端点数量 0x03, // 接口类 (HID) 0x00, // 接口子类 (无) 0x00, // 接口协议 (无) 0x00, // 接口描述符索引 // HID描述符 // ... // 端点描述符 (中断IN) // ... // 接口2: CDC (虚拟串口) 0x09, // 接口描述符长度 0x04, // 接口描述符类型 0x02, // 接口编号 0x00, // 备用设置 0x02, // 端点数量 0x02, // 接口类 (Communications) 0x02, // 接口子类 (ACM) 0x01, // 接口协议 (AT命令) 0x00, // 接口描述符索引 // CDC特定的描述符 // ... // 数据接口描述符 // ... // 端点描述符 (Bulk-IN, Bulk-OUT, 中断IN) // ... };

配置描述符告诉电脑:“我这个设备有三个功能”,电脑就会加载相应的驱动程序。

4.3 WS2812灯带控制

WS2812的控制需要精确的时序,通常用PWM+DMA的方式。这里是一个简单的控制函数:

// WS2812时序参数(单位:ns) #define T0H 350 // 0码高电平时间 #define T0L 800 // 0码低电平时间 #define T1H 700 // 1码高电平时间 #define T1L 600 // 1码低电平时间 #define RESET 50000 // 复位时间 // 发送一个字节到WS2812 void WS2812_SendByte(uint8_t byte) { for (int i = 7; i >= 0; i--) { if (byte & (1 << i)) // 当前位是1 { // 发送1码:高电平T1H,低电平T1L GPIO_SetBits(GPIOB, GPIO_Pin_1); // 拉高 Delay_ns(T1H); // 保持高电平 GPIO_ResetBits(GPIOB, GPIO_Pin_1);// 拉低 Delay_ns(T1L); // 保持低电平 } else // 当前位是0 { // 发送0码:高电平T0H,低电平T0L GPIO_SetBits(GPIOB, GPIO_Pin_1); // 拉高 Delay_ns(T0H); // 保持高电平 GPIO_ResetBits(GPIOB, GPIO_Pin_1);// 拉低 Delay_ns(T0L); // 保持低电平 } } } // 设置一个灯珠的颜色(GRB顺序) void WS2812_SetColor(uint8_t red, uint8_t green, uint8_t blue) { WS2812_SendByte(green); // WS2812是GRB顺序,不是RGB! WS2812_SendByte(red); WS2812_SendByte(blue); } // 发送复位信号 void WS2812_Reset(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_1); // 拉低 Delay_ns(RESET); // 保持低电平足够长时间 }

注意:WS2812的数据格式是GRB(绿-红-蓝),不是常见的RGB。这个坑我踩过,调了半天颜色都不对,最后才发现顺序错了。

4.4 生成带CRC校验的.bin文件

要让BootLoader能校验APP文件的完整性,需要在.bin文件末尾附加CRC32值。可以在Keil中添加一个后处理命令:

# 这是一个批处理文件的内容(post_build.bat) fromelf --bin -o ".\output\@L.bin" ".\output\@L.axf" checksum -p STM32F103RC -d ".\output\@L.bin"

或者在Keil的User选项卡中配置:

  1. After Build/Rebuild部分勾选Run #1
  2. 命令栏输入:fromelf --bin --output=.\output\project.bin .\output\project.axf
  3. 再添加一个Run #2,命令:checksum -p STM32F103RC -d .\output\project.bin

这样编译完成后会自动生成带CRC校验的.bin文件。

5. 使用与二次开发指南

5.1 第一次使用步骤

如果你拿到了焊接好的板子,需要按以下步骤初始化:

  1. 烧录BootLoader:通过SD卡槽下方的排针,用ST-Link或DAP-Link烧录BootLoader程序
  2. 进入升级模式:按住滚轮按键,插入USB线给设备上电
  3. 格式化U盘:电脑会识别出一个名为"BOOT"的U盘,提示格式化,直接格式化即可
  4. 复制setting文件夹:将项目中的setting文件夹(包含FATFS中文支持文件和配置文件)拖到BOOT盘中
  5. 拖拽升级APP:将编译好的APP.bin文件拖到BOOT盘中,设备会自动更新并重启

提示:如果没有setting文件夹,设备也能工作,但无法保存配置参数,FATFS也不能支持中文长文件名。

5.2 二次开发注意事项

如果你想基于这个项目开发自己的应用,有几个地方需要注意:

Flash空间分配

  • BootLoader占用0x0800 0000 - 0x0800 FFFF(64KB)
  • 你的APP要从0x0801 0000开始
  • 在Keil中需要修改Target选项中的ROM地址:
    • Start:0x08010000
    • Size:0x30000(192KB)

中断向量表重映射APP程序的中断向量表需要重定位到0x0801 0000,在system_stm32f10x.c中修改:

// 在SystemInit函数中重映射中断向量表 void SystemInit(void) { // ... 其他初始化代码 // 设置向量表偏移(对于APP程序) #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; #else SCB->VTOR = FLASH_BASE | 0x10000; // 偏移64KB #endif }

CRC校验你的APP.bin文件必须包含CRC32校验值在文件末尾。可以使用作者提供的脚本,或者参考安富莱电子的教程。

5.3 常见问题与调试技巧

问题1:拖拽升级后设备不工作

  • 检查.bin文件是否包含CRC校验
  • 尝试重新进入BootLoader模式(按住按键上电)再次升级
  • 检查外部Flash(W25Q64)是否焊接良好

问题2:USB设备识别不正常

  • 检查USB数据线,有些充电线只能充电不能传输数据
  • 尝试不同的USB端口
  • 在设备管理器中查看是否有未知设备

问题3:OLED不显示

  • 检查OLED是SSD1306还是SH1106,驱动略有不同
  • 确认I2C地址是否正确(通常是0x78或0x7A)
  • 检查上拉电阻是否焊接

问题4:WS2812灯珠不亮

  • 检查数据线连接方向,WS2812有数据输入和输出端,不要接反
  • 确认时序参数,不同批次的WS2812可能时序略有差异
  • 注意复位信号的时间要足够长(至少50μs)

6. 项目资源与后续改进

这个项目完全开源,所有资源都可以在立创开源平台找到:

  • 工程主页:立创开源平台搜索"基于Stm32的可拖拽文件升级的三合一USB读卡器"
  • BootLoader代码:https://gitee.com/silent-sheep/spark-plan_-usbboot-loader
  • APP程序代码:https://gitee.com/silent-sheep/spark-plan_-app
  • WouoUI框架:https://github.com/Sheep118/WouoUI-PageVersion

作者提到后续会改进的地方:

  1. 优化SD卡读写速度(目前比较慢)
  2. 修复CDC虚拟串口不定时重启的问题
  3. 可能会更换USB库以提高稳定性
  4. 完善WouoUIPage框架,发布2.0版本

这个项目最吸引我的地方是它把多个实用功能集成在一起,而且实现了拖拽升级这种开发者友好的特性。虽然还有些小问题需要完善,但作为学习USB复合设备、BootLoader设计的案例,已经非常完整了。

如果你对USB协议、嵌入式UI框架、或者BootLoader设计感兴趣,这个项目值得深入研究。你可以基于它开发自己的应用,比如做一个智能桌面控制器、多媒体遥控器,或者学习如何设计一个稳定的固件升级系统。

http://www.jsqmd.com/news/479351/

相关文章:

  • Qwen3.5-35B-A3B-AWQ-4bit多场景落地:零售货架图商品识别+缺货预警生成
  • CLIP-GmP-ViT-L-14中小企业AI方案:低成本部署跨模态语义搜索
  • 3大突破:WarcraftHelper让魔兽争霸3重获新生的现代解决方案
  • Phi-4-reasoning-vision-15B一文详解:视觉多模态模型在数字孪生系统中的感知中枢作用
  • 视频资源管理新范式:douyin-downloader的效率革命
  • Hunyuan-MT-7B-WEBUI新手必看:从部署到翻译,完整操作流程解析
  • 八卦键盘:面向嵌入式开发的模块化USB多主机键盘平台
  • MT4进阶实战:从EA策略编写到自动化交易部署
  • ARM架构中的堆栈指针(SP)管理:从原理到实践
  • 南北阁Nanbeige 4.1-3B部署详解:Windows系统C盘空间清理与优化策略
  • 智慧农田远程采集系统:双MCU+太阳能供电的嵌入式物联网方案
  • Kimi-VL-A3B-Thinking部署教程:单节点多实例部署,支持并发图文请求处理
  • Dify 2026缓存机制到底改了什么?——基于源码级diff(commit: d4f8a2c…)与OpenTelemetry链路追踪的逐行解读
  • 春联生成模型-中文-base基础教程:Python环境快速部署与调用指南
  • 立创EDA实战:TF读卡器模块硬件设计与固件烧录指南
  • Windows驱动清理与管理工具:如何安全清理过时驱动?
  • 低成本GPU方案:T4显卡运行实时手机检测镜像的显存与延迟实测
  • WarcraftHelper:现代设备上的魔兽争霸III增强工具
  • 罗技宏脚本场景化解决方案:从入门到精通的实战指南
  • Qwen3.5-27B从部署到应用:4小时搭建私有图文AI助手(含权限与审计配置)
  • CLIP-GmP-ViT-L-14图文匹配测试工具在Ollama本地模型管理中的集成
  • SMUDebugTool:解锁AMD Ryzen处理器潜能的专业调试工具
  • CocoPI-Zero:基于F1C200S的Linux嵌入式学习平台
  • Qwen3智能字幕系统Typora文档生成功能
  • Python+OpenCV实战:5分钟搞定彩色图转灰度图(附完整代码)
  • RK3566模块化嵌入式平台:掌机/平板/工控三模硬件设计
  • 时间序列预测模型评估指标:从理论到实战的全面解析
  • 解锁城通网盘全速下载:3种突破限制方案深度解析
  • 基于CLIP的文本编码:HY-Motion 1.0语义对齐能力解析
  • cv_resnet18_ocr-detection部署指南:轻松搭建本地OCR检测服务