💡 划重点
- 主控采用 ESP32-C3,成本低、体积小,自带低功耗蓝牙。
- SCD41 监测书桌 CO₂ 与温湿度,WS2812 灯环用颜色反馈专注状态。
- 按键用于静音与模式切换,手机通过低功耗蓝牙查看趋势。
- 整机物料控制在 118 元内,适合学生与居家办公桌面改造。
- 接线沿用给定引脚:SCD41 的 I2C 使用 8/9,灯环数据使用 10,按键使用 3。
需求洞察
目标用户是居家自习的中学生、大学生、备考人群和远程办公者。真实痛点是:书桌门窗关闭后 CO₂ 逐渐升高,人却很难立刻察觉,常见表现是犯困、烦躁、注意力涣散;番茄钟只能提醒休息,不能反映空气环境;商用 CO₂ 监测仪价格偏高,也缺少与台灯联动的即时反馈。这个项目值得做,是因为台灯本来就是书桌必备品,把传感、灯光和蓝牙记录叠加进去,不额外占用桌面空间;用颜色变化提示通风或休息,比数字仪表更不打断学习;成本低,便于复制和迭代。
方案设计
感知层由 SCD41 与按键组成。SCD41 每 5 秒读取 CO₂、温度和湿度,I2C 地址通常为 0x62;按键用于短按静音、长按进入校准流程。控制层由 ESP32-C3 完成滤波、阈值分级、按键状态机和蓝牙数据封装。执行层是 12 位 WS2812 灯环:CO₂ 低于 800ppm 显示绿色,800 至 1200ppm 显示黄色,高于 1200ppm 显示红色;夜间降低亮度,静音时熄灭灯环。日志与联网层通过低功耗蓝牙自定义服务上报“CO₂,温度,湿度”,串口同步输出日志;不依赖路由器,隐私风险低。供电采用 USB-C 5V,灯环亮度限制在较低水平,避免电流过大。
物料清单
| 物料 | 数量 | 用途 | 估算单价 | 合计 |
|---|---|---|---|---|
| ESP32-C3 开发板 | 1 | 主控与蓝牙 | 25 元 | 25 元 |
| SCD41 模块 | 1 | CO₂、温湿度采集 | 65 元 | 65 元 |
| WS2812 12 位灯环 | 1 | 状态灯光反馈 | 8 元 | 8 元 |
| 轻触按键 | 2 | 静音、校准 | 0.5 元 | 1 元 |
| 电阻电容 | 若干 | 限流、滤波 | 2 元 | 2 元 |
| 洞洞板与杜邦线 | 1 套 | 焊接与连接 | 8 元 | 8 元 |
| USB-C 电源线 | 1 | 供电 | 5 元 | 5 元 |
| 外壳与遮光片 | 1 套 | 固定与柔光 | 4 元 | 4 元 |
| 合计 | 118 元 |
接线与结构
SCD41 的 VCC 接 3V3,GND 接 GND,SDA 接 GPIO8,SCL 接 GPIO9;WS2812 的 VCC 接 5V,GND 接 GND,DIN 接 GPIO10,数据线串联约 330Ω 电阻,电源端并联 1000µF 电容;按键一端接 GPIO3,另一端接 GND,使用内部上拉。结构上,灯环固定在灯臂顶部并加遮光片,SCD41 放在底座靠近桌面处,外壳开透气孔并远离发热元件;按键布置在底座侧面。按给定接线即可工作,无需改脚;若灯环数据不稳定,可加电平转换,但会增加成本,因此优先缩短数据线并做好共地。
核心代码
#include <Wire.h>
#include <SensirionI2CScd4x.h>
#include <Adafruit_NeoPixel.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#define SDA_PIN 8
#define SCL_PIN 9
#define LED_PIN 10
#define KEY_PIN 3
#define LED_COUNT 12
SensirionI2CScd4x scd4x;
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
BLEServer* pServer = nullptr;
BLECharacteristic* pChar = nullptr;
uint16_t co2 = 0;
float temp = 0, hum = 0;
unsigned long lastRead = 0, lastKeyTime = 0;
bool muted = false;
int lastKey = HIGH;
void setRing(uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < LED_COUNT; i++) strip.setPixelColor(i, strip.Color(r, g, b));
strip.show();
}
void updateColor(uint16_t v) {
if (muted) { setRing(0, 0, 0); return; }
if (v < 800) setRing(0, 80, 20);
else if (v < 1200) setRing(120, 70, 0);
else setRing(160, 0, 0);
}
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
strip.begin();
strip.setBrightness(60);
strip.show();
scd4x.begin(Wire);
pServer = BLEDevice::createServer();
BLEService* pService = pServer->createService("12345678-1234-1234-1234-1234567890ab");
pChar = pService->createCharacteristic(
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pChar->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising* pAdv = BLEDevice::getAdvertising();
pAdv->addServiceUUID(pService->getUUID());
pAdv->start();
}
void loop() {
int key = digitalRead(KEY_PIN);
if (key == LOW && lastKey == HIGH && millis() - lastKeyTime > 200) {
muted = !muted;
lastKeyTime = millis();
}
lastKey = key;
if (millis() - lastRead > 5000) {
lastRead = millis();
uint16_t v; float t, h;
if (scd4x.readMeasurement(v, t, h) == 0 && v > 0) {
co2 = v; temp = t; hum = h;
}
updateColor(co2);
String payload = String(co2) + "," + String(temp, 1) + "," + String(hum, 1);
pChar->setValue(payload.c_str());
if (pServer->getConnectedCount() > 0) pChar->notify();
Serial.println(payload);
}
}
调试步骤
先烧录程序并打开 115200 串口,检查 I2C 是否能发现 SCD41;预热后观察 CO₂ 数值是否稳定。再单独测试灯环颜色与亮度,确认 5V 供电和共地正常。随后测试按键短按静音、消抖是否可靠。手机用低功耗蓝牙调试工具连接设备,查看自定义服务与通知数据。用密闭房间验证阈值切换,并加入迟滞逻辑避免颜色频繁跳动。最后检查外壳开孔、传感器位置和整机发热,必要时在通风环境下执行 400ppm 基线校准。