1. 这个项目到底在折腾什么先坦白讲我第一次看到用 Arduino 接屏幕刷 B 站这个说法的时候脑子里蹦出来的第一个念头是这不扯吗Arduino UNO 那颗 ATmega328P16MHz 主频、2KB SRAM、32KB Flash连一张稍微大点的图片都存不下你让它去解码视频流、渲染网页这不是拿自行车上高速吗。但仔细一琢磨这个项目的核心逻辑其实不是让 Arduino 去跑 B 站而是让 Arduino 成为整个显示链路里的一个控制节点。真正干活的可能是另一台设备——手机、电脑、树莓派甚至是带视频输出能力的开发板。Arduino 在这里的角色更像是一个遥控器或者信号中转站负责处理 USB 通信、外设控制、按键输入这些它擅长的事情而视频解码和网络请求交给更有能力的设备去做。这个思路其实挺聪明的。我见过太多人一上来就想用单片机硬扛所有事情结果卡在性能瓶颈上出不来。换个角度想Arduino 最值钱的地方从来不是算力而是它那套极其成熟的 GPIO 控制、丰富的库生态、以及几乎零门槛的上手体验。把它放在合适的位置上它就能发挥出远超参数表的价值。这个项目适合什么人看如果你手头有 Arduino UNO 或者 UNO Q想折腾点有意思的东西同时对 USB 通信、外接显示、拓展坞这些概念有点好奇那这篇内容就是写给你的。不需要你懂视频编解码也不需要你会写安卓驱动我会把整个链路的每个环节拆开讲清楚包括我踩过的坑和最后怎么绕过去的。核心关键词先摆出来Arduino、UNO Q、USB、显示器、拓展坞。这五个词基本覆盖了整个项目的技术栈。下面我按实际搭建的顺序从整体设计思路开始一步步往下拆。2. 整体设计思路与方案选型2.1 为什么不让 Arduino 直接解码视频这个问题必须放在最前面说清楚不然很多人会在错误的方向上浪费大量时间。Arduino UNO 的 ATmega328P 是一颗 8 位 AVR 单片机最高运行频率 16MHzSRAM 只有 2KB。你知道 2KB 是什么概念吗一张 320x240 分辨率的 RGB565 图片光像素数据就要 320×240×2 153600 字节也就是 150KB。UNO 的 SRAM 连这张图的百分之一都装不下。更别提视频了一帧 1080P 的 YUV420 数据大概是 3MBUNO 得存 1500 次才能凑出一帧。所以Arduino 刷 B 站这个说法准确的理解应该是Arduino 作为整个系统的一个环节参与进来而不是独立完成所有工作。这就像你家里的遥控器不能自己放电视节目但它能控制电视去放节目。Arduino 就是那个遥控器只不过它控制的不只是开关和音量还包括信号切换、外设管理、甚至通过 USB 协议跟主机设备进行数据交互。我实际测试下来最稳定的方案是用一台性能足够的设备手机、笔记本、树莓派都行负责网络请求和视频解码Arduino 负责处理物理层的按键输入、屏幕背光控制、以及通过 USB 或串口跟主机设备通信。这样各司其职谁也别为难谁。2.2 UNO Q 在这套方案里的特殊价值普通 UNO 和 UNO Q 最大的区别在于UNO Q 板载了更强大的通信能力。我手头这块 UNO Q 支持 USB 主机模式和设备模式切换这意味着它可以作为 USB 主机去识别外接的键盘、鼠标、甚至某些型号的拓展坞。这一点在项目里非常关键。普通 UNO 你要接 USB 设备得额外加一块 USB Host Shield那东西价格不便宜而且库的兼容性一言难尽。UNO Q 原生支持就省事很多。我试过直接插一个带 HDMI 输出的拓展坞到 UNO Q 上虽然 UNO Q 本身没有视频输出能力但它能识别到拓展坞的 USB Hub 芯片并且可以通过 I2C 或 SPI 去读取拓展坞上的一些状态信息。这里有个细节值得注意UNO Q 的 USB 接口供电能力有限如果你接的拓展坞带 PD 快充功能一定要确认拓展坞支持独立供电否则 UNO Q 的 5V 稳压器可能会过热保护。我第一次测试的时候就是没注意这个拓展坞一插上去 UNO Q 就重启了后来换了个带外部供电的拓展坞才稳定下来。2.3 显示链路的三种可行架构经过反复折腾我总结出三种能跑通的架构各有优劣方案一主机直连显示器Arduino 做控制端这是最稳妥的方案。手机或电脑通过 HDMI 或 Type-C 直接连显示器Arduino 通过 USB 串口跟主机通信负责发送控制指令比如打开 B 站、切换视频。Arduino 这边接几个物理按键按一下就往串口发一条命令主机端写个小程序监听串口收到命令就执行对应操作。这个方案的好处是视频质量完全由主机和显示器决定Arduino 不参与任何视频处理稳定性极高。缺点是 Arduino 的角色比较边缘更像一个外接键盘。方案二Arduino 作为 USB 中转拓展坞做信号切换这个方案稍微复杂一点。拓展坞同时连接主机和显示器Arduino 通过 USB 控制拓展坞的输入源切换。比如你按一下 Arduino 上的按钮拓展坞就从 HDMI 1 切到 HDMI 2这样可以在不同信号源之间快速切换。我实测下来支持 USB 控制信号切换的拓展坞不多大部分廉价拓展坞的切换按钮是纯物理电路没有 USB 控制接口。如果你要玩这个方案买拓展坞之前一定要确认它有没有提供 USB HID 控制接口或者串口控制协议。方案三Arduino 驱动小尺寸 SPI 屏幕做辅助显示如果你不追求大屏看视频只是想用 Arduino 驱动一块小屏幕显示一些信息比如 B 站粉丝数、直播间弹幕那方案就简单多了。用 ILI9341 或 ST7789 这类 SPI 屏幕Arduino 通过 SPI 接口驱动配合 ESP32 做网络请求完全可行。这个方案我后面会详细讲因为它是最能体现Arduino 刷 B 站这个概念的实现方式——虽然屏幕小但确实是在显示 B 站的内容。2.4 关键器件的选型对比器件型号关键参数适用场景参考价格主控Arduino UNO QUSB Host/Device 可切换需要 USB 主机功能中高主控Arduino UNO R3ATmega328P 16MHz基础控制低主控ESP32双核 240MHz 带 WiFi需要网络功能低屏幕ILI93412.4寸 320x240 SPI小尺寸辅助显示低屏幕ST77891.3寸 240x240 SPI迷你显示低拓展坞带 PD 供电的 USB-C Hub支持 HDMI 输出信号切换中转接FT232RL 模块USB 转串口调试通信低转接CP2102N 模块USB 转串口调试通信低选型的时候有个原则先确定你要实现到什么程度再倒推需要什么器件。如果你只是想用 Arduino 控制电脑打开 B 站那一个普通 UNO 加一根 USB 线就够了。如果你想用 Arduino 驱动屏幕显示内容那就需要 SPI 屏幕加一个带网络能力的协处理器。3. 核心细节解析与实操要点3.1 USB 通信链路的关键参数整个项目里最容易出问题的环节就是 USB 通信。Arduino UNO 上的 USB 接口其实是通过一颗 USB 转串口芯片实现的常见的有 ATmega16U2官方板、CH340兼容板、FT232RL部分第三方板。这颗芯片负责把 USB 信号转成 TTL 串口信号给主控。这里有个很多人不知道的细节UNO 的 USB 转串口芯片和主控之间是串口通信波特率通常固定为 115200 或 9600。你在代码里写的Serial.begin(115200)设置的是主控的串口波特率但 USB 转串口芯片和电脑之间的通信速率是 USB 协议决定的不受这个波特率影响。所以有时候你改波特率发现通信还是正常的别惊讶那是因为 USB 那一段根本没变。如果你用的是 FT232RL 或 CP2102N 这类外置 USB 转串口模块需要注意驱动安装。Windows 10 以后系统自带 FT232R 和 CP2102 的驱动但某些精简版系统可能会缺。我遇到过一台工控机设备管理器里显示FT232R USB UART带黄色感叹号去官网下了驱动装上就好了。CP2102N 的驱动在 Silicon Labs 官网有安装的时候记得选对版本32 位和 64 位不通用。注意如果你在设备管理器里看到USB 转串口设备但端口号一直跳变大概率是驱动问题或者 USB 线质量太差。换一根带屏蔽的短 USB 线试试很多时候问题就出在线材上。3.2 拓展坞的 PD 供电与信号完整性带 PD 快充的拓展坞在这个项目里扮演的是信号枢纽的角色。它同时处理 USB 数据、HDMI 视频信号、PD 供电三件事内部其实是一个多路复用器加电源管理芯片。我拆过一个便宜的拓展坞里面用的是一颗国产的 Hub 芯片加一颗 HDMI 切换芯片PD 部分是一颗独立的协议芯片。这种设计的问题是当 PD 供电功率变化时比如你插上手机开始快充HDMI 信号可能会短暂中断。我实测的时候手机一插上拓展坞开始 18W 快充显示器就黑屏两秒然后恢复。后来换了一个带独立电源输入的拓展坞这个问题就没了。如果你要用拓展坞做信号切换一定要确认它的 HDMI 切换是硬件切换还是软件切换。硬件切换的延迟低但需要物理按钮软件切换可以通过 USB 控制但延迟高。我试过用 Arduino 通过 USB 发送 HID 命令去模拟按下拓展坞上的切换按钮延迟大概在 200ms 左右看视频的时候切换会有明显卡顿但用来切换输入源比如从电脑切到游戏机完全够用。3.3 SPI 屏幕的驱动要点如果你走的是方案三用 SPI 屏幕显示 B 站信息那屏幕驱动是核心。以 ILI9341 为例它支持 SPI 接口最高时钟频率大概在 40MHz 左右但实际用 Arduino UNO 驱动的时候SPI 时钟只能跑到 8MHz 左右再高就会花屏。接线方面ILI9341 需要以下引脚VCC 接 3.3V 或 5V看模块有没有电平转换GND 接地CS 片选接数字引脚 10RESET 复位接数字引脚 9DC 数据/命令选择接数字引脚 8MOSI 接数字引脚 11SCK 接数字引脚 13LED 背光接 3.3V 或通过 PWM 控制这里有个坑UNO 的 3.3V 输出电流有限大概只有 50mA 左右。ILI9341 的背光 LED 如果全亮电流可能超过 100mA。我一开始直接把 LED 引脚接到 3.3V屏幕亮是亮了但 UNO 的稳压器烫得厉害。后来改成从 5V 引脚接一个限流电阻到背光问题就解决了。限流电阻的计算方法是(5V - 3.2V) / 0.02A 90Ω选个 100Ω 的电阻就行。驱动库方面我用的是 Adafruit_ILI9341 和 Adafruit_GFX 这两个库。安装方法很简单在 Arduino IDE 的库管理器里搜名字就能找到。但要注意这两个库比较占空间UNO 的 32KB Flash 装完库之后大概只剩 10KB 左右给用户代码写复杂逻辑的时候要省着点用。3.4 网络请求的协处理方案Arduino UNO 本身没有网络能力要获取 B 站的数据必须借助外部模块。常见的有三种ESP8266 作为 WiFi 模块通过串口 AT 指令跟 UNO 通信。优点是便宜缺点是 AT 指令调试起来很烦而且 ESP8266 的固件版本不同AT 指令集可能有差异。ESP32 作为独立协处理器ESP32 自己跑网络请求把结果通过串口发给 UNO。这个方案最灵活ESP32 可以跑完整的 HTTP 客户端甚至能解析 JSON。我推荐用这个方案虽然成本高一点但省心。电脑或手机作为网关UNO 通过 USB 串口跟电脑通信电脑负责网络请求把结果转发给 UNO。这个方案适合桌面场景不适合独立运行。我实际用的是 ESP32 方案。ESP32 通过串口 2 跟 UNO 通信波特率 115200。ESP32 这边用 ArduinoJson 库解析 B 站 API 返回的 JSON 数据提取出粉丝数、播放量这些字段然后按约定格式发给 UNO。UNO 收到数据后刷新屏幕显示。提示B 站的 API 返回的 JSON 数据量可能比较大ESP32 的串口缓冲区默认只有 256 字节记得在代码里把缓冲区调大或者分片发送。我一开始没注意这个数据一长就丢包查了半天才发现是缓冲区溢出了。4. 实操过程与核心环节实现4.1 硬件连接与供电检查先把所有硬件摆出来。我用的配置是Arduino UNO Q 一块、2.4 寸 ILI9341 SPI 屏幕一块、ESP32 开发板一块、带 PD 供电的 USB-C 拓展坞一个、若干杜邦线和面包板。连接顺序很重要一定要先断电再接线。我见过太多人带电插拔杜邦线结果烧了引脚或者屏幕。第一步把 ILI9341 接到 UNO Q 上。按照前面说的引脚定义接好注意屏幕的 VCC 先接 3.3V 测试如果亮度不够再考虑接 5V 加限流电阻。第二步把 ESP32 跟 UNO Q 连起来。ESP32 的 TX2 接 UNO 的 RX数字引脚 0ESP32 的 RX2 接 UNO 的 TX数字引脚 1。但这样接有个问题UNO 的数字引脚 0 和 1 同时也是 USB 串口引脚接上 ESP32 之后USB 串口通信会受影响。所以更稳妥的做法是用 SoftwareSerial 库把 ESP32 接到 UNO 的其他数字引脚上比如引脚 2 和 3。第三步拓展坞连接。拓展坞的 USB-C 输入接电源适配器HDMI 输出接显示器USB-A 口接 UNO Q 的 USB 接口。这样 UNO Q 既能从拓展坞取电又能通过 USB 跟拓展坞通信。供电检查的时候用万用表量一下 UNO Q 的 5V 引脚和 3.3V 引脚电压。正常应该是 5.0V ± 0.2V 和 3.3V ± 0.1V。如果偏差太大检查电源适配器是不是功率不够。我用的适配器是 65W 的带一个 UNO Q 加一个 ESP32 加一块屏幕绰绰有余。4.2 Arduino 端代码框架UNO 这边的代码主要做三件事初始化屏幕、接收 ESP32 发来的数据、刷新显示。下面是我实际用的代码框架基于 Adafruit_ILI9341 库#include SPI.h #include Adafruit_GFX.h #include Adafruit_ILI9341.h #include SoftwareSerial.h #define TFT_CS 10 #define TFT_DC 8 #define TFT_RST 9 Adafruit_ILI9341 tft Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); SoftwareSerial espSerial(2, 3); // RX, TX String receivedData ; void setup() { Serial.begin(115200); espSerial.begin(115200); tft.begin(); tft.setRotation(1); tft.fillScreen(ILI9341_BLACK); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(2); tft.setCursor(10, 10); tft.println(Bili Monitor); tft.setTextSize(1); tft.setCursor(10, 40); tft.println(Waiting for data...); } void loop() { while (espSerial.available()) { char c espSerial.read(); if (c \n) { updateDisplay(receivedData); receivedData ; } else { receivedData c; } } } void updateDisplay(String data) { // 数据格式约定粉丝数,播放量,点赞数 int firstComma data.indexOf(,); int secondComma data.indexOf(,, firstComma 1); if (firstComma 0 secondComma 0) { String fans data.substring(0, firstComma); String views data.substring(firstComma 1, secondComma); String likes data.substring(secondComma 1); tft.fillRect(0, 60, 320, 120, ILI9341_BLACK); tft.setTextSize(2); tft.setCursor(10, 70); tft.setTextColor(ILI9341_CYAN); tft.print(Fans: ); tft.println(fans); tft.setCursor(10, 100); tft.setTextColor(ILI9341_GREEN); tft.print(Views: ); tft.println(views); tft.setCursor(10, 130); tft.setTextColor(ILI9341_YELLOW); tft.print(Likes: ); tft.println(likes); } }这段代码的逻辑很直白ESP32 通过串口发来一行以换行符结尾的数据格式是粉丝数,播放量,点赞数UNO 收到后解析并刷新屏幕对应区域。有个细节要注意tft.fillRect只刷新数据区域不要每次都fillScreen否则屏幕会闪得厉害。我一开始就是每次全屏刷新结果屏幕闪烁严重后来改成局部刷新就舒服多了。4.3 ESP32 端网络请求实现ESP32 这边负责连 WiFi、请求 B 站 API、解析 JSON、通过串口发给 UNO。代码稍微长一点核心部分如下#include WiFi.h #include HTTPClient.h #include ArduinoJson.h const char* ssid 你的WiFi名称; const char* password 你的WiFi密码; const char* apiUrl https://api.bilibili.com/x/relation/stat?vmid你的UID; void setup() { Serial.begin(115200); Serial2.begin(115200, SERIAL_8N1, 16, 17); // RX16, TX17 WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(WiFi connected); } void loop() { if (WiFi.status() WL_CONNECTED) { HTTPClient http; http.begin(apiUrl); int httpCode http.GET(); if (httpCode 200) { String payload http.getString(); DynamicJsonDocument doc(1024); deserializeJson(doc, payload); long fans doc[data][follower]; // 其他字段类似提取 Serial2.print(fans); Serial2.print(,); Serial2.print(0); // 播放量占位 Serial2.print(,); Serial2.println(0); // 点赞数占位 } http.end(); } delay(10000); // 每10秒刷新一次 }这里用到了 ArduinoJson 库安装的时候选 6.x 版本。DynamicJsonDocument 的大小要根据实际返回的 JSON 长度调整1024 字节对于 B 站的粉丝数接口够用了但如果你要请求更复杂的接口可能需要调到 2048 或更大。注意B 站的 API 有频率限制请求太频繁可能会被临时限制。我建议刷新间隔不要低于 5 秒10 秒比较稳妥。另外某些接口需要携带 User-Agent 头否则会返回 403。在 HTTPClient 里可以用http.addHeader(User-Agent, Mozilla/5.0)来设置。4.4 拓展坞信号切换的 Arduino 控制如果你想让 Arduino 控制拓展坞切换输入源需要先确认拓展坞支持 USB 控制。我手头这个拓展坞用的是 HID 协议按一下物理按钮会发送一个 HID 报告。用 USB 抓包工具抓一下就能看到报告格式。抓包我用的是 Wireshark 加 USBPcap在 Windows 上装好之后能直接抓 USB 流量。抓到的 HID 报告大概是这样的01 00 00 00 00 00 00 00第一个字节是报告 ID后面是按键状态。知道了格式之后用 Arduino 的 USB Host Shield 库或者 UNO Q 的原生 USB Host 功能就能模拟发送。不过说实话这个功能的实用性一般。除非你有特殊需求否则直接用拓展坞的物理按钮切换更简单可靠。Arduino 控制拓展坞更适合做自动化场景比如定时切换信号源、根据某个条件自动切换。4.5 整机联调与稳定性测试所有代码写完之后先分别测试每个模块。UNO 单独跑屏幕显示测试ESP32 单独跑网络请求测试确认各自都能正常工作之后再联调。联调的时候先上电 UNO 和屏幕确认屏幕显示正常。然后上电 ESP32观察串口输出确认 WiFi 连接成功并且能获取到数据。最后检查 UNO 屏幕上的数据是否更新。我连续跑了 72 小时做稳定性测试中间遇到过两次屏幕花屏重启后恢复。后来查出来是 SPI 线太长导致信号衰减把杜邦线换成短的屏蔽线之后就没再出现过。还有一次 ESP32 死机原因是 WiFi 断连后没有重连逻辑加上重连代码后解决了。功耗方面整机运行时的电流大概是 5V/0.8A 左右其中屏幕背光占了大头。如果你要用电池供电建议选 10000mAh 以上的移动电源续航大概能撑 8 到 10 小时。5. 常见问题与排查技巧实录5.1 屏幕不亮或花屏这是最常见的问题排查顺序如下先检查背光。把屏幕的 LED 引脚直接接 3.3V如果背光亮了但没显示说明是驱动问题。如果背光都不亮检查限流电阻和接线。再检查 SPI 通信。用示波器或者逻辑分析仪看 SCK 和 MOSI 引脚有没有波形。如果没有波形检查 CS 引脚有没有拉低DC 引脚电平是否正确。最后检查库的兼容性。不同批次的 ILI9341 模块可能用的是不同厂家的驱动芯片有些需要修改库里的初始化序列。我遇到过一块屏幕用 Adafruit 库怎么都不亮换成 TFT_eSPI 库就正常了。现象可能原因解决方法背光不亮供电不足或限流电阻过大检查 3.3V 输出电流减小限流电阻背光亮但白屏初始化失败检查复位引脚换驱动库花屏SPI 时钟过高或线太长降低 SPI 频率换短屏蔽线局部花屏内存不足减少全局变量用 PROGMEM 存常量颜色不对颜色格式不匹配检查是 RGB565 还是 BGR5655.2 USB 设备识别失败UNO Q 作为 USB 主机的时候如果插上设备没反应先看 UNO Q 上的电源指示灯有没有变暗。如果变暗了说明供电不足需要给拓展坞接外部电源。如果供电正常但设备识别不到检查 USB 设备的协议类型。UNO Q 的 USB Host 库对某些设备兼容性不好特别是那些需要特定驱动或者自定义协议的设备。我试过接一个 USB 摄像头UNO Q 能识别到设备但读不到数据后来查资料发现那个摄像头用的是 UVC 协议UNO Q 的库不支持。还有一个容易忽略的点USB 线本身。有些 USB 线只有充电功能没有数据传输功能插上去设备能充电但识别不到。换一根确认能传数据的线试试。5.3 串口通信丢包或乱码串口通信出问题九成是波特率不匹配或者地线没接好。先确认两边的波特率设置一致。UNO 和 ESP32 的串口波特率都要设成 115200而且数据位、停止位、校验位也要一致。SoftwareSerial 库的默认格式是 8N1跟硬串口一样。如果波特率没问题但还是乱码检查地线。UNO 和 ESP32 的 GND 必须连在一起否则电平参考不一致收到的数据就是乱的。我一开始忘了接地线调了半天以为是代码问题后来发现是硬件问题。丢包的话检查串口缓冲区大小。UNO 的硬串口缓冲区默认是 64 字节SoftwareSerial 的缓冲区可以自定义最大 256 字节。如果单次发送的数据超过缓冲区大小就会丢包。解决办法是分片发送每片不超过 32 字节接收端拼起来。5.4 WiFi 连接不稳定ESP32 的 WiFi 稳定性受环境影响很大。如果你发现 ESP32 经常断连先检查路由器是不是开了双频合一。ESP32 只支持 2.4GHz如果路由器把 2.4G 和 5G 合并成一个 SSIDESP32 可能会尝试连 5G 然后失败。解决办法是在路由器设置里把 2.4G 和 5G 分开ESP32 连 2.4G 的那个 SSID。另外ESP32 的天线是板载的如果放在金属外壳里信号会很差。我一开始把 ESP32 装在铁盒子里WiFi 信号只有一格拿出来之后满格。还有一点ESP32 在 WiFi 连接过程中如果长时间连不上看门狗会复位。所以在while (WiFi.status() ! WL_CONNECTED)循环里要加delay(500)喂狗否则 ESP32 会一直重启。5.5 拓展坞 PD 供电导致的重启这个问题我在前面提过但值得再强调一次。UNO Q 的 USB 接口供电能力有限如果拓展坞的 PD 协议协商过程中出现电压波动UNO Q 可能会因为欠压而重启。解决办法有两个一是用带独立电源输入的拓展坞让拓展坞自己供电不要从 UNO Q 取电二是在 UNO Q 的电源输入端加一个大电容比如 1000uF缓冲电压波动。我两个方法都用了现在整机连续运行一周都没有再出现重启。电容选 16V 耐压的电解电容就行正极接 5V负极接 GND注意极性不要接反。6. 几个容易被忽略的实操心得6.1 关于 UNO Q 的 USB Host 库选择UNO Q 的 USB Host 功能需要用到特定的库官方推荐的是 USBHost 库但实际用下来我发现它的兼容性一般。如果你接的是标准 HID 设备键盘、鼠标用官方库没问题。但如果接的是自定义设备或者需要批量传输的设备建议用 USB_Host_Shield_2.0 库虽然名字里有 Shield但它也支持 UNO Q 的原生 USB 接口。安装这个库的时候要注意它跟某些版本的 Arduino IDE 有冲突。我在 IDE 2.3 上装的时候报了一堆编译错误后来降到 IDE 1.8.19 就正常了。如果你也遇到类似问题可以试试换 IDE 版本。6.2 关于 SPI 屏幕的刷新率优化如果你觉得屏幕刷新太慢可以试试这几个优化手段把 SPI 时钟从默认的 4MHz 提到 8MHz刷新率能翻倍。但要注意有些屏幕模块在 8MHz 下不稳定需要实际测试。只刷新变化区域不要全屏刷新。比如粉丝数从 1000 变成 1001只需要刷新最后一位数字的区域前面的不用动。用tft.setTextColor(color, background)代替tft.setTextColor(color)这样绘制文字的时候会自动填充背景色省去一次fillRect调用。6.3 关于整机外壳的设计如果你打算把这个项目做成一个成品外壳设计要考虑散热和接口可达性。UNO Q 和 ESP32 都会发热尤其是 ESP32 在 WiFi 传输的时候芯片表面温度能到 50 度以上。外壳上要开散热孔或者用金属外壳辅助散热。接口方面USB 接口、电源接口、屏幕排线都要留出足够的空间。我第一版外壳做得太紧凑插拔 USB 线的时候经常碰到屏幕排线后来把外壳加宽了 5mm 才解决问题。6.4 关于代码的长期维护这个项目涉及 UNO 和 ESP32 两块板子的代码建议用 Git 做版本管理。我一开始嫌麻烦没弄后来改代码改乱了想回退都回不去。现在两块板子的代码放在同一个仓库的不同目录下每次改动都提交清爽很多。另外B 站的 API 可能会变建议把 API 地址和参数提取到单独的配置文件里不要硬编码在代码里。这样 API 变了只需要改配置文件不用重新编译烧录。6.5 关于扩展方向这个项目跑通之后可以往几个方向扩展加一个红外接收头用遥控器控制屏幕显示内容切换。加一个温湿度传感器在屏幕上同时显示环境数据。加一个蜂鸣器粉丝数突破某个阈值的时候响一下。加一个 SD 卡模块把历史数据记录下来做成趋势图。我目前在做的是加一个旋转编码器用来手动切换显示不同的 B 站数据粉丝数、播放量、点赞数、评论数。旋转编码器比按键好用可以连续调节而且带按下功能一个器件搞定选择和确认两个操作。最后分享一个我在调试过程中发现的小技巧如果你不确定 ESP32 发出来的数据格式对不对可以先用 USB 转 TTL 模块把 ESP32 接到电脑上用串口助手看原始数据。确认格式没问题之后再接到 UNO 上。这样排查问题的时候可以少走很多弯路不用每次都烧录 UNO 的代码。