
1. 项目概述从“晴天娃娃”到桌面气象站几年前我还在用那种老式的机械温湿度计每天得凑近了看数据还不准。后来玩上了单片机第一个项目就是用DHT11做了个简陋的温湿度显示器虽然能用但总觉得差点意思——它只是个冷冰冰的数据终端。直到有一次看到女儿画的晴天娃娃突然有了灵感为什么不能做一个有“表情”、有“生命”的天气预报站呢它不仅能告诉我现在的温湿度还能用直观的“表情”预告接下来的体感变化放在桌角既是个实用的工具又是个有趣的摆件。这就是“晴天娃娃天气预报站”的由来。它的核心很简单一块ESP32-E开发板加上一个温湿度传感器。但它的“灵魂”在于我们赋予了数据以形象。ESP32-E作为主控负责读取传感器数据、进行简单的逻辑判断比如判断是“干燥舒适”还是“潮湿闷热”然后驱动一个OLED屏幕让上面的晴天娃娃露出微笑、皱眉或者打伞的表情。你甚至可以通过Wi-Fi将数据同步到手机端实现远程查看。这个项目非常适合刚接触物联网IoT和嵌入式开发的朋友它涵盖了硬件连接、传感器驱动、数据显示、逻辑判断乃至网络通信等多个基础且核心的环节做完这一个你对如何让硬件“活”起来会有全新的认识。2. 核心硬件选型与设计思路拆解2.1 主控芯片为什么是ESP32-E在众多MCU中选中ESP32-E是经过一番考量的。首先ESP32系列最大的优势在于其双核处理器和集成的Wi-Fi与蓝牙功能这为我们项目的可扩展性比如后续添加手机通知、数据上传云端埋下了伏笔。而ESP32-E作为ESP32系列的一个变种在保持核心功能的同时通常具有更优的功耗表现和更稳定的射频性能这对于需要长时间插电运行的桌面设备来说是个加分项。对比经典的Arduino UnoESP32-E的性能是碾压级的价格却相差无几。对比树莓派PicoESP32-E原生集成了无线模块无需额外添加在实现联网功能时更简洁、成本更低。对于我们的天气预报站ESP32-E的运算能力足以流畅处理传感器数据、运行显示逻辑以及轻量级的网络服务资源绰绰有余。注意市场上ESP32开发板型号繁多如ESP32-DevKitC、NodeMCU-32S等它们的主芯片可能是ESP32-D0WDQ6、ESP32-S3等。ESP32-E通常指采用ESP32-E芯片模组的开发板。购买时只要确认开发板搭载了ESP32系列芯片且带有Wi-Fi功能即可引脚定义可能略有不同但核心开发方式一致。2.2 传感器对决SHT4x vs DHT11如何选择这是本项目的关键决策点之一。网络热词中提到了SHT4x和DHT11它们代表了温湿度传感器的两个不同梯队。DHT11堪称“启蒙导师”。优点是极致便宜通常几块钱、接口简单单总线通信、资料巨多。但缺点也很明显精度较低温度±2°C湿度±5%RH、响应慢、测量范围窄且在高温高湿环境下容易漂移甚至损坏。它适合对精度要求不高、预算极其有限的纯学习场景。SHT4x系列如SHT40, SHT45则是“专业选手”。来自盛思锐Sensirion采用I2C数字接口精度高SHT40精度可达±0.2°C ±1.8%RH、响应速度快、长期稳定性好并且功耗极低。当然价格是DHT11的十倍甚至更高。对于“晴天娃娃天气预报站”我的建议是如果预算允许直接上SHT4x。理由有三第一我们追求的是“体验”精准的数据是良好体验的基础一个显示湿度60%但实际上可能55%或65%的设备会让人对其“预报”功能产生怀疑。第二SHT4x的I2C接口比DHT11的单总线更稳定编程更规范不易出现读取失败的问题。第三从学习角度掌握I2C通信这一标准协议比学习DHT11的私有单总线协议对未来做其他项目更有帮助。其他备选像SHT10是更早的型号精度和性能不如SHT4x而热词中“DHT11温湿度传感器STM32F1”或“DHT11和LCD1602”的组合更多是其他平台或显示方案的特定应用案例不影响我们基于ESP32的核心选择。2.3 显示与“灵魂”载体OLED屏幕的选择为了让晴天娃娃“活”起来一块像素密度足够的显示屏是必须的。这里我强烈推荐使用0.96英寸或1.3英寸的I2C接口OLED屏幕SSD1306驱动。这种屏幕分辨率通常是128x64足以显示一个生动的表情图标和清晰的数字数据。其优点是自发光、对比度高、可视角度大、功耗低且I2C接口只需要两根数据线SDA, SCL与ESP32连接可以和SHT4x传感器共用同一组I2C总线通过不同的I2C地址区分极大简化了布线。为什么不选LCD1602LCD1602是字符型屏幕只能显示固定的字符无法绘制自定义的晴天娃娃图案表现力大打折扣。而彩色TFT屏幕虽然更炫酷但驱动复杂、功耗高、成本也高对于这个以简洁、温馨为核心的项目来说有点“杀鸡用牛刀”。2.4 系统架构与供电设计整个系统的架构非常清晰SHT4x传感器和OLED屏幕通过I2C总线连接到ESP32-E。ESP32负责定时例如每5秒读取传感器数据根据一套预设的“舒适度算法”后文详述判断当前天气状态然后在OLED上更新对应的晴天娃娃表情和具体的温湿度数值。如果需要网络功能ESP32在空闲时间连接Wi-Fi可以将数据发送到指定的服务器或物联网平台。供电方面由于ESP32-E、SHT4x和OLED功耗都很低整个系统在正常工作模式下电流通常不超过150mA。因此使用一枚5V1A的USB电源适配器通过Micro-USB或Type-C口给开发板供电是最稳定、最方便的方案。如果追求桌面整洁也可以使用一个移动电源供电实现完全无线化。3. 硬件连接与电路搭建实操3.1 I2C总线连接详解ESP32-E的I2C引脚通常是固定的但不同开发板可能有不同标注务必查看你的板子原理图GPIO21通常作为I2C SDA数据线GPIO22通常作为I2C SCL时钟线我们需要将SHT4x传感器和OLED屏幕的SDA引脚都连接到ESP32的GPIO21SCL引脚都连接到GPIO22。这就构成了一个多设备的I2C总线。实操心得在面包板上搭建时务必为I2C总线加上上拉电阻。虽然很多模块板载了上拉电阻但为了稳定性尤其是在总线较长或设备较多时建议在SDA和SCL线上各接一个4.7kΩ或10kΩ的电阻连接到3.3V电源。这是避免I2C通信失败的最常见措施。电源连接将所有设备的VCC引脚连接到ESP32的3.3V输出引脚。将所有设备的GND引脚连接到ESP32的GND引脚。连线核对表设备引脚连接到ESP32-E说明SHT4x传感器VCC3.3V电源正极GNDGND电源地SDAGPIO21I2C数据线SCLGPIO22I2C时钟线OLED屏幕VCC3.3V电源正极GNDGND电源地SDAGPIO21I2C数据线与传感器并联SCLGPIO22I2C时钟线与传感器并联3.2 地址冲突检查与解决I2C设备都有唯一的地址。SHT4x的默认地址是0x44也可通过引脚配置为0x45。常见的0.96寸OLEDSSD1306驱动的I2C地址通常是0x3C。这两个地址不同因此可以挂在同一条总线上相安无事。连接好硬件后在上传代码前强烈建议先运行一个简单的I2C扫描程序来确认所有设备都被正确识别。这能提前排除接线错误、电源问题或设备损坏等故障。#include Wire.h void setup() { Serial.begin(115200); Wire.begin(); // 初始化I2C使用默认SDA21, SCL22 Serial.println(\nI2C Scanner开始扫描...); } void loop() { byte error, address; int nDevices 0; Serial.println(扫描中...); for(address 1; address 127; address ) { Wire.beginTransmission(address); error Wire.endTransmission(); if (error 0) { Serial.print(在地址 0x); if (address16) Serial.print(0); Serial.print(address, HEX); Serial.println( 发现设备); nDevices; } } if (nDevices 0) Serial.println(未发现任何I2C设备\n); else Serial.println(扫描完成\n); delay(5000); }上传代码后打开串口监视器波特率115200你应该能看到类似这样的输出在地址 0x3C 发现设备 在地址 0x44 发现设备这证明你的OLED屏幕和SHT4x传感器都已准备就绪。4. 软件环境配置与核心库安装我们将使用Arduino IDE进行开发这是对新手最友好的环境。4.1 安装ESP32开发板支持打开Arduino IDE点击文件-首选项。在“附加开发板管理器网址”中填入https://espressif.github.io/arduino-esp32/package_esp32_index.json如果已有其他URL用逗号隔开。点击工具-开发板-开发板管理器。搜索“esp32”找到由“Espressif Systems”提供的“ESP32”开发板包点击安装。4.2 安装必要的库本项目需要两个核心库SHT4x传感器库用于与SHT4x通信。在Arduino IDE中点击项目-加载库-管理库...搜索“SHT4x”选择由“Sensirion AG”发布的库进行安装。OLED显示库用于驱动SSD1306屏幕。同样在库管理中搜索“Adafruit SSD1306”并安装。安装时它会提示你同时安装依赖库“Adafruit GFX Library”务必选择“安装所有”。注意事项Adafruit SSD1306库安装后需要根据你的屏幕尺寸和I2C地址进行简单配置。我们将在代码部分详细说明。5. 核心代码实现与逻辑解析5.1 头文件引入与全局定义#include Wire.h #include Adafruit_GFX.h #include Adafruit_SSD1306.h #include SHT4x.h // 定义OLED屏幕参数 #define SCREEN_WIDTH 128 // OLED宽度单位像素 #define SCREEN_HEIGHT 64 // OLED高度 #define OLED_RESET -1 // 重置引脚-1表示共享Arduino重置引脚 #define SCREEN_ADDRESS 0x3C // OLED的I2C地址 // 初始化OLED对象 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire, OLED_RESET); // 初始化SHT4x对象 SHT4x sht4; // 定义舒适度阈值可根据个人体感调整 const float TEMP_COMFORT_LOW 18.0; const float TEMP_COMFORT_HIGH 26.0; const float HUMI_COMFORT_LOW 40.0; const float HUMI_COMFORT_HIGH 60.0; // 定义表情状态枚举 enum WeatherMood { SUNNY_SMILE, // 晴微笑 CLOUDY_NEUTRAL, // 多云中性 RAINY_SAD, // 雨悲伤 HOT_FROWN, // 热皱眉 COLD_SHAKY // 冷发抖 }; WeatherMood currentMood SUNNY_SMILE; float currentTemp 0.0; float currentHumi 0.0;这部分代码引入了所有必要的库定义了屏幕参数初始化了设备和变量。舒适度阈值是晴天娃娃“表情”算法的核心你可以根据自己所在地区的气候和体感进行微调。5.2 初始化设置setup函数void setup() { Serial.begin(115200); delay(100); // 给串口一点启动时间 // 初始化I2C总线 Wire.begin(); // 初始化OLED屏幕 if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F(SSD1306分配失败)); for(;;); // 卡死检查硬件连接 } Serial.println(OLED初始化成功); display.display(); // 显示Adafruit的启动logo delay(2000); display.clearDisplay(); // 清屏准备绘制 // 初始化SHT4x传感器 sht4.begin(); uint32_t serialNumber sht4.serialNumber(); Serial.print(SHT4x传感器序列号: 0x); Serial.println(serialNumber, HEX); // 设置SHT4x为高精度模式可选中等精度以降低功耗 sht4.setPrecision(SHT4X_HIGH_PRECISION); // 设置加热器关闭本项目不需要自加热功能 sht4.setHeater(SHT4X_NO_HEATER); // 显示启动画面 displayStartupScreen(); }setup()函数完成了所有硬件的初始化和自检。其中display.begin()函数如果失败最常见的原因是I2C地址错误或接线问题务必用之前的扫描程序确认。SHT4x的setPrecision函数允许你在精度和功耗之间做权衡对于桌面设备高精度模式是首选。5.3 核心逻辑数据读取与舒适度判断void readSensorAndJudgeMood() { uint16_t error; char errorMessage[256]; // 读取测量数据 error sht4.measureHighPrecision(currentTemp, currentHumi); if (error) { Serial.print(读取传感器错误: ); Serial.println(error); // 这里可以添加错误处理比如显示一个“错误”表情 return; } // 打印到串口监视器方便调试 Serial.print(温度: ); Serial.print(currentTemp); Serial.print( °C\t湿度: ); Serial.print(currentHumi); Serial.println( %); // 基于温湿度判断天气情绪核心算法 // 优先级极端不舒适 一般不舒适 舒适 if (currentTemp TEMP_COMFORT_HIGH 5 || currentHumi HUMI_COMFORT_HIGH 15) { currentMood HOT_FROWN; // 过热或过湿闷热 } else if (currentTemp TEMP_COMFORT_LOW - 5) { currentMood COLD_SHAKY; // 过冷 } else if (currentHumi HUMI_COMFORT_HIGH) { currentMood RAINY_SAD; // 潮湿可能下雨 } else if (currentTemp TEMP_COMFORT_HIGH || currentTemp TEMP_COMFORT_LOW || currentHumi HUMI_COMFORT_LOW) { currentMood CLOUDY_NEUTRAL; // 偏热、偏冷或偏干感觉一般 } else { currentMood SUNNY_SMILE; // 温湿度均在舒适区间 } }这是项目的“大脑”。它首先读取高精度的温湿度数据然后通过一系列if-else判断来决定晴天娃娃的表情。这个判断逻辑你可以尽情自定义。例如我这里将“过热过湿”和“过冷”设为最高优先级因为它们体感最差其次是“潮湿”然后是“轻微不舒适”最后才是“舒适”。这种分层判断逻辑比简单的二维区间判断更符合人的实际感受。5.4 图形界面绘制让娃娃“活”起来void drawWeatherDisplay() { display.clearDisplay(); // 清空上一帧画面 // 1. 绘制顶部边框或装饰线可选 display.drawRect(0, 0, display.width(), display.height(), SSD1306_WHITE); // 2. 根据情绪绘制晴天娃娃主体和表情 drawSunnyDoll(currentMood); // 3. 在右侧或下方绘制温湿度数据 display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(70, 10); // 设置文本起始位置 display.print(F(Temp:)); display.setCursor(70, 20); display.print(currentTemp, 1); // 显示一位小数 display.print(F( C)); display.setCursor(70, 35); display.print(F(Humi:)); display.setCursor(70, 45); display.print(currentHumi, 0); // 湿度显示整数 display.print(F( %)); // 4. 绘制状态描述文字 display.setTextSize(1); display.setCursor(10, 55); switch(currentMood) { case SUNNY_SMILE: display.print(F(Sunny Comfy!)); break; case CLOUDY_NEUTRAL: display.print(F(Not Bad...)); break; case RAINY_SAD: display.print(F(Rainy Damp)); break; case HOT_FROWN: display.print(F(Too Hot! _)); break; case COLD_SHAKY: display.print(F(Brrr...Cold!)); break; } display.display(); // 将缓冲区内容发送到屏幕显示 } // 绘制晴天娃娃的函数示例需自己绘制或找点阵图 void drawSunnyDoll(WeatherMood mood) { // 这里是一个简化的示例实际你需要用drawPixel, drawLine, drawCircle, drawBitmap等函数 // 绘制娃娃的圆头 display.fillCircle(32, 25, 15, SSD1306_WHITE); // 头 display.fillCircle(32, 25, 14, SSD1306_BLACK); // 镂空中心形成圆环效果简易版 // 根据情绪绘制表情 switch(mood) { case SUNNY_SMILE: // 画微笑的眼睛和嘴 display.fillCircle(27, 22, 2, SSD1306_WHITE); // 左眼 display.fillCircle(37, 22, 2, SSD1306_WHITE); // 右眼 display.drawArc(32, 28, 8, 4, 180, 360, SSD1306_WHITE); // 微笑的嘴需自定义drawArc函数或使用其他方式 // 可以在头顶画个小太阳 for(int i0; i8; i) { float angle i * 45 * 3.14159 / 180; int x1 32 cos(angle) * 20; int y1 25 sin(angle) * 20; int x2 32 cos(angle) * 25; int y2 25 sin(angle) * 25; display.drawLine(x1, y1, x2, y2, SSD1306_WHITE); } break; case RAINY_SAD: // 画悲伤的眼睛和嘴 display.fillCircle(27, 22, 2, SSD1306_WHITE); display.fillCircle(37, 22, 2, SSD1306_WHITE); display.drawArc(32, 30, 8, 4, 0, 180, SSD1306_WHITE); // 向下的弧线表示悲伤 // 画雨滴 display.fillCircle(20, 10, 2, SSD1306_WHITE); display.fillCircle(35, 5, 2, SSD1306_WHITE); display.fillCircle(45, 12, 2, SSD1306_WHITE); break; case HOT_FROWN: // 画皱眉的眼睛和嘴 display.fillCircle(27, 20, 2, SSD1306_WHITE); // 眼睛位置稍高 display.fillCircle(37, 20, 2, SSD1306_WHITE); display.drawLine(25, 30, 39, 30, SSD1306_WHITE); // 一条横线表示皱眉的嘴 // 画汗滴 display.fillTriangle(40, 15, 42, 18, 38, 18, SSD1306_WHITE); break; // ... 其他表情类似需要你发挥创意绘制 default: // 默认中性脸 display.fillCircle(27, 22, 2, SSD1306_WHITE); display.fillCircle(37, 22, 2, SSD1306_WHITE); display.drawLine(28, 30, 36, 30, SSD1306_WHITE); // 一条短横线 break; } }图形绘制是项目中最有趣也最体现个性的部分。Adafruit_GFX库提供了丰富的绘图函数。对于复杂的晴天娃娃图案更高效的做法是使用取模软件如LCD Assistant将一张黑白图片转换成位图数组然后用display.drawBitmap()函数直接显示。这里为了代码清晰我用基本图形函数做了示意。你可以先画在纸上或用绘图软件设计好再转化为代码。5.5 主循环与节奏控制void loop() { // 1. 读取传感器并判断情绪 readSensorAndJudgeMood(); // 2. 在OLED上更新显示 drawWeatherDisplay(); // 3. 控制更新频率每5秒更新一次 delay(5000); // 可选未来可以在这里添加Wi-Fi上传数据的代码 // if (WiFi.status() WL_CONNECTED) { // uploadDataToCloud(currentTemp, currentHumi); // } }主循环控制着整个设备的节奏。delay(5000)意味着每5秒更新一次数据。对于室内环境监测这个频率足够了既能及时反映变化又不会让传感器和屏幕过度工作。你也可以用millis()函数实现非阻塞的定时让程序结构更优为后续添加网络功能留出时间片。6. 进阶功能添加Wi-Fi与远程查看让晴天娃娃“上网”是ESP32的天然优势。这里简述一下思路你可以选择将数据上传到免费的物联网平台如ThingsBoard、Blynk、SIoT等或者自己搭建一个简单的MQTT服务器。6.1 连接本地Wi-Fi首先在代码开头添加Wi-Fi库和配置你的网络信息#include WiFi.h const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码;在setup()函数中加入连接代码void setup() { // ... 其他初始化代码 ... // 连接Wi-Fi WiFi.begin(ssid, password); Serial.print(正在连接到Wi-Fi); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(\n连接成功); Serial.print(IP地址: ); Serial.println(WiFi.localIP()); }6.2 数据上传到物联网平台以ThingsBoard为例在ThingsBoard官网创建账户和设备获取设备访问令牌。安装ThingsBoard的Arduino客户端库通过库管理器搜索“ThingsBoard”。在代码中初始化并发送数据#include ThingsBoard.h #define TB_SERVER demo.thingsboard.io // 或你的私有服务器地址 #define TB_PORT 1883 #define TB_TOKEN 你的设备令牌 WiFiClient espClient; ThingsBoard tb(espClient); void uploadToThingsBoard() { if (!tb.connected()) { if (!tb.connect(TB_SERVER, TB_TOKEN, TB_PORT)) { Serial.println(连接到ThingsBoard失败); return; } } // 构建JSON数据 String telemetry {\temperature\: String(currentTemp) ,\humidity\: String(currentHumi) }; // 发送数据 tb.sendTelemetryJson(telemetry.c_str()); Serial.println(数据已上传); tb.loop(); // 处理MQTT循环 }然后在loop()函数中以较慢的频率比如每30秒或每分钟调用一次uploadToThingsBoard()函数即可。这样你就可以在ThingsBoard的仪表板上实时看到桌面的温湿度变化曲线了。7. 外壳制作与桌面美化硬件和软件都完成后一个精致的外壳能让你的天气预报站从“开发板堆”变成真正的“桌面艺术品”。材料选择3D打印这是最理想的方式。你可以在Thingiverse等网站搜索“ESP32 case”找到很多现成模型或者用Fusion 360、Tinkercad等软件自己设计一个带有晴天娃娃镂空窗口的盒子。亚克力板激光切割设计一个多层结构将屏幕、主板、传感器分层固定显得非常极客和精致。手工改造利用现成的礼品盒、小木盒甚至乐高积木进行改造。在正面开一个窗口露出屏幕内部用热熔胶或螺丝固定电路板。布局要点散热确保ESP32芯片和电源部分有一定的通风空间。传感器位置温湿度传感器SHT4x的探测头不要被封闭在盒子内部最好有开孔或将其引到外壳外部以避免测量值受设备自身发热影响。屏幕视角将OLED屏幕固定在与人眼平视最佳的角度。电源线管理设计好电源线的出口保持桌面整洁。8. 常见问题排查与优化技巧在实际制作过程中你可能会遇到以下问题问题现象可能原因排查与解决OLED屏幕不亮或白屏1. 电源接错接了5V2. I2C地址不对3. 初始化失败1. 确认VCC接3.3V。2. 运行I2C扫描程序确认地址多为0x3C或0x3D。3. 检查display.begin()函数参数和返回值。SHT4x读取失败返回01. I2C接线错误或松动2. 电源不稳3. 未安装上拉电阻1. 重新检查SDA、SCL接线。2. 确保供电稳定可用万用表测量3.3V电压。3. 在SDA和SCL上添加4.7kΩ上拉电阻到3.3V。温湿度数值明显不准1. 传感器受热源影响2. SHT4x精度模式设置错误1. 将传感器远离ESP32主板、电源等发热元件。2. 确认使用了SHT4X_HIGH_PRECISION模式。Wi-Fi连接不稳定1. 信号弱2. 路由器兼容性问题1. 尝试将设备靠近路由器。2. 在代码中尝试设置静态IP或调整Wi-Fi模式如WiFi.mode(WIFI_STA)。画面闪烁或更新卡顿1. 主循环中有长延时阻塞2. 图形绘制过于复杂1. 将delay(5000)改为基于millis()的非阻塞定时。2. 优化drawSunnyDoll函数使用drawBitmap显示预渲染的位图效率远高于动态绘制基本图形。功耗偏高如使用电池1. OLED常亮2. Wi-Fi常开3. 传感器采样率过高1. 可让屏幕间歇性休眠display.ssd1306_command(SSD1306_DISPLAYOFF)。2. 仅在需要上传数据时连接Wi-Fi然后断开。3. 降低SHT4x精度模式或采样频率使用SHT4X_MED_PRECISION。优化技巧降低功耗如果打算用电池供电除了上述方法还可以将ESP32设置为深度睡眠模式定时唤醒测量和显示这样待机电流可以降到微安级别。增加交互添加一个按键短按切换显示信息如切换显示温度/湿度/舒适度指数长按进入Wi-Fi配置模式使用Web Server或SmartConfig。数据记录在ESP32上挂载一个微型SD卡模块将历史温湿度数据以CSV格式记录下来用于长期趋势分析。多房间组网制作多个晴天娃娃站让它们通过Wi-Fi将数据汇总到一个中心显示端如另一个带大屏幕的ESP32实现家庭环境监测网络。这个“晴天娃娃天气预报站”项目从硬件焊接、软件编程到外观设计完整地走完了一个物联网产品从概念到实物的闭环。它不仅仅是一个显示温湿度的工具更是你个人创意和技术的结合体。当你看着自己创造的“娃娃”随着天气变化而变换表情那种成就感和与物理世界交互的乐趣是单纯购买一个成品无法比拟的。希望这份详细的指南能帮你少走弯路顺利做出属于你自己的、有温度的桌面伙伴。