用ESP32和0.96寸OLED做个桌面小摆件:实时显示天气/时间(附完整源码)
用ESP32和0.96寸OLED打造智能桌面天气时钟(附完整项目源码)
在创客圈里,ESP32和OLED屏幕的组合堪称经典CP。今天我们就来玩点实用的——用这两样小东西做个能显示天气和时间的桌面摆件。这可不是简单的"Hello World"级别项目,而是一个融合了Wi-Fi联网、API调用、NTP时间同步等实用技术的完整解决方案。
1. 硬件准备与电路连接
先来看看我们需要哪些硬件材料:
- ESP32开发板(推荐使用NodeMCU-32S,自带USB转串口)
- 0.96寸OLED显示屏(SSD1306驱动,I2C接口)
- 微型面包板和杜邦线若干
- USB电源线(供电兼下载程序用)
接线示意图:
ESP32 OLED 3.3V --- VCC GND --- GND GPIO22 --- SCL GPIO21 --- SDA注意:不同型号的OLED屏引脚定义可能略有差异,购买时请确认是I2C接口的4针版本(VCC、GND、SCL、SDA)
实际连接时,建议先用万用表检查线路通断。我遇到过好几次因为杜邦线接触不良导致的显示异常,排查起来特别费时间。
2. 开发环境搭建
我们使用PlatformIO作为开发环境,它比Arduino IDE更适合管理依赖库。以下是具体配置步骤:
- 安装VSCode和PlatformIO插件
- 新建ESP32项目,修改platformio.ini配置文件:
[env:nodemcu-32s] platform = espressif32 board = nodemcu-32s framework = arduino lib_deps = adafruit/Adafruit SSD1306@^2.5.7 adafruit/Adafruit GFX Library@^1.11.3 bblanchon/ArduinoJson@^6.19.4- 安装必要的库:
pio lib install "Adafruit SSD1306" pio lib install "ArduinoJson"3. 核心代码实现
项目主要分为三个功能模块:OLED驱动、时间同步和天气获取。我们先从最基础的OLED显示开始。
3.1 OLED显示基础
创建oled_display.h头文件,初始化显示驱动:
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); void initOLED() { if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED分配失败"); for(;;); } display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(1); display.display(); }3.2 时间同步功能
ESP32可以通过NTP协议获取网络时间,首先需要连接WiFi:
#include <WiFi.h> #include <NTPClient.h> #include <WiFiUdp.h> const char* ssid = "你的WiFi名称"; const char* password = "你的WiFi密码"; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", 8*3600, 60000); void connectWiFi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } timeClient.begin(); } String getFormattedTime() { timeClient.update(); return timeClient.getFormattedTime(); }3.3 天气数据获取
我们使用和风天气的免费API获取实时天气数据:
#include <HTTPClient.h> #include <ArduinoJson.h> String apiKey = "你的API密钥"; String cityID = "城市ID"; String getWeatherData() { HTTPClient http; String url = "http://api.heweather.net/s6/weather/now?location=" + cityID + "&key=" + apiKey; http.begin(url); int httpCode = http.GET(); if(httpCode == HTTP_CODE_OK) { String payload = http.getString(); DynamicJsonDocument doc(1024); deserializeJson(doc, payload); String weather = doc["HeWeather6"][0]["now"]["cond_txt"].as<String>(); String temp = doc["HeWeather6"][0]["now"]["tmp"].as<String>(); return weather + " " + temp + "°C"; } return "获取失败"; }4. 功能整合与界面设计
现在我们把各个模块整合起来,设计一个简洁的显示界面:
void displayInfo() { display.clearDisplay(); // 顶部状态栏 display.setCursor(0, 0); display.print(getFormattedTime()); // 中间大字体显示日期 display.setTextSize(2); display.setCursor(0, 20); display.print("2023-07-15"); // 底部天气信息 display.setTextSize(1); display.setCursor(0, 50); display.print(getWeatherData()); display.display(); } void setup() { Serial.begin(115200); initOLED(); connectWiFi(); } void loop() { displayInfo(); delay(60000); // 每分钟更新一次 }5. 进阶优化技巧
基础功能实现后,我们可以进一步优化用户体验:
5.1 多页面切换
通过按钮实现不同信息页面的切换:
#define BUTTON_PIN 0 int page = 0; void checkButton() { if(digitalRead(BUTTON_PIN) == LOW) { page = (page + 1) % 3; delay(200); // 防抖 } } void displayPage() { switch(page) { case 0: displayClock(); break; case 1: displayWeather(); break; case 2: displaySensorData(); break; } }5.2 添加传感器数据
连接BME280传感器,显示温湿度:
#include <Adafruit_BME280.h> Adafruit_BME280 bme; void initBME280() { if (!bme.begin(0x76)) { Serial.println("找不到BME280传感器!"); } } String getSensorData() { return String(bme.readTemperature()) + "°C " + String(bme.readHumidity()) + "%"; }5.3 低功耗优化
对于电池供电的场景,可以启用ESP32的深度睡眠模式:
void deepSleep() { esp_sleep_enable_timer_wakeup(60 * 1000000); // 睡眠60秒 esp_deep_sleep_start(); }6. 外壳设计与成品展示
一个精致的项目少不了合适的外壳。这里分享几种常见方案:
- 3D打印外壳:使用FreeCAD或Tinkercad设计,预留屏幕开口和按钮孔位
- 亚克力拼接:激光切割亚克力板,用胶水粘合成立方体
- 创意改造:利用现成的相框或小盒子改造
材料清单:
- 3D打印耗材/亚克力板
- M2螺丝螺母套装
- 微型按键开关
- 防滑硅胶垫
最后完成的摆件可以放在书桌、床头或办公室,既实用又彰显极客气质。整个项目的物料成本不超过100元,但获得的成就感和实用价值远超这个数字。
