用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 ArduinoJson3. 核心代码实现项目主要分为三个功能模块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].asString(); String temp doc[HeWeather6][0][now][tmp].asString(); 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元但获得的成就感和实用价值远超这个数字。