STM32F103实现USB副屏:基于CDC协议的嵌入式显示方案
1. 项目背景与核心概念
在嵌入式开发中,我们常常需要为设备增加一个简单的显示界面,用于输出调试信息、状态参数或作为小型人机交互终端。传统的方案是使用SPI或I2C接口的OLED屏幕,但这需要占用MCU的硬件外设引脚,并且显示内容通常需要开发者自己绘制,功能较为单一。你是否想过,能否利用手头最常见的STM32F103开发板,通过USB接口直接模拟成一个额外的电脑显示器,实现更丰富、更灵活的显示效果?这就是“USB副屏”项目的核心。
简单来说,USB副屏 是指将一个嵌入式设备(如STM32)通过USB接口连接到电脑,使其被电脑识别为一个额外的显示设备。电脑可以将特定的窗口或区域内容“投射”到这个副屏上,实现扩展桌面或镜像显示的功能。对于STM32F103而言,由于其内置了USB设备控制器,我们可以利用USB的HID(人机接口设备) 或更高效的自定义类协议,来接收来自电脑的显示数据,并驱动一块LCD屏幕进行实时渲染。
这个项目将STM32F103从一个简单的微控制器,转变为一个具备特定功能的USB外设。它解决了在没有复杂图形处理能力的MCU上,实现动态、高质量内容显示的难题。常见的应用场景包括:
- 嵌入式系统调试监视器:将关键的变量、日志、波形图实时显示在副屏上,无需连接串口助手。
- 小型信息看板:显示时间、天气、股票信息、服务器状态等。
- 游戏外设或仪表盘:为模拟飞行、赛车游戏提供额外的仪表数据显示。
- 创客教育与功能验证:深入学习USB通信协议和图形显示驱动,是综合性的嵌入式实战项目。
掌握这项技术,意味着你不仅能驱动一块屏幕,更能深入理解USB设备枚举、数据传输、以及帧缓冲渲染等核心嵌入式开发概念,极大提升工程能力。
2. 环境准备与版本说明
在开始动手之前,请确保你的软硬件环境已就绪。版本信息至关重要,不同的库和工具链版本可能导致编译或运行错误。
硬件清单:
- 主控芯片:STM32F103C8T6(蓝色战舰最小系统板)或STM32F103RET6(正点原子战舰板)等。核心是必须带有USB接口(通常是USB Device)和足够的RAM(至少20KB)与Flash。
- 显示屏幕:推荐使用SPI接口的TFT LCD屏幕,如ST7735S、ILI9341等。SPI接口占用引脚少,软件驱动成熟。确保屏幕分辨率不宜过高(如240x320以内),以适应STM32F103的性能和内存限制。
- USB连接线:一根Micro-USB数据线,用于连接开发板和电脑。
- 调试器:ST-Link V2或J-Link,用于程序下载和调试。
- 杜邦线:用于连接LCD屏幕与开发板。
软件环境:
- 集成开发环境(IDE):Keil uVision 5(MDK-ARM)或 STM32CubeIDE。本文示例将基于 Keil uVision 5 进行。
- STM32固件库:标准外设库(Standard Peripheral Library)或HAL库。HAL库抽象程度更高,移植方便,本文将以 STM32CubeMX 生成的HAL库代码为基础。
- STM32CubeMX:用于图形化配置芯片引脚、时钟、外设和中间件(包括USB)的工具。版本建议使用6.0或以上。
- USB驱动:当STM32作为自定义USB设备时,电脑端可能需要安装特定的驱动程序(如WinUSB、libusb)。我们将采用无需额外驱动的 USB HID 或 USB CDC(虚拟串口) 协议简化开发,但性能受限。对于高性能需求,需要开发自定义驱动,这超出了入门范围。
- 电脑端软件:需要一个能将电脑屏幕内容捕获并发送到USB端口的程序。我们可以用Python(
pywin32,opencv,pyserial)或C#等语言自行编写一个简单的发送端程序。
版本兼容性提示:STM32CubeMX和HAL库更新较快,部分函数名或配置方式可能随版本略有变化。如果遇到编译错误,请首先核对函数名与你的HAL库版本是否匹配。本文的代码思路和架构是通用的。
3. 核心原理与方案选择
实现USB副屏,本质上是建立一个从电脑到STM32的高速、稳定的单向图像数据流。我们需要拆解为几个关键部分:
3.1 系统架构
3.2 USB协议选择 这是项目的核心决策点,需要在易用性和性能之间权衡。
-
USB HID (人机接口设备):
- 优点:无需安装额外驱动,系统原生支持。协议栈简单。
- 缺点:带宽极低。全速USB(12 Mbps)下,中断传输方式每个帧(1ms)最大数据包仅为64字节。这意味着每秒最多传输64KB数据,对于图像传输来说是杯水车薪,仅适用于极低分辨率或极低刷新率的场景。
- 适用场景:传输简单的位图图标、少量字符或低分辨率黑白图像。
-
USB CDC (通信设备类,即虚拟串口):
- 优点:在大多数操作系统上可自动安装驱动,使用简单如同操作串口。批量传输(Bulk Transfer)模式理论带宽高。
- 缺点:实际传输速率受串口波特率概念和系统调度影响,稳定性不如纯批量传输。数据需要打包成串口数据帧格式。
- 适用场景:中等数据量传输,是平衡易用性和性能的折中方案。
-
USB 自定义类 + WinUSB/libusb:
- 优点:可以充分利用USB批量传输模式,达到理论最高速度(全速USB约1MB/s)。灵活性最高。
- 缺点:需要在电脑端安装自定义驱动程序(如使用Zadig工具替换为WinUSB或libusb),对用户不友好,开发复杂度高。
- 适用场景:对刷新率和分辨率有较高要求的项目。
对于入门和大多数应用,我们推荐先使用 USB CDC (虚拟串口) 方案。它避免了驱动开发的麻烦,性能足以驱动一块小尺寸LCD进行每秒数帧的更新,适合显示非高速动态画面。
3.3 图像数据传输与处理 直接传输原始RGB565位图(240x320x2=150KB)即使对于自定义类USB也很吃力。必须考虑压缩:
- 简单差分压缩:只发送与上一帧相比发生变化的部分(脏矩形)。这对于状态信息显示非常有效。
- 运行长度编码(RLE):对于连续相同颜色的区域压缩效果好。
- 设置命令协议:定义简单的协议,如
[命令头][X坐标][Y坐标][宽度][高度][像素数据...]。电脑端只发送需要更新的区域。
在我们的示例中,将采用一种分块传输+简单协议的方式,将屏幕分成若干块,轮流更新,以降低对瞬时带宽的要求。
4. 完整实战案例:基于USB CDC的简易副屏
我们将分步实现一个简易副屏。目标:电脑端发送指定区域的RGB565像素数据,STM32接收并显示在240x320的LCD上。
4.1 使用STM32CubeMX创建工程基础
- 新建项目:打开STM32CubeMX,选择你的芯片型号(如STM32F103C8T6)。
- 配置时钟:
- 在
RCC中,将HSE设置为Crystal/Ceramic Resonator。 - 在
Clock Configuration标签页,将系统时钟(SYSCLK)配置为72MHz。USB模块需要48MHz时钟,CubeMX会自动从PLL分频得到。
- 在
- 配置USB:
- 在
Connectivity下,启用USB。 - 在
Middleware部分
- 在