
很多朋友第一次听到“嵌入式衣柜”可能会愣一下衣柜不是木工师傅做的吗跟嵌入式开发有什么关系其实这里说的“嵌入式衣柜”并不是装修术语而是一个结合了嵌入式系统、传感器和Web技术的智能家居小项目用一块ESP32开发板给普通衣柜加上温湿度监控、智能除湿、自动照明和远程状态查看的能力。这个项目非常适合嵌入式入门、物联网开发以及想给家里衣柜做智能化改造的开发者。它覆盖了传感器数据采集、执行器控制、Wi-Fi通信、Web页面展示等完整链路做完之后既能收获一个可用的智能衣柜设备也能把嵌入式开发的常见套路完整走一遍。1. 嵌入式衣柜是什么1.1 它到底解决什么问题普通衣柜的痛点其实很常见南方梅雨季节柜内湿度大衣物容易发霉时间长了还有一股霉味。衣柜深处光线暗找衣服需要手机照明翻东西全靠手感。密闭空间空气不流通衣服容易闷出异味。出门前想知道柜内温度和湿度是否合适只能打开柜门用体感判断。“嵌入式衣柜”就是把这些问题交给单片机来解决。它本质上是一个小型的智能环境监测与控制系统安装在衣柜内部持续采集温湿度、光照强度并根据预设条件自动执行除湿、通风和照明动作。从技术角度看这个项目的主控芯片选用ESP32原因是它价格便宜、开发资料多、自带Wi-Fi和蓝牙而且GPIO资源足够覆盖传感器、舵机和LED灯带。对于个人DIY项目来说ESP32是性价比极高的选择。1.2 整体技术架构整个系统可以分为三层感知层负责采集环境数据包括DHT22温湿度传感器和光敏电阻模块。控制层核心是ESP32主控芯片负责读取传感器数据、执行控制逻辑并通过Wi-Fi对外提供状态查询接口。执行层包括舵机控制通风挡板、WS2812B灯带照明、蜂鸣器可选告警。数据流方向可以概括为采集数据 → 主控分析 → 执行动作 → 返回结果值得注意的是这个数据流并不是单向的。ESP32连接家庭路由器的Wi-Fi之后手机或电脑可以通过浏览器访问开发板上的Web页面实时查看柜内状态也可以手动触发通风或照明。也就是说它既是一个自动控制系统也是一个可以被用户主动操作的物联网终端。2. 环境准备与硬件清单2.1 硬件准备下面列出本文使用的硬件实际购买时可以根据手头资源替换不需要完全一致硬件说明数量ESP32 开发板支持Wi-Fi和蓝牙IO丰富适合本项目1块DHT22 温湿度传感器数字单总线传感器精度高于DHT111个光敏电阻模块输出模拟量用于检测柜内光照1个SG90 舵机控制通风挡板开合1个WS2812B LED灯带带PWM控制的照明灯带可单点控制颜色1米5V/2A 电源给ESP32和灯带供电舵机需要额外供电时也用它1个面包板杜邦线连接电路若干DHT22和DHT11在代码层面几乎通用如果你手上只有DHT11也可以运行本文代码只需要修改宏定义即可。不过需要注意DHT11采样间隔是1秒DHT22是2秒代码里延时参数建议按2秒以上写避免接近极限值触发读取失败。2.2 软件环境开发环境建议选择 Arduino IDE 或 VS Code PlatformIO 插件。本文以 Arduino IDE 为例原因是它对新手最友好下载固件和查看串口输出都方便。需要安装的库DHT sensor libraryAdafruitAdafruit Unified Sensor LibraryDHT库的依赖库Adafruit NeoPixel驱动WS2812B灯带ESP32Servo驱动SG90舵机在 Arduino IDE 的“开发板管理器”中安装 esp32 板卡包时注意选择与你的开发板匹配的版本。不同版本的板卡包API可能有细微差异如果遇到编译报错优先检查板卡包版本。版本号这里不写死因为Arduino IDE和板卡包更新很快。只要你的环境能正常编译ESP32自带的Blink示例程序就可以继续。本文重点是配置思路和代码逻辑不是某个特定版本。2.3 项目文件结构本文采用Arduino的.ino单文件示例方便复制和上传。但为了可维护性实际项目建议拆分为多个文件embedded-wardrobe/ ├── embedded-wardrobe.ino ├── config.h ├── sensor.h ├── sensor.cpp ├── actions.h ├── actions.cpp └── web.h单文件演示时所有代码都放在 .ino 中适合快速测试。工程化改造时再拆分模块后面第 6 节会详细讲。3. 核心原理与知识点拆解3.1 温湿度采集DHT22DHT22 输出的是数字信号数据帧一共40位16位湿度数据、16位温度数据、8位校验和。它的优点是单总线通信只需一根数据线接到ESP32的GPIO代码层面通过DHT库读取非常方便。选用DHT22而不是DHT11的主要原因是精度和量程差异。参数DHT11DHT22湿度误差±5%±2%温度误差±2℃±0.5℃温度量程0~50℃-40~80℃采样间隔1秒2秒衣柜内部空间小温湿度变化平缓理论上两种传感器都可以使用。但从长期数据稳定性考虑DHT22更值得。核心读取代码如下#include DHT.h #define DHTPIN 4 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(115200); dht.begin(); } void loop() { float h dht.readHumidity(); float t dht.readTemperature(); Serial.print(湿度: ); Serial.print(h); Serial.print(% 温度: ); Serial.print(t); Serial.println(℃); delay(2000); }注意DHT22 两次读数之间建议间隔2秒以上这是传感器本身的规定读取间隔过短会导致返回NaN。3.2 光照检测光敏电阻模块光敏电阻模块会输出一个随光照强度变化的模拟电压信号ESP32 通过 ADC模数转换器读取这个电压值映射成0~4095的数字量。光线越强ADC值越小光线越暗ADC值越大。注意不同模块的电压输出范围不同最好先用串口打印观察实际值范围再设定阈值。示例代码int lightPin 34; int lightValue 0; void loop() { lightValue analogRead(lightPin); Serial.println(lightValue); delay(500); }实际项目中可以设定一个阈值比如ADC值超过3000时认为衣柜内部太暗自动打开LED灯带。这里有一个容易踩坑的细节ESP32的ADC引脚在默认情况下使用11dB衰减测量范围大约是0~3.3V。如果你的光敏电阻模块输出范围不是0~3.3V比如部分模块在5V供电时输出0~5V直接接到GPIO脚可能烧坏芯片。建议先确认模块参数或者在模块输出端串联一个分压电阻。3.3 执行器舵机控制通风挡板SG90 是小功率模拟舵机通过PWM信号控制旋转角度。它的控制信号周期为20ms高电平脉冲宽度决定角度0.5ms 对应 0°1.5ms 对应 90°2.5ms 对应 180°在ESP32中可以用内置的LEDCLED Control模块产生PWM信号也可以使用 ESP32Servo 库后者更简单不需要手动计算脉冲宽度。#include ESP32Servo.h Servo myServo; int servoPin 15; void setup() { myServo.attach(servoPin); } void loop() { myServo.write(0); // 关闭挡板 delay(3000); myServo.write(90); // 半开 delay(3000); myServo.write(180); // 完全打开 delay(3000); }在智能衣柜中舵机控制的是一个通风挡板。当湿度偏高时主控自动把挡板打开湿度正常后再关闭挡板。3.4 状态展示Web服务器ESP32 可作为Wi-Fi客户端连接路由器也可以开启SoftAP模式。这里采用STA模式连接路由器然后启动WebServer手机和电脑通过局域网IP访问页面。#include WiFi.h #include WebServer.h const char* ssid 你的WiFi名称; const char* password 你的WiFi密码; WebServer server(80); void handleRoot() { String html !DOCTYPE htmlhtmlheadmeta charsetutf-8/headbody; html h1智能衣柜状态/h1; html p温度23.5 ℃/p; html p湿度45%/p; html /body/html; server.send(200, text/html, html); } void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(WiFi.localIP()); server.on(/, handleRoot); server.begin(); } void loop() { server.handleClient(); }通过串口打印出的IP地址在浏览器中输入即可访问。这里需要提醒一点server.send(200, text/plain, )这种空响应在部分浏览器中会显示空白页但没关系因为后面的sendHeader(Location, /)会触发302跳转浏览器会自动回到主页。4. 完整实战嵌入式衣柜系统下面把上面的模块整合成一个完整的、可下载到开发板的智能衣柜项目。这是本文的核心部分代码可以直接复制到Arduino IDE中编译上传。4.1 系统需求定义在这个实战中我们定义以下功能每2秒采集一次温湿度。每500毫秒采集一次光照强度。当湿度大于65%时自动打开通风挡板湿度降到55%以下时关闭挡板。当光照强度低于阈值时自动打开LED照明灯带。提供Web页面显示当前温湿度、光照状态、挡板状态和灯光状态。提供Web按钮可以手动控制通风挡板和灯光。4.2 电路连接连接示意如下模块ESP32引脚DHT22 DATAGPIO4光敏电阻模块 OUTGPIO34 (ADC)SG90 信号线GPIO15WS2812B DINGPIO2模块 VCC3.3V 或 5V见下面注意事项所有模块 GNDGND注意SG90 舵机电流较大建议VCC接5V电源不要直接用ESP32的3.3V引脚带动。WS2812B灯带也需要5V供电如果灯带较长超过20个灯珠建议单独接电源避免压降导致颜色异常或闪烁。4.3 完整代码使用Arduino IDE新建一个工程文件名为 embedded_wardrobe.ino复制以下代码#include WiFi.h #include WebServer.h #include DHT.h #include ESP32Servo.h #include Adafruit_NeoPixel.h // 配置区 #define DHT_PIN 4 #define DHT_TYPE DHT22 #define LIGHT_PIN 34 #define SERVO_PIN 15 #define LED_PIN 2 #define LED_NUM 10 #define HUMIDITY_HIGH 65.0 #define HUMIDITY_LOW 55.0 #define LIGHT_THRESHOLD 3000 const char* ssid 你的WiFi名称; const char* password 你的WiFi密码; // DHT dht(DHT_PIN, DHT_TYPE); Servo ventServo; Adafruit_NeoPixel strip(LED_NUM, LED_PIN, NEO_GRB NEO_KHZ800); WebServer server(80); float temperature 0.0; float humidity 0.0; int lightValue 0; bool ventOpen false; bool lightOn false; unsigned long lastSensorRead 0; void readSensor() { unsigned long now millis(); if (now - lastSensorRead 2000) { return; } lastSensorRead now; temperature dht.readTemperature(); humidity dht.readHumidity(); lightValue analogRead(LIGHT_PIN); } void setVent(bool open) { ventOpen open; if (open) { ventServo.write(180); } else { ventServo.write(0); } } void setLight(bool on) { lightOn on; if (on) { strip.fill(strip.Color(255, 255, 255)); strip.show(); } else { strip.clear(); strip.show(); } } void handleRoot() { String html !DOCTYPE htmlhtmlhead; html meta charsetutf-8; html title嵌入式衣柜控制台/title; html style; html body{font-family:sans-serif;max-width:600px;margin:50px auto;padding:0 20px}; html .card{background:#f5f5f5;border-radius:8px;padding:20px;margin-bottom:16px}; html button{font-size:16px;padding:10px 20px;margin-right:10px;cursor:pointer}; html /style; html /headbody; html h1嵌入式衣柜控制台/h1; html div classcard; html p温度b String(temperature) /b ℃/p; html p湿度b String(humidity) /b %/p; html p光照值b String(lightValue) /b/p; html p通风挡板b String(ventOpen ? 开启 : 关闭) /b/p; html p照明灯带b String(lightOn ? 开启 : 关闭) /b/p; html /div; html div classcard; html p手动控制/p; html button onclickfetch(\/vent\)切换通风/button; html button onclickfetch(\/light\)切换照明/button; html /div; html scriptsetTimeout(function(){location.reload();}, 5000);/script; html /body/html; server.send(200, text/html, html); } void handleVent() { setVent(!ventOpen); server.sendHeader(Location, /); server.send(302, text/plain, ); } void handleLight() { setLight(!lightOn); server.sendHeader(Location, /); server.send(302, text/plain, ); } void setup() { Serial.begin(115200); dht.begin(); ventServo.attach(SERVO_PIN); strip.begin(); strip.clear(); strip.show(); setVent(false); setLight(false); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print(连接Wi-Fi中); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(); Serial.print(接入IP地址); Serial.println(WiFi.localIP()); server.on(/, handleRoot); server.on(/vent, handleVent); server.on(/light, handleLight); server.begin(); } void loop() { server.handleClient(); readSensor(); // 自动控制逻辑湿度控制通风 if (humidity HUMIDITY_HIGH !ventOpen) { setVent(true); Serial.println(湿度超标打开通风挡板); } else if (humidity HUMIDITY_LOW ventOpen) { setVent(false); Serial.println(湿度正常关闭通风挡板); } // 自动控制逻辑光照控制照明 if (lightValue LIGHT_THRESHOLD !lightOn) { setLight(true); Serial.println(光照不足打开灯带); } else if (lightValue LIGHT_THRESHOLD lightOn) { setLight(false); Serial.println(光照充足关闭灯带); } }这段代码的核心逻辑分为三块readSensor()负责周期读取传感器间隔2秒。setVent()和setLight()两个函数封装执行器控制避免逻辑代码里直接写IO操作。loop()中完成两个自动判断湿度控制通风光照控制照明。4.4 编译与上传在Arduino IDE中选择开发板工具 → 开发板 → ESP32 Dev Module。选择对应端口。点击编译并上传。打开串口监视器波特率115200等待Wi-Fi连接成功记录IP地址。4.5 运行验证在手机或电脑浏览器中输入串口打印的IP地址可以看到控制台页面。预期观察结果页面每5秒自动刷新一次显示最新温湿度和光照值。用手遮住光敏电阻灯带应自动亮起。让传感器感受到湿度升高可以对着DHT22哈气通风挡板应自动打开。点击页面上的“切换通风”和“切换照明”按钮执行器应该立即响应。5. 常见问题与排查思路5.1 编译报错找不到库文件现象提示DHT.h: No such file or directory、Adafruit_NeoPixel.h: No such file or directory或ESP32Servo.h: No such file or directory。原因相关库没有安装或者库名称与代码不一致。解决打开 Arduino IDE → 工具 → 管理库。搜索并安装 DHT sensor library、Adafruit Unified Sensor Library、Adafruit NeoPixel、ESP32Servo。安装完成后关闭并重新打开Arduino IDE重新编译。5.2 串口输出NaN现象温度和湿度一直显示 NaN。原因DHT22接线错误、GPIO脚选错、采样间隔低于2秒、供电不稳。排查步骤检查DHT22引脚连接确认DATA接在GPIO4。确认VCC供电正常GND共地。检查代码中dht.begin()是否在setup中调用。把读取间隔调大到2500毫秒以上。使用万用表测量传感器VCC和GND之间的电压应在3.3V~5V之间。5.3 Wi-Fi连不上现象串口一直打印.最后重启。原因SSID或密码错误、路由器开启MAC过滤、ESP32距离路由器太远、路由器只允许2.4GHz频段。解决确认SSID和密码正确注意大小写。先在手机热点上测试排除路由器策略问题。确认路由器开启了2.4GHz频段ESP32不支持5GHz频段。观察路由器后台是否出现新设备。5.4 舵机抖动或不动现象舵机持续抖动无法转到指定角度或者完全没反应。原因供电不足。SG90在转动瞬间电流可达几百毫安如果使用USB线直接供电很容易压降。另外舵机信号线接触不良也可能导致抖动。解决使用外部5V电源给舵机供电。VCC和GND分开走线不要共用一条细杜邦线。在电源输出端并联一个100μF电解电容稳定电压。检查信号线是否牢固插在GPIO15上。5.5 ADC读数跳变现象光敏电阻读数不稳定灯带频繁闪烁。原因光敏电阻模块输出信号受电源噪声影响或者ESP32 ADC本身有一定噪声。解决软件上多次采样取平均值。使用analogRead()后延迟10ms读第二次去掉最高值和最低值再取平均。检查光敏电阻模块的供电3.3V供电时ADC量程也会受影响。在模块输出端和GND之间并联一个0.1μF电容滤波。6. 最佳实践与工程化建议6.1 代码模块化演示代码全部放在 .ino 文件中适合学习但不适合长期维护。工程化时建议拆成 config.h配置、sensor.h/cpp传感器、actions.h/cpp执行器、web.h/cppWeb服务四个模块每个模块只负责一类职责。这样做有几个好处更换传感器时只需要修改sensor模块。调试舵机时不需要翻看全部代码。新增功能比如添加继电器控制除湿机时不影响已有模块。6.2 数据持久化与远程上报目前设备只提供局域网Web页面数据在重启后会丢失。如果需要长期追踪衣柜温湿度变化建议把数据定时上报到MQTT Broker。使用本地MySQL或SQLite存储。使用云平台IoT服务时注意配置好Topic权限和证书不要使用明文密码登录。MQTT上报是一个常见的进阶方向。ESP32每隔5分钟发布一次温湿度到wardrobe/sensor这个Topic服务端订阅后写入数据库就可以在Web端绘制历史曲线。常见的MQTT Broker有Mosquitto自建和阿里云、腾讯云等云平台提供的MQTT服务。6.3 安全边界与权限控制当设备接入网络后必须考虑安全不要硬编码生产环境的Wi-Fi密码在Git仓库中。建议使用配置文件并添加到.gitignore。Web控制接口建议增加简单口令验证否则同一局域网内任何人都能控制你的衣柜。不要直接在公网暴露设备的22端口或Web服务端口。如果使用云平台接入优先使用设备证书认证避免共享密钥泄露。最小权限原则同样适用于设备端衣柜的Web接口只需要读取传感器状态和控制通风照明不要开放串口调试命令或远程固件升级接口除非你有完善的签名校验机制。6.4 功耗优化如果衣柜设备使用电池供电需要考虑低功耗方案将ESP32设置为深度睡眠模式每隔10分钟唤醒一次采集数据并上报然后再次进入睡眠。传感器和执行器分开供电平时只给传感器供电执行器仅在实际动作时上电。关闭Wi-Fi的DHCP重传冗余设置静态IP减少连接耗时。舵机和高亮度灯带是耗电大户尽量避免长时间保持运行。需要提醒的是深度睡眠模式下必须使用外部定时器唤醒例如RTC定时器不能用delay()模拟否则Wi-Fi模块会持续耗电低功耗效果大打折扣。6.5 异常处理与日志记录在嵌入式环境中传感器偶尔返回错误值很正常。关键是要让代码具备容错能力if (isnan(humidity) || isnan(temperature)) { Serial.println(DHT22读取失败跳过本轮控制); return; }这段逻辑可以放在readSensor()中避免异常值触发错误的风门动作。生产环境下建议把关键日志通过串口和MQTT双通道输出方便远程排查问题。此外执行器动作不应该频繁触发。比如船舱门每5秒开关一次既不实际又会让舵机磨损严重。建议在自动控制逻辑中加入滞回区间本项目已经用了65%开、55%关的滞回设计并且限制最小动作间隔。7. 总结与下一步学习方向通过嵌入式衣柜这个完整的项目我们实际上串起了嵌入式开发中最常见的几条知识主线数字传感器 DHT22 的单总线通信与数据读取。ADC 对模拟信号光敏电阻的采样与阈值判断。PWM 舵机控制和 WS2812B 灯带的驱动。WiFi 接入和 WebServer 的搭建。一个完整的闭环控制链路采集 → 分析 → 执行 → 展示。这套技能迁移性很强。把衣柜换成鱼缸就是水温监测 自动加热 喂食控制换成花盆就是土壤湿度和自动浇灌系统换成房门就是门磁传感器 远程开锁。核心架构完全一致变化的只是传感器和执行器的类型。如果你刚完成本项目下一步可以按以下路线继续深入把单文件代码拆分为多模块工程体验代码重构。给 Web 页面加上实时图表Chart.js不再手动刷新。引入 MQTT将数据接入 Home Assistant 或自建服务端。增加继电器模块控制小型除湿机等强电设备。尝试使用 LVGL 等 GUI 库为设备添加一块显示屏做成真正独立的智能家居产品。遇到问题时优先看串口日志再拆模块定位最后搜索具体报错信息。嵌入式开发就是一个反复“埋问题、找问题、解决问题”的过程做完一个小项目你对单片机调试的理解会比看十篇教程都有用。如果本文对你有帮助可以收藏备用。也欢迎在评论区交流你的智能衣柜改造方案包括硬件选型、控制逻辑优化、外观开模或者遇到的任何报错看到都会回复。