使用 KY-039 传感器与 Arduino 测量心率
组件与物料
| 组件 | 数量 |
|---|---|
| Arduino UNO | 1 |
| KY-039 心跳传感器 | 1 |
| 跳线 | 1套 |
项目原理
Arduino 37 合一传感器套装中的 KY-039 心跳传感器,并非直接输出心率数值,而是输出 0-1023 的模拟量,反映红外光接收强度。手指放在红外 LED 和光敏晶体管之间,血管随心跳膨胀收缩,改变红外透过率,形成脉动信号。通过信号处理可计算心率 (BPM)。
信号处理步骤
- 原始读取:直接读取模拟值,波形锯齿严重,受 50Hz 交流电光源干扰。
- 滑动平均滤波:对最近 20 个采样取平均,平滑波形。
- 20ms 积分平均:在 20ms 窗口内连续采样并平均,消除 50Hz 工频干扰(60Hz 地区用 16.67ms)。
- 峰值检测:检测连续
rise_threshold次上升沿(默认 5 次)判定一个心跳,记录时间间隔计算 BPM。 - 加权平均:利用最近 3 次心跳间隔加权平均(权重 0.4, 0.3, 0.3)输出稳定心率。
核心算法代码
#define samp_siz 4
#define rise_threshold 4
int sensorPin = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
float reads[samp_siz], sum = 0;
long int now, ptr = 0;
float last, reader, start;
float first, second, third, before, print_value;
bool rising = false;
int rise_count = 0;
int n;
long int last_beat = 0;
for (int i = 0; i < samp_siz; i++) reads[i] = 0;
while (1) {
// 20ms 窗口平均采样,消除 50Hz 干扰
n = 0; start = millis(); reader = 0;
do {
reader += analogRead(sensorPin);
n++;
now = millis();
} while (now < start + 20);
reader /= n;
// 滑动窗口平均
sum -= reads[ptr];
sum += reader;
reads[ptr] = reader;
last = sum / samp_siz;
// 上升沿检测
if (last > before) {
rise_count++;
if (!rising && rise_count > rise_threshold) {
rising = true;
first = millis() - last_beat;
last_beat = millis();
// 加权平均计算 BPM
print_value = 60000.0 / (0.4 * first + 0.3 * second + 0.3 * third);
Serial.println(print_value);
third = second;
second = first;
}
} else {
rising = false;
rise_count = 0;
}
before = last;
ptr++; ptr %= samp_siz;
}
}
进阶优化建议
- 基于 15 秒窗口计算平均心率,剔除离群值
- 针对不同人群(高心率、波形差异)调整检测阈值
- 增加下降沿或波峰检测作为备选
原理图

制造工艺
- 树莓派 ppDAQC 扩展板实时采集温度数据并上传至 InitialState
- 树莓派多传感器温度光照监测系统:DS18B20 实战构建
- 4 美元太阳能庭院灯改造:MSP430 + nRF24L01+ 打造花园无线传感器节点
- 基于树莓派的卫生间占用传感器:通过 Twilio 实现语音与短信提醒
- 树莓派运行 Windows 10 IoT Core 读取心率脉冲传感器:分步指南
- 树莓派光敏电阻教程:接线与 Python 读取光照强度
- 数字光照传感器驱动 LED:Windows 10 IoT Core 树莓派实战
- 远程心率监测系统:AWS IoT 告警 + 树莓派 Windows IoT 可视化
- 色彩传感器:工作原理与关键应用
- OPT3007超薄环境光传感器:智能设备精准光测量
- 环境光传感器:功能、设计与关键应用
- 光学传感器:基础、类型与实用应用