STM32+MAX30102+DS18B20:心率血氧温度显示系统设计与实现

📅 发布时间:2026/8/31 23:23:57
STM32+MAX30102+DS18B20:心率血氧温度显示系统设计与实现
简介本资源是一套完整的STM32嵌入式健康监测系统设计实现方案面向电子类、自动化及物联网方向的本科课程设计、毕业设计与竞赛备赛学生解决心率、血氧饱和度与体温多参数实时采集、本地显示与无线上传的一体化开发难题。压缩包共含多个工程文件以Keil uVision5项目工程.uvprojx、C源码与头文件.c/.h、原理图与PCB设计文件.sch/.pcbdoc、设计报告PDF为核心辅以蓝牙APP通信协议说明与LCD1602驱动适配代码整体大小为319.05MB结构清晰、模块解耦明确便于分阶段学习与功能复现。已有2861人下载学习资源包含从传感器驱动MAX30102 I²C通信、DS18B20单总线测温、阈值报警逻辑、蜂鸣器控制、LCD1602动态刷新到蓝牙串口透传的全链路实现并配套详实的设计报告涵盖硬件选型依据、软件流程图、关键代码注释及调试问题分析可直接用于教学参考或项目快速启动。 STTM32加传感器加屏幕这组合一看就是典型的嵌入式课程设计或者毕业设计题目。我当年做类似项目的时候光是把MAX30102调通就折腾了整整两天不是读不出数据就是数值乱跳后来才摸清楚这套系统的门道。所以这篇博文我打算把这个“STM32心率血氧温度显示设计”拆开揉碎讲透从方案选型到代码实现从传感器原理到报告写作把我踩过的坑和总结的经验都倒出来希望能让你少走点弯路。这个项目的核心内容很清晰用STM32作为主控通过I2C接口读取MAX30102心率血氧传感器的数据用单总线协议读取温度传感器最常见的是DS18B20的数据处理后显示在LCD1602蓝膜液晶屏上。它解决的核心问题就是把医疗级的生理参数测量原理用低成本、低功耗的嵌入式方案落地实现非常适合作为嵌入式系统、传感器技术、信号处理这几门课的综合实践项目也适合想入门STM32外设开发、想搞懂PPG信号处理算法的朋友拿来练手。无论你是刚学完STM32基础想找个完整项目实战还是正在为课程设计报告发愁这篇内容都应该能帮到你。1. 整体方案设计与器件选型思路1.1 为什么是STM32 MAX30102 DS18B20 LCD1602先说选型。STM32F103C8T6这颗芯片在国产开发板领域已经快成“街U”了72MHz主频、20KB RAM、64KB Flash对付这类传感器数据采集和显示任务绰绰有余。更关键的是它资源丰富硬件I2C、ADC、定时器、DMA全都有而且固件库和例程满天飞遇到问题一搜就有解决方案对学生项目和入门开发者来说这比用什么冷门芯片省心太多。我见过有人用STM32F407甚至F429去做这个项目性能严重过剩价格还贵没必要。MAX30102这颗传感器本质上就是把红光LED660nm、红外光LED880nm、光电二极管、ADC、环境光抑制、数字滤波全部封装进了一个3mm x 3mm的小芯片里。它输出的已经是数字化的光电容积脉搏波PPG数据不需要额外搭建模拟放大电路这对我们这种非模拟电路专业背景的人来说简直是救星。市面上还有个MAX30100但它的红光和红外LED无法独立控制血氧计算精度不如MAX30102既然价格差不多直接上MAX30102。温度传感器这块标题没指定具体型号但最常见、最适合这个项目的是DS18B20。理由很简单单总线协议只占一个IO口测温范围-55°C到125°C12位精度下分辨率0.0625°C而且每个芯片有唯一的64位序列号以后你想扩展成多点测温系统一条总线上挂多个传感器就能区分非常灵活。有人会用NTC热敏电阻或者LM75但前者需要自己标定查表后者是I2C接口会跟MAX30102抢总线DS18B20反而是接线最简单、代码最成熟的选择。LCD1602蓝膜模块这屏老归老可它8毛钱一片的单价、清晰锐利的字符显示让它至今仍是字符显示需求的首选。蓝底白字在室内环境下看着也舒服。驱动方式上我强烈建议用I2C转接板PCF8574芯片把原本需要至少6个IO的并口连接压缩成2根线给STM32省出来的GPIO你可以用来接按键、接蜂鸣器、加状态灯。有人觉得并口直连更“正统”但做项目追求的是快速稳定地实现功能I2C扩展的方式可靠性完全没问题还能顺带练一下I2C设备的操作一举两得。1.2 技术指标与设计目标在动手之前先把技术指标定下来不然做到后面很容易陷入“传感器数值乱跳不知道该优化到啥程度”的泥潭。我当年做这个项目时给自己定的指标是这样心率测量范围30~220次/分钟误差控制在±2次/分钟内血氧测量范围80%~100%误差控制在±2%以内温度显示范围-10°C~50°C误差±0.5°C以内LCD1602显示刷新率1秒刷新一次太快会闪烁太慢观感迟钝支持按键切换显示模式心率血氧一屏、温度一屏、心率温度一屏注意血氧这项指标你要有点心理准备MAX30102毕竟不是医疗级设备指尖放置位置、按压力度、环境光都会影响读数。能稳定做到±2%~3%的误差而且重复性良好也就是同一个状态下多次测量结果基本一致这个项目就算成功了。我更看重复现性如果传感器值每次测出来都稳定那算法的方向就是对的。1.3 电源与电路设计的坑这个项目看着简单但电源设计有个隐藏的坑。MAX30102的LED驱动电流峰值能到50mA级别DS18B20工作电流1mA左右LCD1602背光电流20mA左右加上STM32本身整个系统峰值电流要留出150mA的余量。如果用USB供电问题不大但要是用3.3V的AMS1117稳压芯片从5V降压注意AMS1117的压差要求是1V以上输入5V、输出3.3V刚好处于临界区如果输入电压掉到4.5V输出就可能不稳。我实测过一个现象当MAX30102的红外LED以满电流驱动时系统3.3V纹波会明显增大导致LCD1602背光轻微闪烁。解决方法是MAX30102的VLEDLED供电引脚单独走线并在旁边加一个10uF钽电容和0.1uF陶瓷电容并联去耦这样能把LED开关带来的电源毛刺抑制住。还有一点DS18B20的数据线必须接一个4.7kΩ上拉电阻到3.3V不要用什么10kΩ的偷懒温度高的时候上拉太弱会导致时序读取出错。2. 核心器件工作原理与硬件连接2.1 MAX30102的心率血氧测量原理MAX30102能测心率和血氧背后的原理是光电容积脉搏波描记法简称PPG这个名词你会在论文和报告里反复看到。简单说血液在血管里是脉冲式流动的心脏收缩时血管血量增加对光的吸收增强心脏舒张时血量减少对光的吸收减弱。把LED的光照射到指尖另一侧的光电二极管接收到透射光透射光的强度就会随着心跳呈现规律性的波动这个波动信号就是PPG信号它的频率就是心率。血氧测量的原理更巧妙用的是双波长吸收差异法。还原血红蛋白Hb和氧合血红蛋白HbO2对红光660nm和红外光880nm的吸收系数不同HbO2对红光的吸收比Hb弱对红外光的吸收比Hb强。通过同时驱动红光和红外光LED分别测得两种光下的PPG信号计算两者的交流分量AC即脉搏波动部分与直流分量DC即组织基线吸收部分的比值就能推算出血氧饱和度。血氧计算公式在工程上有一个常用的经验公式R (AC_R / DC_R) / (AC_IR / DC_IR) SpO2 110 - 25 × R其中AC_R和AC_IR分别是红光和红外光的交流分量幅值DC_R和DC_IR是直流分量。这个公式算出来的结果正常范围内误差不大但R值超过2之后偏差会变大所以代码里要做好数据范围的限制算出来SpO2低于70%或者高于100%的全部拦截掉不要直接显示在屏幕上。2.2 实际接线与引脚分配硬件的连接方案我直接给出经过验证的引脚分配表。主控用STM32F103C8T6最小系统板传感器的连接方式如下模块引脚STM32引脚说明MAX30102VIN3.3V注意不是5VMAX30102超过3.6V会烧MAX30102GNDGND共地必须接MAX30102SCLPB6 (I2C1_SCL)上拉4.7kΩ到3.3VMAX30102SDAPB7 (I2C1_SDA)上拉4.7kΩ到3.3VMAX30102INTPA1中断引脚可配置FIFO几乎满时触发DS18B20VCC3.3V寄生供电也可但推荐外部供电DS18B20DQPA0必须接4.7kΩ上拉到3.3VDS18B20GNDGND共地LCD1602 I2CVCC5V转接板带稳压5V供电显示更亮LCD1602 I2CGNDGND共地LCD1602 I2CSCLPB8软件I2C避免与MAX30102冲突LCD1602 I2CSDAPB9软件I2C按键1一端PA2另一端接地按下切屏蜂鸣器I/OPA3心率超限报警可选这里有个关键设计决策为什么LCD1602的I2C不走硬件I2C1因为MAX30102已经占了I2C1如果共用总线MAX30102那种需要频繁读写FIFO的器件会拖慢LCD的刷新。而LCD1602本身对时序不敏感用软件模拟I2C完全不影响还能避免两个设备互相干扰。这就是分层设计的思想把实时性要求高的传感器放在硬件总线上把实时性要求低的外设用软件模拟整个系统跑起来会稳定很多。2.3 LCD1602的显示规划LCD1602是两行十六字符的显示模块项目里的显示内容规划直接决定用户体验。我最终用的是三屏循环切换的方案第一屏第一行显示“HR: 75 BPM”第二行显示“SpO2: 98%”第二屏第一行显示“TEMP: 36.5C”第二行显示“HOME: 28.5C”室温第三屏第一行显示“HR: 75 SpO2:98”第二行显示“SYS-STATUS: OK”第三屏其实是我后期加的调试信息正常显示时可以看到系统运行状态比如FIFO溢出次数、信噪比等级等。这个设计思路可以借鉴一下显示模块不只是显示最终数据适当显示系统执行状态对排查问题非常有帮助。你在调试阶段会深刻体会到这一点的好处。3. 软件架构与关键代码实现3.1 程序总体架构前后台系统这个项目没上RTOS用的是经典的前后台系统也就是一个大循环加中断服务的结构。程序流程是这样的系统初始化时钟、GPIO、I2C、定时器、串口外设初始化MAX30102配置、DS18B20探测、LCD1602初始化主循环读取传感器数据 → 算法处理 → 更新显示 → 检测按键 → 循环关键点在于MAX30102的数据读取我用了FIFO几乎满中断的方式。MAX30102内部有32个采样点的FIFO采样率50Hz时每0.64秒FIFO就会满一次配置INT引脚在FIFO数据达到阈值时输出低电平触发STM32的EXTI外部中断在中断服务函数里批量读取FIFO数据再交给主循环里的算法处理。这样就避免了主循环轮询带来的数据丢失也保证了采样的均匀性。3.2 MAX30102寄存器配置一个参数都不能错MAX30102的驱动代码网上很多但很多人直接抄过来跑不通原因就是寄存器配置出了问题。我给出经过验证的配置流程并解释每个参数背后的考量void MAX30102_Init(void) { // 1. 复位所有寄存器 MAX30102_WriteReg(REG_MODE_CONFIG, 0x40); HAL_Delay(100); // 2. 配置中断使能FIFO几乎满中断 新数据就绪中断 // 0x40: A_FULL_EN, 0x20: PPG_RDY_EN, 0x10: ALC_OVF_EN MAX30102_WriteReg(REG_INTR_ENABLE_1, 0xC0); MAX30102_WriteReg(REG_INTR_ENABLE_2, 0x00); // 3. FIFO配置4个采样点触发中断几乎满时中断 // SMP_AVE1 (4次平均), FIFO_ROLLOVER_EN1 (溢出不丢失) MAX30102_WriteReg(REG_FIFO_CONFIG, 0x4F); // 4. 设置FIFO几乎满阈值触发中断的水位 MAX30102_WriteReg(REG_FIFO_WR_PTR, 0x00); MAX30102_WriteReg(REG_OVF_COUNTER, 0x00); MAX30102_WriteReg(REG_FIFO_RD_PTR, 0x00); MAX30102_WriteReg(REG_FIFO_DATA, 0x00); // 5. 采样率与ADC配置SPO2_ADC_RGE2 (4096nA), SPO2_SMP_RATE3 (100Hz) // LED_PW3 (411us 脉宽分辨率18bit) MAX30102_WriteReg(REG_SPO2_CONFIG, 0x73); // 6. LED电流配置红光 6.4mA红外 7.2mA // 这个值需要根据指尖厚度调整太亮或太暗都不行 MAX30102_WriteReg(REG_LED1_PA, 0x24); // 红光LED电流 MAX30102_WriteReg(REG_LED2_PA, 0x28); // 红外LED电流 // 7. 模式配置心率和血氧模式红红外同时采样 MAX30102_WriteReg(REG_MODE_CONFIG, 0x03); }这个配置里SPO2_CONFIG寄存器值得多说两句。高三位SPO2_ADC_RGE是ADC量程我选的是4096nA这是对指尖透射场景比较合适的量程。如果指尖较厚或者肤色较深透射光强衰减严重可以改成2048nA提升增益。中间三位是采样率我选了100Hz这个值对心率测量来说已经很高了因为心率信号的主要能量集中在0.5~5Hz100Hz采样能够完整还原波形而且不会产生频谱混叠。低三位LED脉宽选411us对应18位ADC分辨率读数稳定性更好。LED电流的设置更关键PA寄存器每1位对应0.2mA0x24就是7.2mA0x28就是8.0mA。具体多大的电流合适要看红光和红外光的ADC原始值。健康的原始值范围是红光在10000~60000之间红外在30000~60000之间18位ADC满量程262144。如果数值太小说明光太弱信号都被组织吸收了交流分量太小后续算血氧时AC/DC的信噪比会很差。一定要在调试阶段把原始值打印出来根据实际值调整LED电流。这是个反复试错的过程但做一次就有经验了。3.3 心率算法从原始信号到BPM数值从MAX30102拿到的原始数据是一串随时间变化的光强数值里面包含了心跳信号、呼吸信号、运动伪迹、工频干扰的叠加。要把心率算出来关键是分离出心跳的频率成分。我用的滤波器是级联的IIR滤波器分别是0.5Hz高通滤波和5Hz低通滤波把有效信号限制在心跳的正常频率范围内。IIR滤波器的系数用MATLAB的fdatool工具算出来然后转成C语言的浮点系数数组。STM32F103没有FPU浮点运算效率不高但心率计算属于低频任务每秒才处理50个点即便是软件浮点也毫无压力。滤波之后就是R峰检测或者叫脉搏波峰检测。算法逻辑不复杂设置一个动态阈值初始值为信号均值当信号从下方穿过阈值并达到局部最大值时记为一个脉搏峰。相邻两个峰值的时间差就是一次心跳周期。为了防止噪声引起的误检我加了一个不应期机制检测到峰值后的250ms内不接收新峰值。uint16_t HR_Calculate(uint16_t *ir_buffer, uint16_t length) { // 假设ir_buffer已经是滤波后的红外PPG信号 // 1. 计算信号均值作为初始阈值 uint32_t sum 0; for (uint16_t i 0; i length; i) { sum ir_buffer[i]; } uint16_t threshold sum / length; // 2. 峰值检测 uint16_t peak_count 0; uint16_t last_peak_index 0; uint32_t peak_interval_sum 0; for (uint16_t i 1; i length - 1; i) { if (ir_buffer[i] threshold ir_buffer[i] ir_buffer[i-1] ir_buffer[i] ir_buffer[i1]) { if (peak_count 0) { last_peak_index i; peak_count 1; } else { uint16_t interval i - last_peak_index; // 不应期检查300ms内不判为峰采样率100Hz即30个点 if (interval 30) { peak_interval_sum interval; peak_count; last_peak_index i; } } } // 动态更新阈值取最近信号的80%分位数简化版用均值 if (i % 10 0) { threshold (threshold * 3 (ir_buffer[i] ir_buffer[i-1]) / 2) / 4; } } if (peak_count 2) { return 0; // 数据不足无法计算 } uint16_t avg_interval peak_interval_sum / (peak_count - 1); // 采样率100Hz每分钟60秒 uint16_t bpm 6000 / avg_interval; return bpm; }这里有个实战技巧最后显示的心率不是直接拿当前周期算出来的瞬时心率而是做了一次5次平均的滑动滤波。瞬时心率会随着呼吸节奏有±5BPM的自然波动直接显示在屏幕上数字跳个不停看起来像系统不稳定实际是生理信号本身就是这个特性。滑动平均之后显示值稳定平滑整体感觉专业很多。3.4 血氧算法与温度读取血氧计算的核心是分离出红光和红外光的交流分量。工程上用的是一个简化方案在10秒的时间窗口内分别对红光和红外信号计算标准差再把各自的直流分量求平均用标准差替代AC幅值。这样做的精度不如FFT但胜在计算量极小对工程应用完全够用。uint8_t SpO2_Calculate(uint16_t *red_buffer, uint16_t *ir_buffer, uint16_t length) { // 计算R值 uint8_t spo2 0; float ac_r 0, dc_r 0, ac_ir 0, dc_ir 0; // 直流分量平均 uint32_t sum_r 0, sum_ir 0; for (uint16_t i 0; i length; i) { sum_r red_buffer[i]; sum_ir ir_buffer[i]; } dc_r (float)sum_r / length; dc_ir (float)sum_ir / length; // 交流分量标准差 float var_r 0, var_ir 0; for (uint16_t i 0; i length; i) { var_r (red_buffer[i] - dc_r) * (red_buffer[i] - dc_r); var_ir (ir_buffer[i] - dc_ir) * (ir_buffer[i] - dc_ir); } ac_r sqrt(var_r / (length - 1)); ac_ir sqrt(var_ir / (length - 1)); float R (ac_r / dc_r) / (ac_ir / dc_ir); // 经验公式 spo2 (uint8_t)(110 - 25 * R); // 范围限制 if (spo2 100) spo2 100; if (spo2 70) spo2 0; // 0表示无效 return spo2; }温度读取这块相对容易。DS18B20的操作流程是复位总线 → 发送跳过ROM命令0xCC → 发送启动温度转换命令0x44 → 等待750ms12位精度下的最大转换时间 → 复位总线 → 发送跳过ROM命令 → 发送读暂存器命令0xBE → 读取两个字节的温度数据。低字节的4个高有效位是符号位如果温度为负需要做补码转换。正数的计算是温度 ((低字节 0xFF) | (高字节 8)) 4这个值乘以0.0625就得到实际温度。我在代码里用了一个整数运算的优化方案直接对16位原始值乘以625再除以10000避免了浮点数运算在STM32上效率更高。注意DS18B20的转换时间是750ms也就是说温度没法做到每秒刷新所以我的显示刷新策略是温度1秒刷新一次在转换间隙穿插其他任务心率和血氧每10秒重新计算一次串口调试信息200ms打印一次。这样不会因为某个传感器等太久阻塞了整体流程。3.5 LCD1602显示驱动注意事项LCD1602用I2C转接板后操作的是PCF8574芯片一个字节数据被拆成两次发送先发高4位再发低4位每位配合使能脉冲。这里的时序有讲究PCF8574的速度上限是100kHz标准模式虽然很多模块能跑到400kHz但为了稳定起见我软件I2C的时钟设为50kHz。给LCD的每条指令之间要留足够的延时清屏命令需要2ms其余命令只需要40us。还有一个容易忽略的细节LCD1602初始化时如果上一次断电的时候正好处于光标移动模式重新上电后可能显示乱码。解决方案是在初始化函数里按照标准流程完整执行一遍延时40ms → 发0x33 → 延时5ms → 发0x32 → 延时1ms → 发0x28 → 延时1ms → 发0x0C开显示不显示光标→ 清屏 → 发0x06光标右移。步骤缺一不可特别是前面两个0x33和0x32是用来让LCD正确识别4位还是8位模式的握手协议。网上很多简化版的初始化代码把这两步省略了结果屏幕经常花屏就是这个原因。4. 调试过程、常见问题与设计报告写作要点4.1 我踩过的三个最大的坑第一个坑是硬件I2C死锁。STM32的硬件I2C在从设备拉低SDA线时总线会被锁死尤其是MAX30102这种上电时序严格的芯片如果复位时序不对I2C通信就直接卡住。排查方法是用示波器看SDA线的电平发现一直是低电平就知道总线被锁了。最终我干脆在I2C初始化前加了一步GPIO复位把SCL和SDA配置成普通推挽输出手动翻转9个时钟周期把可能处于半通信状态的从设备复位然后再切回复用开漏模式初始化I2C。这个“软件复位总线”的小技巧后来帮我解决了好几次莫名其妙的总线卡死。第二个坑是MAX30102读到的数据全是65535。这个值是FIFO数据为空的标志。现象是传感器初始化正常但读取寄存器永远是0xFFFF。排查后发现是硬件I2C的时钟速度问题STM32硬件I2C如果配置成400kHz快速模式MAX30102的上电时序和时钟延展配合不好就会导致FIFO读指针异常。把I2C时钟降到100kHz标准模式后问题迎刃而解。MAX30102的数据手册标称SCL最高支持400kHz但那是理想情况下实际应用多留点裕量总没错。第三个坑是数据明明有波形但计算出的心率偶尔会翻倍。后来通过串口把原始波形打印出来分析发现有个别脉搏波的波峰特别尖锐高过阈值后触发了两次峰值检测。加了我前面说的不应期机制后这个问题彻底解决。这类问题就是你光看计算结果很难定位必须把原始数据拉出来画图看才有头绪。所以我的调试代码里串口打印功能是常开的通过宏定义控制打印级别这在后期调算法时省了大力气。4.2 数据异常的快速排查表现象可能原因排查方法MAX30102读数全为0xFFFFFIFO为空、I2C死锁检查中断是否触发、复位I2C总线心率持续显示0或翻倍信号太弱、峰值检测误判观察红光ADC原始值是否在10000以上血氧显示80以下或0无法分辨AC信号、指数溢出检查红外信号幅度调整LED电流LCD1602显示方块或乱码I2C地址错误、初始化不完整扫描设备地址确认是0x27还是0x3FDS18B20返回85°C上拉电阻缺失、采样时序不对检查DQ引脚上拉到3.3V系统偶尔死机电源纹波过大、中断优先级冲突测量3.3V波形确认中断服务函数时长背光灯亮但无字符对比度电位器没调好调整转接板上的蓝色电位器这个表格里面的每一项我都在实际调试中遇到过。最玄学的是DS18B20读取返回85°C这个值其实是DS18B20的“上电复位值”说明根本没有成功读取到温度数据而是读到了暂存器里的初始状态。原因是你的复位时序太短传感器没被正确唤醒把DS18B20的复位低电平时间从480us增加到700us就能解决。4.3 设计报告的写作思路与内容规划标题里带了“带设计报告”这个项目的报告占比还是挺重要的尤其是作为课程设计或毕业论文的时候。报告别把它想得太复杂本质上就是把你这几个月做的东西按照问题、方案、实现、验证的逻辑链写清楚。我的建议是报告按六章来组织第一章是绪论交代项目的背景和意义可以从可穿戴健康监测设备的普及切入说明为什么需要这样一套基于嵌入式平台的生理参数监测系统。第二章是系统方案设计画总体框图对比几个备选方案比如用ESP32OLED或者用纯模拟电路搭建的优劣说明为什么最终选择STM32MAX30102DS18B20LCD1602组合。第三章是硬件设计重点论述MAX30102的电路连接、滤波电容配置、I2C总线上拉电阻计算和PCB布局注意点。第四章是软件设计展开讲主程序流程图、各传感器驱动函数实现、滤波算法和心率血氧计算原理。第五章是系统调试与测试结果放上实测数据表最好像我一样把测试数据整理成一个表不同测试者、不同状态静坐、跑步后、不同时间点的心率血氧读数。第六章是总结与展望把项目做得好的和不足的都写出来比如“运动伪迹对血氧测量干扰较大后续可结合加速度计进行运动补偿”“显示内容目前只有字符后续可以接OLED或TFT屏实现波形显示”。报告最容易出彩的地方是第五章的测试数据和分析别只写“经过测试系统工作正常”要写具体的数据比如“对10名测试者进行静息状态下的心率测试与脉搏血氧仪对比平均误差为1.8次/分钟最大误差不超过4次/分钟”。这样的数据摆在报告里给老师的印象是“这是真做了实验的”而不是从网上摘抄的。4.4 一些能提升项目完成度的进阶方案基础功能做完之后如果想在这个项目上再加分我建议从这几个方向里挑一个做扩展。第一个是加OLED波形显示把MAX30102的PPG原始波形画出来这比显示一个数字直观得多而且能顺便展示你的滤波效果展示时说服力很强。第二个是加蓝牙模块把心率血氧数据通过HC-05或者低功耗蓝牙发送到手机APP上做成一个迷你健康监测终端。第三个是数据存储用SPI接口的MicroSD卡模块定时记录数据后续可以用Python读出来分析长时心率变异性。这三个方向都不难但写进报告里就是“系统具备扩展性可方便地接入无线传输与数据记录模块”档次完全不一样。算法方面如果学有余力可以把心率计算的滤波方式从IIR升级成滑动窗口FFT直接在频域找峰值频率。这样抗干扰能力更强尤其是对运动伪迹的抑制效果更好。代价是计算量增大但F103跑128点FFT只需几毫秒完全扛得住。最后分享一点个人经验这个项目做完之后我对嵌入式的理解明显上了一个台阶。之前学STM32的时候都是跑跑GPIO点灯、串口发发数据这种孤立的小实验对这个芯片的认知是碎片化的直到做了这个综合项目才意识到把这些外设整合在一起的时候真正困难的不是单个模块的驱动而是如何让它们协调工作怎样处理中断和主循环的关系怎样在资源有限的情况下做算法优化。MAX30102的心率计算让我第一次认真思考数字信号处理里的滤波问题以前在课本上学的频域分析、数字滤波这些知识在这一刻突然就“活”了过来。最后再送你一句我的实操心得给这个项目多留出一周的时间专门用来调参数和实测你以为的“代码写完就万事大吉”是不存在的传感器的LED电流、滤波器的截止频率、检测阈值这些参数每项都得经过几十次实验才能调到最舒服的状态。我当时就是为了找一个适合大多数人的LED电流值让室友们轮流测了一个多小时才最终确定红光0x24、红外0x28这个配置。这种调试过程虽然枯燥但今天回想起来这才是做项目最大的收获。本文还有配套的精品资源点击获取