💡 划重点
- 本方案面向每天依赖公交通勤的上班族,用 ESP32 搭配 ILI9341 彩色 TFT 屏,制作一个摆在桌面的公交到站播报器。设备平时处于深度休眠状态,早上按下唤醒键后,自动连接 WiFi 并通过 HTTP API 实时获取所选线路的预计到站时间,循环刷新显示剩余分钟数。全项目物料成本控制在 75 元以内,结构简单,无需焊接也能完成。
需求洞察
目标用户:每日固定时间出门、依赖 1‑2 条公交线路的上班族。
真实痛点:早晨时间紧张,频繁解锁手机查看公交到站容易打断出门节奏;手机通知容易被海量消息淹没,错过提醒;冬季或雨天,在手机地图上反复刷新体验极差。
为什么值得做:桌面播报器让信息“抬头即见”,减少手机依赖;ESP32 的深度休眠配合按键唤醒,几乎不耗电;75 元内的成本远低于商业智能屏,且完全可定制,适合极客和居家办公人群。
方案设计
整体采用四层架构:
- 感知层
通过 ESP32 内置 Wi-Fi 连接家庭路由器,使用 HTTP GET 请求公交实时到站 API(可申请高德或百度的公开接口,或自建简易转发服务)。JSON 数据包解析后提取目标线路、最近一辆车的距离站数或预计分钟数。
- 控制层
ESP32 主控作为核心。GPIO0 配置为 RTC 唤醒源,长按或短按唤醒深度休眠的芯片。唤醒后执行联网、拉取数据流程;若 30 秒内无新数据或用户未操作,自动再次进入深度休眠。GPIO 分配兼顾 SPI 屏与按键,避免干扰启动引脚。
- 执行层
ILI9341 2.8 寸彩色 TFT 屏显示:当前时间、线路名、剩余分钟数、车辆状态(“即将到站”、“还有 2 站”等)。颜色区分紧急程度,比如剩余<3 分钟显示红色背景。屏幕背光在休眠时关闭,唤醒后点亮。
- 日志/联网层
每次成功获取数据后,将时间戳、线路、到站分钟数通过串口打印,也可通过板载 LED 闪烁指示网络状态。后期可扩展将日志上传到本地 NAS 或 HomeAssistant,形成出行记录。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|---|
| 1 | ESP32-WROOM-32 开发板 | 1 | 主控与 Wi-Fi | 19 |
| 2 | ILI9341 2.8寸 TFT 屏(SPI) | 1 | 信息显示 | 28 |
| 3 | 轻触按键(6x6mm) | 1 | 唤醒按钮 | 0.5 |
| 4 | 面包板 + 杜邦线 | 若干 | 连接电路 | 5 |
| 5 | 10KΩ 电阻 | 1 | 按键上拉 | 0.2 |
| 6 | USB 供电线 | 1 | 供电 | 2 |
| 合计 | 54.7 |
*注:总成本远低于 75 元预算,可另配外壳或打印底座。*
接线与结构
遵循说明书中默认 GPIO,仅增加必用的上拉电阻。接线关系如下:
- TFT 屏幕
SCK → GPIO18
MOSI → GPIO23
CS → GPIO15
DC → GPIO2
RST → 可接 EN 或 3.3V(此处接 3.3V 保持不复位)
VCC → 3.3V
GND → GND
LED → 3.3V(可通过 GPIO 控制背光,但为简化暂接 3.3V)
- 按键
一端接 GPIO0,另一端接 GND;同时 GPIO0 与 3.3V 之间接 10KΩ 上拉电阻,确保未按下时保持高电平。ESP32 的 RTC 唤醒管脚复用 GPIO0,唤醒后程序检测按键短按次数可设置不同线路选择。
微调理由:GPIO0 作为启动模式引脚,外部上拉不影响芯片上电,且自带内部弱上拉,增加外部 10K 仅增强抗干扰。如此接线可在深度休眠下仍识别按键下降沿唤醒。
核心代码
以下给出基于 Arduino 框架的骨架代码,依赖 TFT_eSPI 库和 ArduinoJson 解析库。示例中配置高德 API 格式,请自行替换 API Key 和线路参数。
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
const char* ssid = "SSID";
const char* password = "PASS";
const char* apiUrl = "http://api.xxx.com/bus?line=102";
RTC_DATA_ATTR int bootCount = 0;
#define BUTTON_PIN 0
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE);
WiFi.begin(ssid, password);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 20) {
delay(500);
retry++;
}
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);
int minutes = doc["data"]["arrival_min"];
String line = doc["data"]["line_name"];
tft.fillScreen(TFT_BLACK);
tft.drawString("Line: " + line, 10, 40, 4);
tft.drawString("In " + String(minutes) + " min", 10, 90, 4);
}
http.end();
}
delay(30000); // 显示30秒
esp_deep_sleep_start();
}
void loop() {
// 未使用
}
*说明:* 程序从深度休眠唤醒后运行 setup(),网络失败则直接重进休眠,可通过串口检查状态。实际产品可加入按键消抖与线路切换逻辑,此处为简洁只展示单线路。
调试步骤
- 硬件检查:用万用表确认 3.3V、GND 无短路,TFT 背光亮起;按下按键时 GPIO0 电压由高变低。
- 固件烧录:在 Arduino IDE 中安装 ESP32 板包、TFT_eSPI 库、ArduinoJson 库。选择
ESP32 Dev Module,上传后打开串口监视器。 - Wi-Fi 连接:观察串口打印的 IP 地址,若持续连接失败,检查 SSID/密码,确认路由器 2.4GHz 频段开启。
- API 获取:先用浏览器或
curl测试 API 链接,确保 JSON 返回格式与代码一致。若解析失败,调整DynamicJsonDocument容量。 - 显示校验:观察屏幕是否出现线路与时间文字。如果背光亮无内容,检查 SPI 引脚顺序,或调整 TFT_eSPI 的 User_Setup 文件匹配 GPIO。
- 休眠唤醒:断开 USB 后重新上电,等待 30 秒屏幕熄灭,按下按键设备应重新亮起并刷新数据。