💡 划重点

  • 主控选用 ESP32,自带 WiFi,直接对接公交实时 API,无需额外联网模块。
  • 屏幕采用 ILI9341(2.4 寸 TFT),显示下一班公交到站倒计时及线路状态。
  • 按键唤醒:不插电时 ESP32 进入深度睡眠,按一下立即启动并刷新数据,功耗极低。
  • 全部物料成本控制在 75 元以内,适合上班族放在办公桌或玄关使用。
  • 核心难点在于 HTTP API 的解析与断网重试,以及按键唤醒后的快速加载。

需求洞察

目标用户:每天固定乘坐 1-2 路公交通勤的上班族,尤其在早晚高峰期对到站时间有强刚需。

真实痛点:手机查公交需要解锁、打开 App、输入线路,操作步骤多且容易忘记;候车亭电子屏信息不全,步行到站后才发现车刚走,白白浪费时间。

为什么值得做:桌面播报器固定在视野范围内,抬手即看,无需任何操作。ESP32 每次唤醒后自动拉取最新到站数据,屏幕显示“下一班 3 分钟后到达”,比手机更直观、更省心。而且这个项目成本低、技术栈成熟,非常适合作为入门级智能家居硬件练手,既能巩固嵌入式网络编程,又能产出每天真正用得上的工具。

方案设计

感知层:通过 HTTP GET 请求访问公交实时 API(如高德或公交公司开放接口),获取指定站点、指定线路下一班车的预计到达分钟数。ESP32 内置 WiFi 负责网络连接,按键作为物理感知触发信号。

控制层:ESP32 主循环解析 JSON 数据,提取到站时间、车辆距离、是否进站等关键字段;根据剩余时间切换显示颜色(>5 分钟绿色、2-5 分钟黄色、<2 分钟红色)并驱动蜂鸣器短鸣提醒。

执行层:ILI9341 TFT 屏幕绘制“线路号 + 倒计时 + 提示语”,同时可选控制 LED 灯闪烁。采用 TFT_eSPI 库,SPI 通信刷新帧率足够流畅。

日志/联网层:每次唤醒后自动记录本次请求状态(成功/失败、响应耗时、到站时间)到 ESP32 内置 NVS 闪存,可通过串口导出分析。断网时自动重试 3 次,失败则屏幕显示“网络异常”。

物料清单

物品 数量 用途 估算单价
ESP32 DevKit 开发板 1 主控,WiFi 与 GPIO 控制 ¥20
ILI9341 2.4寸 TFT 屏 1 信息显示 ¥30
轻触按键 1 唤醒/手动刷新 ¥1
蜂鸣器模块(带三极管驱动) 1 到站提醒 ¥2
面包板+杜邦线若干 1套 电路连接 ¥5
USB 数据线 1 供电 + 烧录 ¥3
亚克力透明支架/小盒子 1 桌面固定 ¥10
合计 ¥71(控制在 75 元内)

接线与结构

传感器/模块 ESP32 引脚
TFT SCK GPIO18
TFT MOSI GPIO23
TFT CS GPIO15
TFT DC GPIO2
TFT RST 接 3.3V
TFT 背光 接 3.3V(常亮)
按键 GPIO0(板载 Boot 按键复用,轻触即可)
蜂鸣器 GPIO4(PWM 输出)

按键直接复用 GPIO0 是有意为之:ESP32 在深度睡眠时,GPIO0 可作为 EXT1 唤醒源,且板载按键无需重新焊接,按下即进入 ESP32 的下载/唤醒模式,省去额外布线。蜂鸣器接 GPIO4 通过 PWM 输出不同频率提示音。TFT 的 RST 直接拉高,减少 GPIO 占用。整体结构为:屏幕背面用双面胶固定到亚克力支架,ESP32 与面包板藏在底座内,按键露出底座边缘,方便单手点按。

核心代码


#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TFT_eSPI.h>

const char* ssid = "your_wifi";
const char* password = "your_pass";
const char* apiUrl = "http://your_bus_api?line=127&station;=xx";

TFT_eSPI tft = TFT_eSPI();

void drawBusInfo(int minutes, bool isArriving) {
  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(2);
  tft.setTextSize(4);
  if (isArriving) {
  } else {
    tft.drawString(String(minutes) + " min", 20, 80);
  }
}

void fetchAndDisplay() {
  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["minutes"] | -1;
    bool arriving = doc["arriving"] | false;
    if (arriving) {
      ledcWrite(0, 128);  // GPIO4 PWM 蜂鸣器提醒
      delay(200);
      ledcWrite(0, 0);
    }
  } else {
    tft.fillScreen(TFT_BLACK);
    tft.setTextSize(2);
  }
  http.end();
}

void setup() {
  tft.init();
  tft.setRotation(1);
  pinMode(4, OUTPUT);
  ledcSetup(0, 5000, 8);
  ledcAttachPin(4, 0);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(100);
  fetchAndDisplay();
  esp_deep_sleep_start();  // 显示完成后进入睡眠
}

void loop() {
  // 唤醒后在 setup 中执行完毕后会自动进入下一次睡眠
}

调试步骤

  1. 硬件摸底:先用示例代码跑通 TFT 屏幕显示,确认 SCK/MOSI/CS/DC 接线顺序正确,屏幕背光亮且无花屏。若花屏,检查 CS 是否接错或 DC 电压。
  2. WiFi 联网:单独烧录 WiFi 扫描程序,确认 ESP32 能连接路由器。在串口监视器观察 IP 获取情况。
  3. API 数据解析:先用电脑浏览器访问 apiUrl,确认返回 JSON 格式;然后在 Arduino 中通过 deserializeJson 实验解析,串口打印 minutes 字段。
  4. 显示联调:将解析结果传给 drawBusInfo,观察不同数值下颜色变化是否符合预期。重点测试 0 分钟(进站)时的红色闪烁和蜂鸣器。
  5. 按键唤醒:烧录完整程序后断电。按一下 GPIO0 按键,观察是否在 2-3 秒内完成 WiFi 连接并刷新屏幕。若长时间无反应,检查 esp_sleep_enable_ext0_wakeup 是否误接高电平。

设计图

公交到站桌面播报器结构flow
1
感知输入(按键唤醒 / HTTP请求返回到站数据)
2
控制处理(ESP32 解析JSON、判断到站时间、预设显示策略)
3
执行反馈(ILI9341 绘制倒计时、蜂鸣器播报提醒)
4
数据上报(日志记录到NVS、串口输出调试信息)