资讯动态

ESP32+ST7789桌面天气屏项目指南:从接线到避坑

发布时间:2026/10/27 7:48:06 来源:尧图企业网站定制
简介一份面向ESP32与ST7789彩色LCD驱动的嵌入式实践资料包围绕‘左面小电视’复古风格天气显示器的完整实现展开。内容涵盖ESP32 GPIO/SPI接口开发、ST7789驱动初始化与显示控制、天气API数据请求及JSON解析、像素化界面设计与定时刷新机制等关键环节也包含硬件接线思路与串口调试排错方法适合具备一定单片机基础、希望上手物联网显示项目的开发者参考学习。压缩包为RAR格式大小约132.38MB内部文件类型与数量暂未提供但整体目录结构围绕源码、配置与说明文档组织便于按模块查阅。该资源目前已有528人学习下载既能帮助理解嵌入式软硬件协同开发的完整流程也能为复刻同款小电视天气终端提供可直接参考的代码框架与实现思路。1. 左面小电视的三种叫法桌面天气屏为何值得折腾把一块 240x240 的 ST7789 屏幕接到 ESP32 上塞进一个 3D 打印的小盒子放在显示器左侧常年显示温度、湿度、天气图标和日历这就是很多人说的“左面小电视”。桌搭天气屏、桌面小电视叫法不同本质都是同一个 ESP32 项目用单片机和一块小屏把网络天气数据变成余光就能扫到的信息面板。这个标题里的“源码……资料总汇”意味着作者把能跑通的工程、接线说明、依赖库、图标字库都整理在了一起不用从零写驱动也不用对着数据手册猜寄存器。你只需要做四件事选对板子、接对线、改 WiFi 和城市代码、烧录剩下的问题大多出在“资料包和我手上的板子不完全一样”这篇文章就是把这类差异和坑提前摆出来。2. 硬件选型与接线ESP32 ST7789 的最小点亮方案2.1 ESP32 板子怎么选Flash 容量和串口芯片先看左面小电视这类资料总汇绝大多数是按“通用开发板”来写的最常见的基准是 ESP32-WROOM-32 模组的 DevKitC 或 NodeMCU-32S 板型。选板子时先看两个参数Flash 容量和 USB 转串口芯片。Flash 容量决定你能装下多少字库和位图资源。ST7789 的驱动本身不占多少空间天气逻辑也就几百行代码但如果资料包带的是全量中文字库或 LVGL 界面4MB Flash 刚够8MB 更宽裕。市面上容易踩坑的是“ESP32-S2”“ESP32-C3”这类模组被当成普通 ESP32 卖它们的引脚和 USB 烧录逻辑不一样资料包里的 Arduino 工程未必直接兼容。最稳妥的做法是买板子时确认芯片是 ESP32 双核经典款Flash 不小于 4MB。串口芯片方面CP2102 和 CH340 都常见区别只在于驱动。Windows 下 CH340 偶尔会被识别成未知设备装驱动后就能用CP2102 在 macOS 上更省心。资料总汇里的烧录步骤一般也默认这两种芯片不需要为了“烧录器”额外花钱。下面是我常用的一个参考接线配置注意不同源码包引脚定义可能不同最终以包里的 User_Setup.h 或 config.h 为准。2.2 ST7789 屏幕接线SPI 引脚映射表ST7789 屏幕的接口一般是 8 针 SPIVCC、GND、SCLK、MOSI、CS、DC、RST、BLK。ESP32 的硬件 SPI 引脚是固定的但片选、复位、背光这几个控制脚可以自由映射资料总汇里最常见的映射如下功能ST7789 引脚ESP32 GPIO备注电源VCC3V33.3V严禁接 5V地GNDGND与 ESP32 共地时钟SCLK/SCKGPIO18SPI 时钟数据MOSI/SDAGPIO23单向写屏足够片选CSGPIO5低电平有效数据/命令DC/RSGPIO2区分命令和数据复位RST/RESGPIO4高电平复位背光BLK/LEDAGPIO32可 PWM 调亮度也可直接接 3V3接线对应到代码里就是 TFT_eSPI 库的 User_Setup.h 配置。下面是我在工程里保留的片段// User_Setup.h 关键配置 #define ST7789_DRIVER #define TFT_WIDTH 240 #define TFT_HEIGHT 240 #define TFT_MOSI 23 #define TFT_SCLK 18 #define TFT_CS 5 #define TFT_DC 2 #define TFT_RST 4 #define TFT_BL 32这段配置的每个参数都对应一个硬件引脚MOSI 是数据线SCLK 是时钟线CS 选屏幕DC 告诉屏幕当前发的是命令还是像素数据RST 是复位。TFT_WIDTH 和 TFT_HEIGHT 必须和你买的屏幕分辨率一致240x240 的 ST7789 很常见也有 240x320 的型号写错会导致画面只显示一部分或滚动错位。2.3 供电与背光为什么屏幕一刷新板子就重启左面小电视最常见的硬件翻车不是接错线而是供电不足。ST7789 的逻辑电压是 3.3V背光 LED 的电流虽然不大但在 Wi-Fi 开启的瞬间ESP32 的峰值电流能到 300mA 以上屏幕背光再叠加进去劣质 USB 线或电脑前置 USB 口很容易把电压拉低现象就是屏幕一亮整板重启。正确的接法是ESP32 用 USB 或 5V 电源供电屏幕 VCC 接 ESP32 的 3V3 输出而不是单独找一根 5V 线。如果背光亮度调到最高时屏幕闪烁可以在背光引脚和 GND 之间加一个 10~100uF 的电解电容同时把背光 PWM 占空比控制在 80% 以内肉眼看不出来差别但对电源压力小很多。还有一点容易忽略屏幕排线尽量短杜邦线超过 15cm 时 SPI 时钟信号会劣化出现随机花屏。这些细节排查顺序要放在改代码之前。提示先点亮屏幕再接 Wi-Fi。资料包如果带了单独的屏幕测试例程一定要先跑通再集成天气逻辑能省掉一半排查时间。3. 源码总览与首烧用 Arduino 离线包把屏先点亮3.1 资料总汇里通常有哪些东西拿到“ESP32-ST7789左面小电视天气显示资料总汇”这个压缩包先别急着双击打开 .ino 文件。资料总汇的常见结构是这样的目录或文件作用.ino 或 src/Arduino 主程序含 WiFi、天气请求、界面刷新逻辑libraries/作者整理好的依赖库常见 TFT_eSPI、ArduinoJsonassets/ 或 data/天气图标、中文字库、背景位图docs/ 或 doc/接线图、烧录步骤、引脚对照表3D 打印模型外壳 stl 文件非必需但常被收录先看 libraries 目录里有没有 TFT_eSPI。这个库是 ST7789 驱动的事实标准几乎所有源码包都依赖它。如果 libraries 目录缺失就得自己去 Arduino IDE 的库管理器搜索安装这里的坑是IDE 默认下载源在国内可能很慢所以我一般建议直接用离线包方式安装。3.2 Arduino IDE 离线包和依赖库安装Arduino IDE 的 ESP32 支持包体积不小在线安装经常卡在下载阶段。常见做法是下载 esp32 Arduino 离线包把它手动解压到 Arduino15 目录。macOS 和 Windows 的路径不一样下面以 macOS 为例# 1. 创建 Arduino15 下的 esp32 硬件目录 mkdir -p ~/Library/Arduino15/packages/esp32/hardware/esp32 # 2. 把离线包内容复制进去离线包一般是整个 esp32 目录结构 cp -r ./esp32-arduino-offline/* ~/Library/Arduino15/packages/esp32/hardware/esp32/ # 3. 查看确认 tools、cores 等子目录都在 ls ~/Library/Arduino15/packages/esp32/hardware/esp32/esp32/Windows 用户把路径换成%LOCALAPPDATA%\Arduino15\packages\esp32\hardware\esp32把离线包解压到对应位置后重启 Arduino IDE工具菜单里就能看到 ESP32 系列开发板。这一步的本质是让 Arduino 的“板级支持包”找到编译工具链离线包和在线安装的唯一区别就是省去了网络下载。如果你更习惯 VS Code也可以装 PlatformIO用platformio.ini里的platform espressif32自动拉工具链但资料总汇的工程一般按 Arduino IDE 组织首烧阶段跟着 Arduino 走最少折腾。依赖库的安装我倾向于直接把资料包里的 libraries 复制进 Arduino 的库目录# 进入 Arduino 库目录 mkdir -p ~/Documents/Arduino/libraries # 将资料包内的 TFT_eSPI 和 ArduinoJson 复制过去 cp -r ./资料包/libraries/TFT_eSPI ~/Documents/Arduino/libraries/ cp -r ./资料包/libraries/ArduinoJson ~/Documents/Arduino/libraries/ # 确认目录存在 ls ~/Documents/Arduino/libraries复制后打开 Arduino IDE点“文件 - 示例”如果能看到 TFT_eSPI 的示例列表说明库已经被识别。要注意ArduinoJson 的版本直接影响代码写法。v6 旧版用StaticJsonDocumentv7 用统一的JsonDocument如果编译报错指向 JSON 相关行先看资料包里的libraries/ArduinoJson版本和主代码是否匹配别急着改代码。3.3 烧录的最小命令和串口验证安装好环境后烧录有两种方式图形界面点“上传”按钮或者用 arduino-cli 命令行。命令行更适合排查问题因为能直接看到编译报错# 安装 esp32 支持如果之前没装 arduino-cli core update-index arduino-cli core install esp32:esp32 # 编译工程fqbn 指定板型为 ESP32 Dev Module arduino-cli compile --fqbn esp32:esp32:esp32 ./leftTV # 上传--port 换成实际串口设备名 arduino-cli upload --fqbn esp32:esp32:esp32 --port /dev/ttyUSB0 ./leftTV--fqbn里的三个esp32分别是平台名、架构名、板型号。串口在 Linux 上一般是ttyUSB0或ttyACM0Windows 上是COM3或COM5。上传时如果日志卡在Connecting...说明芯片没进入下载模式这就是常见的 ESP32 自动下载电路问题后面的避坑章节会专门讲。烧录完成后立刻打开串口监视器波特率设成源码里Serial.begin()的参数通常是 115200。开机日志会打出芯片信息、Wi-Fi 连接状态、IP 地址看到这些就说明硬件链路通了。此时如果屏幕还是白屏问题大多出在 ST7789 的初始化参数而不是硬件接线。4. 天气数据链路API 选型、JSON 解析与刷新节奏4.1 天气 API 怎么选免费额度、返回字段和国内访问速度天气显示的数据源决定了这个项目“能不能用”。资料总汇里会写明它对接了哪个天气服务常见的有 OpenWeatherMap、和风天气、心知天气三类。它们的差别主要在免费额度、中文描述和国内访问速度服务免费额度返回语言备注OpenWeatherMap每分钟 60 次英文为主全球城市齐全调试方便和风天气按量付费/免费开发版中文国内城市数据细需要注册应用心知天气免费版限次数中文部分城市免费接口简单如果资料包默认的是 OpenWeatherMap而你在国内使用注意两点一是它返回的中文字段不一定完整干脆用英文城市名加langzh_cn参数二是免费 key 有调用频率限制刷新间隔别短于 10 分钟。如果资料包默认是国内服务那要改的是两个地方API 地址和 key城市名可以直接填“北京”这样的中文。4.2 用 ArduinoJson 拆分天气字段从 HTTP 响应到屏幕不管用哪家 API数据格式都是 JSON解析逻辑万变不离其宗。下面这段代码是 OpenWeatherMap 的典型写法#include WiFi.h #include HTTPClient.h #include ArduinoJson.h String city Beijing; String apiKey 你的APIKEY; String weatherUrl() { return http://api.openweathermap.org/data/2.5/weather?q city unitsmetriclangzh_cnappid apiKey; } void fetchWeather() { HTTPClient http; http.begin(weatherUrl()); http.setTimeout(5000); // 5 秒超时防止卡死 int code http.GET(); if (code ! HTTP_CODE_OK) { Serial.printf(HTTP error: %d\n, code); http.end(); return; } JsonDocument doc; DeserializationError err deserializeJson(doc, http.getString()); if (err) { Serial.println(JSON parse failed); http.end(); return; } float temp doc[main][temp].asfloat(); // 当前温度 int humi doc[main][humidity].asint(); // 湿度 String desc doc[weather][0][description].asString(); // 天气描述 // 这里把数据交给显示层 renderWeather(temp, humi, desc); http.end(); }代码里的deserializeJson把 JSON 文本解析成可查询的对象。doc[main][temp]对应的是 JSON 里多层嵌套结构先取 main 对象里的 temp 字段。asfloat和asint做类型转换避免把温度整数当成字符串显示。setTimeout(5000)很重要如果 Wi-Fi 弱或 API 无响应HTTPClient 默认可能等几十秒桌面上一个小电视卡在转圈比显示错误更难受。ArduinoJson 的坑在于版本差异。如果你用的是 v6 旧版代码里不会有JsonDocument而是DynamicJsonDocument doc(2048)加deserializeJson(doc, payload)。编译报错“JsonDocument was not declared”时优先检查库版本而不是硬改代码。4.3 NTP 时间同步时钟和天气的刷新节奏左面小电视不只有天气还有时钟。ESP32 没有 RTC 电池每次开机时间都是 1970 年必须从 NTP 服务器同步。同步代码一般是这样的#include time.h // 中国时区 UTC8无夏令时 #define MY_TIMEZONE_OFFSET (8 * 3600) void syncTime() { configTime(MY_TIMEZONE_OFFSET, 0, ntp.aliyun.com, pool.ntp.org); struct tm timeinfo; if (getLocalTime(timeinfo, 1000)) { Serial.printf(Local time: %04d-%02d-%02d %02d:%02d:%02d\n, timeinfo.tm_year 1900, timeinfo.tm_mon 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); } }configTime的第一参数是 UTC 偏移秒数第二参数是夏令时偏移。国内用东八区偏移就是 8 小时夏令时设 0。如果你用的是欧美的 NTP 服务器只是同步基准时间不影响偏移量。getLocalTime的第二个参数是等待毫秒数如果网络不通这个函数可能在阻塞一段时间后返回 false所以调用前最好先确认 Wi-Fi 已连接。刷新节奏是这里的设计重点时钟每秒刷新一次天气每 30 分钟拉取一次。天气接口刷新太快有两个后果一是免费 API 配额很快用完二是屏幕频繁全量刷新会消耗更多电流。代码里一般把天气请求放在主循环里加时间戳判断或者用millis()做非阻塞延迟避免delay(1800000)把整个系统卡死。5. 避坑白屏、乱码、掉线、烧录失败的 5 条排查记录5.1 白屏ST7789 初始化参数和复位脚没配对现象背光亮屏幕全白没有任何图案。原因最常见是 TFT_eSPI 的 User_Setup.h 里驱动型号和屏幕实际型号不一致或者 DC/RST 引脚没在代码里改。有些商家把 ST7789 的屏幕标成 ILI9341 卖程序按 ILI9341 驱动初始化输出全白。另一个原因是复位时序RST 引脚悬空时芯片上电状态不确定。解决打开 User_Setup.h确认#define ST7789_DRIVER这一行还在且没有同时定义 ILI9341_DRIVER。再检查 TFT_RST 是否接到了 GPIO4如果排线松了先碰一下复位脚看屏幕是否闪动。最后是 TFT_INVERSION_ON 的开关某些 ST7789 面板需要反色显示注释掉后从白屏变花屏那就反向操作。5.2 汉字显示为方块字库编码和接口语言不匹配现象温度、数字都正常但城市名或天气描述显示成空心方块、问号。原因TFT_eSPI 默认只内置英文字体中文字形要么用外部字库芯片要么在程序里放了点阵数组。资料包如果提供的是 GB2312 编码的字库而天气接口返回的是 UTF-8 字符串字节流对不上自然画不出正确字形。另一个隐蔽原因是 ArduinoJson 解析时按 UTF-8 处理但源码文件本身是 GBK 编码保存编译时字符串常量就乱了。解决在 Arduino IDE 里把编辑器编码设为 UTF-8重新保存 .ino 文件。如果资料包里带lv_font或font.h确认字库覆盖了你需要的那几个汉字比如“晴、雨、云、霾”。大多数资料包只做了 Limited 字库与其把所有中文都塞进去不如把城市名改成拼音UI 上只显示天气图标和数字。这条经验在新手阶段最实用。5.3 天气长期不更新HTTP 请求失败没有重试策略现象开机前几分钟正常两小时后天气停在同一个值时钟还在走。原因Wi-Fi 断线后 HTTPClient 请求失败代码里没有重连逻辑。ESP32 的 Wi-Fi 模块不会自动恢复WiFi.status()返回WL_CONNECTED但实际连接已假死这在路由器开启省电模式时更明显。解决主循环里每 5 秒检查一次WiFi.status() ! WL_CONNECTED触发重连if (WiFi.status() ! WL_CONNECTED) { Serial.println(WiFi lost, reconnecting...); WiFi.disconnect(); WiFi.reconnect(); delay(1000); }天气刷新函数里加重试次数上限连续 3 次失败就保留上次显示数据而不是把屏幕清成空白。配合看门狗esp_task_wdt_reset()放在主循环末尾防止 HTTP 卡死把整个系统拖崩。5.4 时间差八小时时区和夏令时配置不一致现象屏幕显示的时间比手机慢 8 小时或者每天早上快 1 小时。原因configTime()里时区偏移设置成了 0或者用了带夏令时的欧美时区规则。如果源码里调用的是configTime(0, 0, ntpServer)那拿到的就是 UTC 时间。解决把偏移改成8 * 3600夏令时偏移留 0。如果你所在地区采用夏令时需要把第二个参数填成3600或按当地规则切换。ESP32 的setenv(TZ, CST-8, 1)和tzset()也是常见做法比裸算偏移更直观。注意资料包如果面向海外作者默认很可能是 UTC这个必须改。5.5 烧录失败自动下载电路和手动进入下载模式的差别现象点上传按钮后串口反复输出A fatal error occurred: Failed to connect to ESP32: Timed out或者卡在Connecting........_____.....不动。原因ESP32 只有在 GPIO0 为低电平时才进入下载模式。开发板的自动下载电路通过 USB 转串口芯片的 DTR/RTS 信号控制 GPIO0 和 EN 引脚但不同板子的电路设计不一致使用劣质 USB 线或某些扩展坞时电平切换不可靠。解决手动进入下载模式按住 BOOT 键不放再按一下 EN 键松开然后松开 BOOT此时点击上传等日志出现Connecting... chip is ESP32后再松手。这一步能解决九成烧录失败问题。如果还不行换一根短的数据线并确认串口驱动是 CP2102 还是 CH340Windows 下 CH340 的旧驱动偶尔会丢字节装最新版即可。6. 进阶玩法让左面小电视从天气屏变成桌搭控制台6.1 本地温湿度把 ESP32 温湿度传感器并入显示天气接口给的是室外或区域数据桌面上摆一个小电视顺手接一个 DHT11 或 SHT30 就能显示室内温湿度。DHT11 接 GPIO15代码里加两行#include DHT.h DHT dht(15, DHT11); void setup() { dht.begin(); } void loop() { float t dht.readTemperature(); float h dht.readHumidity(); if (isnan(t) || isnan(h)) { Serial.println(DHT read error); } else { // 和天气数据一起渲染到屏幕 } }DHT11 的数据脚需要上拉电阻很多模块板上自带如果读出来恒为 0 或 NaN先查线。这块板子接了传感器后天气屏就变成了本地的微环境监测终端也算边缘感知的雏形。6.2 内嵌 Web 页面配网不重新烧录改 WiFi每次搬家换路由器都要改代码重烧体验很差。进阶做法是在 ESP32 上跑一个 WebServer开机后进入配网模式手机连上它的热点打开 192.168.4.1 提交 WiFi 账号密码存进 Preferences 里。这个功能网上叫“ESP32 配网”实现起来不算复杂核心是WebServer库加一个/路由返回表单页。我一般会把配网逻辑单独放一个.h文件项目里的话题就从“天气显示”升级成“可配置的桌面信息终端”。以后再接蓝牙音箱、氛围灯都是在这个 Web 配置页上扩展选项。6.3 OTA 升级和外壳打印后续投入的“后悔药”最后一个建议是加 OTA。把ArduinoOTA库加进来之后不接 USB 线也能从局域网推新固件改 UI、调字体、换 API 都方便得多。OTA 的两个坑是固件编译后体积不能超过当前分区表的上限以及升级失败后没有回退机制。保守做法是保留串口烧录线永远留一条物理后路。我自己做这个小电视时第一次犯的错就是跳过了屏幕测试例程直接烧完整工程结果白屏了三次才意识到是驱动型号选错。改成先把屏幕点亮、再接天气、最后加配网的三步走后面所有类似项目都顺了。资料总汇再全也不如自己手里一条稳定可复现的烧录路径。希望这篇笔记能帮你把这块小屏幕真正用起来做成工作台上那个一年到头都在运行的小角落。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑