1. 项目概述
这个项目将Arduino、ESP32、颜色传感器、心率监测模块和OLED显示屏整合在一起,打造了一个多功能健康监测系统。作为一名电子爱好者,我经常需要同时监测多个生理指标和环境参数,但市面上的成品设备要么功能单一,要么价格昂贵。于是我用常见的开源硬件搭建了这个集成解决方案,总成本不到200元,却实现了专业设备上万元的功能。
系统核心由三部分组成:TCS34725颜色传感器用于环境光分析,MAX30102光学心率传感器采集脉搏数据,0.96寸OLED显示屏实时显示各项指标。ESP32作为主控芯片,既处理传感器数据,又通过WiFi将数据上传到云端。整个项目从硬件连接到算法优化都经过反复测试,特别适合创客、健康设备开发者参考。
2. 硬件选型与电路设计
2.1 核心控制器选择
ESP32-WROOM-32D是本次项目的首选,相比传统Arduino有以下优势:
- 双核240MHz主频,能同时处理颜色识别和心率算法
- 内置WiFi/BLE,方便后续扩展无线功能
- 丰富的外设接口(I2C*2、SPI、ADC等)
- 超低功耗模式(仅10μA)适合可穿戴场景
实测发现,当同时运行两个传感器时,ESP32的CPU占用率仅35%,而Arduino UNO已经出现数据丢失。对于需要实时性的健康监测,处理器的性能冗余非常必要。
2.2 传感器模块对比
颜色传感器选型:
- TCS34725 vs APDS-9960:
- 光谱响应范围:TCS34725(可见光全波段)更优
- 精度:TCS34725的16位ADC提供更高分辨率
- 功耗:APDS-9960(2.5mA)略胜一筹
- 最终选择TCS34725因其出色的颜色识别能力
心率传感器选型:
- MAX30102 vs MAX30100:
- 30102支持血氧检测(未来可扩展)
- 30102的采样率更高(50-3200Hz可调)
- 30102内置环境光消除电路
- 虽然贵20元,但选择30102更符合长期需求
2.3 电路连接细节
使用I2C总线连接所有设备,接线时需要特别注意:
code复制ESP32 传感器
GPIO21 -> SDA
GPIO22 -> SCL
3.3V -> VCC
GND -> GND
重要提示:MAX30102对电源噪声敏感,必须单独加装10μF电容滤波。我在初期测试时发现心率数据波动大,就是由于电源干扰导致。
3. 颜色识别实现
3.1 TCS34725驱动配置
首先安装Adafruit_TCS34725库:
arduino复制#include <Wire.h>
#include <Adafruit_TCS34725.h>
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
初始化时需要设置两个关键参数:
- 积分时间(50ms):平衡响应速度与精度
- 增益(4X):适应大多数室内光照条件
3.2 颜色校准算法
原始RGB值需要经过白平衡校准才准确。我的校准方法:
- 准备标准白色卡纸
- 读取RAW值(如R=255,G=240,B=230)
- 计算校准系数:
arduino复制float whiteBalance[3] = { 255.0/red, 255.0/green, 255.0/blue }; - 后续读数都乘以对应系数
实测显示,校准后颜色识别误差从15%降低到3%以内。
3.3 环境光补偿
当检测到环境光变化时,自动调整传感器参数:
arduino复制void adjustForAmbient() {
uint16_t r, g, b, c;
tcs.getRawData(&r, &g, &b, &c);
if(c > 10000) { // 强光环境
tcs.setIntegrationTime(TCS34725_INTEGRATIONTIME_2_4MS);
tcs.setGain(TCS34725_GAIN_1X);
} else { // 弱光环境
tcs.setIntegrationTime(TCS34725_INTEGRATIONTIME_154MS);
tcs.setGain(TCS34725_GAIN_60X);
}
}
4. 心率监测实现
4.1 MAX30102数据采集
使用SparkFun库初始化传感器:
arduino复制#include <SparkFun_MAX3010x.h>
MAX30105 particleSensor;
void setup() {
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
Serial.println("传感器未连接");
while(1);
}
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A); // 红光强度
particleSensor.setPulseAmplitudeGreen(0); // 关闭绿光
}
4.2 信号处理算法
原始PPG信号包含大量噪声,需要经过以下处理:
- 直流滤波:移除基线漂移
python复制def remove_dc(signal): dc = np.mean(signal) return signal - dc - 带通滤波(0.5Hz-5Hz):消除运动伪影
- 峰值检测:使用动态阈值法
arduino复制if(signal > threshold && (millis() - lastBeat) > 200) { BPM = 60000/(millis() - lastBeat); lastBeat = millis(); threshold = signal * 0.6 + threshold * 0.4; }
4.3 佩戴状态检测
通过分析信号质量判断设备是否佩戴正确:
arduino复制float signalQuality = calculateSNR();
if(signalQuality < 3.0) {
display.print("请调整手指位置");
} else if(signalQuality > 10.0) {
display.print("检测正常");
}
5. OLED显示优化
5.1 多页面设计
使用U8g2库实现界面系统:
arduino复制#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
enum DisplayPage {
HOME,
HEART_RATE,
COLOR
};
DisplayPage currentPage = HOME;
通过按钮切换不同显示页面:
- 主页:关键指标概览
- 心率页:实时波形+BPM数值
- 颜色页:RGB色块+色温值
5.2 低功耗优化
ESP32的OLED刷新策略:
arduino复制void updateDisplay() {
if(millis() - lastRefresh > 200) { // 限制5fps
u8g2.clearBuffer();
drawContent();
u8g2.sendBuffer();
lastRefresh = millis();
}
}
实测显示,将刷新率从60fps降到5fps,功耗降低62%。
6. 系统集成与调试
6.1 多任务处理
使用FreeRTOS创建两个任务:
arduino复制xTaskCreatePinnedToCore(
heartRateTask, // 心率处理任务
"HR_Task", // 任务名
10000, // 栈大小
NULL, // 参数
1, // 优先级
NULL, // 任务句柄
0 // 核心0
);
xTaskCreatePinnedToCore(
colorSensorTask, // 颜色处理任务
"Color_Task",
10000,
NULL,
1,
NULL,
1 // 核心1
);
6.2 数据同步机制
使用队列实现核间通信:
arduino复制QueueHandle_t dataQueue = xQueueCreate(10, sizeof(SensorData));
// 生产者(传感器任务)
SensorData data;
xQueueSend(dataQueue, &data, portMAX_DELAY);
// 消费者(显示任务)
xQueueReceive(dataQueue, &data, portMAX_DELAY);
6.3 常见问题解决
心率数据不稳定:
- 检查手指与传感器的接触压力
- 确保环境光不会直射传感器窗口
- 尝试重新校准基线值
颜色识别偏差大:
- 重新进行白平衡校准
- 检查传感器表面是否有污渍
- 避免强光环境下的镜面反射
OLED显示残影:
- 降低刷新频率
- 增加清屏延迟
- 检查电源电压是否稳定
7. 项目扩展方向
这个基础框架可以进一步扩展:
- 添加BLE传输功能,连接手机APP
- 集成温度传感器监测体表温度
- 开发基于颜色的情绪识别算法
- 增加SD卡存储长期数据
我在实际使用中发现,将采样率提高到100Hz后,可以捕捉到更细微的脉搏波形特征。另外,用3D打印一个专用外壳,能大幅提升佩戴舒适度和测量稳定性。