💡 划重点
- 本项目围绕卧室睡眠场景,利用 INMP441 高精度数字麦克风采集呼吸声,通过 ESP32-S3 运行 FFT 频谱分析提取呼吸频率与幅度,动态驱动 WS2812 幻彩灯带实现柔光渐变反馈。异常呼吸事件(如暂停、过缓)可触发灯光警示并预留数据上报通道。整体成本控制在 90 元以内,适合卧室安静环境,帮助用户实时感知自身或家人睡眠呼吸状态。
需求洞察
目标用户包括打鼾人群、轻度睡眠呼吸暂停关注者、婴幼儿父母以及需要照护的老年人。真实痛点在于夜间不易察觉呼吸异常,尤其打鼾低通气或呼吸暂停直接关联健康风险。传统医用睡眠监测设备昂贵且连接繁琐,而普通夜灯缺乏生理感知能力。本项目将呼吸声监测与夜灯自然融合,在不干扰睡眠的前提下提供直观的光效反馈,门槛低、易部署,值得作为个人健康关怀的入门硬件实现。
方案设计
整个系统划分为感知层、控制层、执行层和日志层。感知层由 INMP441 数字 MEMS 麦克风通过 I2S 接口输入原始音频流。控制层以 ESP32-S3 为核心,利用 ESP-IDF 或 Arduino 框架下的 FFT 库对音频片段进行频谱分析,提取 200–1500 Hz 范围内呼吸声能量包络,进而推算呼吸频次和强度。执行层采用 WS2812 LED 灯带,根据呼吸速率驱动柔光渐变:正常呼吸时灯光缓慢律动,呼吸过缓或暂停时改变色温并闪烁提醒。日志层通过板载 Wi-Fi 将异常事件和时间戳上报到本地 MQTT 服务器或串口调试,方便后续健康数据回顾。
信号处理上采用双阈值方法:短时能量低于静音阈值判定为安静,高于呼吸阈值则触发计数并更新灯光节奏。同时加入异常检测,若连续数秒无有效呼吸峰值,则判定为潜在暂停事件,灯光转为警示橙红色并保持至呼吸恢复。
电源使用 5V 适配器直接供电,ESP32-S3 板上稳压为 3.3V,麦克风与灯带共用 5V 电源,整体功耗约 2.5 W,适合整夜运行。
物料清单
| 序号 | 名称 | 规格/型号 | 数量 | 用途 | 估算单价(元) |
|---|---|---|---|---|---|
| 1 | 主控板 | ESP32-S3-DevKitC-1 | 1 | 核心控制与运算 | 35 |
| 2 | I2S 麦克风 | INMP441 模块 | 1 | 呼吸声采集 | 12 |
| 3 | 幻彩灯带 | WS2812B 30颗/米 | 1米 | 柔光反馈 | 18 |
| 4 | 电源适配器 | 5V 2A 带 DC 接口 | 1 | 系统供电 | 10 |
| 5 | 杜邦线+排母 | 母对母 20cm | 若干 | 接线 | 3 |
| 6 | 柔光罩/外壳 | 亚克力磨砂管 1m | 1 | 光效柔化 | 8 |
合计:86 元,在 90 元预算内。
接线与结构
接线依据初始建议并微调:麦克风 I2S 接口 SCK 接 GPIO4,SD 接 GPIO5,WS 接 GPIO6,另外 VCC 接 3.3V,GND 共地。WS2812 数据线接 GPIO10,灯带 5V 和 GND 直接取自电源适配器。由于 GPIO2 或 GPIO8 可能影响板载启动,故选择 GPIO10 避免冲突,该引脚在大部分 ESP32-S3 开发板上无特殊功能。ESP32-S3 的 USB 供电与适配器供电共地,注意不要同时使用两个 USB 口以防倒灌。
物理结构:将灯带粘贴于磨砂亚克力管内侧,主控板和麦克风模块封装在底座内。麦克风通过开孔对准床榻方向,避免遮挡。整体呈圆柱形夜灯造型,灯体向上出光,通过反射实现柔和光环境。
核心代码
基于 Arduino 框架与 ESP32-S3 平台,提供可编译的骨架。需安装 FastLED 和 arduinoFFT 库。
#include <driver/i2s.h>
#include <FastLED.h>
#include <arduinoFFT.h>
#define LED_PIN 10
#define NUM_LEDS 30
#define SAMPLE_RATE 16000
#define BUFFER_SIZE 1024
i2s_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = BUFFER_SIZE
};
i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 6,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = 5
};
CRGB leds[NUM_LEDS];
arduinoFFT FFT = arduinoFFT();
double vReal[BUFFER_SIZE];
double vImag[BUFFER_SIZE];
int32_t samples[BUFFER_SIZE];
float breathEnergy = 0;
unsigned long lastBreath = 0;
bool breathDetected = false;
void setup() {
Serial.begin(115200);
i2s_driver_install(I2S_NUM_0, &i2s;_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin;_config);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(80);
}
void loop() {
size_t bytesRead;
i2s_read(I2S_NUM_0, samples, sizeof(samples), &bytesRead;, portMAX_DELAY);
int sampleCount = bytesRead / 4;
for(int i = 0; i < BUFFER_SIZE && i < sampleCount; i++) {
vReal[i] = samples[i] >> 14;
vImag[i] = 0;
}
float sum = 0;
for(int i = 0; i < BUFFER_SIZE/2; i++) {
if(i > (200 * BUFFER_SIZE / SAMPLE_RATE) && i < (1500 * BUFFER_SIZE / SAMPLE_RATE)) {
sum += vReal[i];
}
}
breathEnergy = sum / (BUFFER_SIZE/2);
float brightness = map(breathEnergy, 10, 200, 0, 100);
brightness = constrain(brightness, 0, 100);
if(breathEnergy > 50) {
if(!breathDetected) {
lastBreath = millis();
breathDetected = true;
}
} else {
breathDetected = false;
if(millis() - lastBreath > 10000) {
} else {
}
}
FastLED.show();
delay(50);
}
代码通过 I2S 读取麦克风数据,执行 1024 点 FFT 后提取呼吸频带能量,根据能量阈值控制灯光颜色与亮度,并在检测到长时间无有效呼吸时触发橙色警示。
调试步骤
- 硬件连接检查:用万用表确认 3.3V、5V 无短路,GPIO4/5/6/10 对应正确。
- 上传程序后打开串口监视器,观察
breathEnergy数值波动。安静环境能量应在 10 左右,轻吹气或模拟呼吸可升至 80 以上。 - 调整阈值:若检测过于灵敏或迟钝,修改
breathEnergy > 50以及map范围,直至灯光律动与呼吸同步。 - 放置麦克风角度:确保开孔指向呼吸区,可用胶带调整内部防震棉。
- 整夜测试:记录异常事件,观察误报率,再微调 10 秒无呼吸告警时长。