ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

STM32智能手环毕业设计:从传感器选型到心率计步算法实现

STM32智能手环毕业设计:从传感器选型到心率计步算法实现 简介本资源是一套完整的基于STM32的智能手环毕业设计实现方案面向嵌入式软硬件初学者、电子信息类本科生及毕业设计备赛学生解决心率、体温、运动数据步数/距离/速度一体化采集与本地可视化的核心问题。资源包共含数十个文件涵盖Keil工程源码、Altium Designer绘制的原理图与PCB参考、系统框图与程序流程图、开题报告与任务书模板、答辩技巧指南、参考论文及关键芯片ADXL345、心率传感器、DS18B20等资料压缩包大小为66.16MB结构清晰、模块对应明确便于分阶段理解与复现。已有4652人学习下载内容覆盖从硬件选型、传感器驱动开发、数据融合算法到LCD1602动态刷新的全流程实践特别适合需要快速构建可演示嵌入式健康监测系统的课程设计或毕业项目使用者。1. 项目缘起一个毕业设计的务实选择又到了一年一度的毕业设计季对于电子、自动化、嵌入式相关专业的同学来说选一个“好做、能出活、有亮点”的题目往往是整个毕业季最头疼的开端。太简单了显得没水平答辩时容易被老师问住太复杂了时间精力有限容易烂尾。我当年也经历过这个阶段所以当有学弟学妹来问我选题建议时我通常会推荐类似“基于STM32的智能手环”这样的项目。它听起来很“智能”很“物联网”但实际上当你把它拆解开来会发现它几乎涵盖了单片机应用开发的所有核心知识点传感器数据采集、实时算法处理、人机交互显示、低功耗设计甚至还能浅浅地触摸到一些无线通信的边。更重要的是STM32的生态足够成熟资料多社区活跃遇到问题容易找到解决方案这对于一个需要在有限时间内独立完成的项目来说是至关重要的“安全感”来源。这个“智能手环脉搏心率计步器体温显示设计”就是一个非常典型的、具有高度可操作性的毕业设计选题。它不是一个空中楼阁的概念而是由几个明确的、可量化的功能模块组成通过特定传感器测量脉搏心率、通过加速度传感器实现计步、通过温度传感器测量体温最后将所有这些信息整合在一块小小的OLED屏幕上显示出来。整个系统的核心就是那颗我们熟悉的STM32单片机。它像是一个勤奋的管家不断地从各个传感器那里收集数据经过一番计算和判断再把结果清晰地呈现给用户。接下来我就结合自己这些年折腾嵌入式项目的经验把这个项目的里里外外、从硬件选型到软件实现的完整脉络以及那些容易踩坑的细节给大家捋清楚。2. 核心功能拆解与传感器选型逻辑一个项目能不能成功第一步的“拆解”和“选型”至关重要。你不能一上来就对着STM32库函数猛敲代码得先想明白你要的每个功能到底对应着物理世界里的哪个器件以及为什么选它。2.1 脉搏心率检测PPG传感器的原理与选型这是整个手环里技术含量相对较高的部分。现在市面上主流的心率检测方案是光电容积脉搏波描记法也就是PPG。它的原理其实很直观利用人体组织对特定波长光线的吸收率会随着血液脉搏流动而周期性变化的特性。传感器一般包含一个发光二极管和一个光电探测器。LED发出绿光因为绿光对血液中血红蛋白的吸收率变化更敏感且受皮肤黑色素影响较小光线射入皮肤部分被血液吸收部分反射回来被光电探测器接收。心脏跳动一次血管里的血液容积就变化一次反射回来的光强也就随之波动一次。探测器将这个光信号转换为微弱的电信号STM32的ADC模数转换器负责采集这个信号后续的算法再从这充满噪声的信号中提取出脉搏的周期。对于毕业设计我强烈推荐使用集成化的心率传感器模块而不是自己用分立元件去搭。自己搭光路、处理微弱信号电磁干扰和噪声会让你怀疑人生。常见的模块有MAX30102和MAX30105。这两者都是非常成熟的选择。MAX30102经典款集成了红光和红外光LED以及一个光电探测器、环境光消除电路。它本身不直接输出心率值而是输出原始的PPG波形数据红光和红外光两个通道。你需要用STM32通过I2C接口读取这些原始数据然后在单片机里自己写算法比如寻找波峰、计算间隔来算出心率。这给了你很大的发挥空间也是答辩时展示你算法能力的亮点。但挑战在于原始信号噪声大人体轻微晃动、传感器佩戴松紧都会影响算法鲁棒性需要仔细调试。MAX30105在MAX30102的基础上增加了绿光LED对心率的检测理论上更准。但它同样输出原始数据。还有一类是像PulseSensor这样的模拟传感器它输出的是一个模拟电压信号直接接STM32的ADC引脚即可。好处是接口简单坏处是需要自己设计放大滤波电路且抗干扰能力更弱。我的选型建议是如果你的时间和能力允许想挑战一下信号处理算法选MAX30102。如果你希望更专注于系统集成和功能实现可以考虑一些已经内置了心率计算算法的模块比如某些厂家基于MAX30102封装的“心率模块”直接通过串口输出心率数值这样STM32只需要解析串口数据即可大大降低了难度。在毕业设计中能稳定地把整个系统跑通比在一个点上死磕更重要。2.2 计步功能加速度计的数据与算法计步的本质是识别“行走”这个周期性动作。我们通过三轴加速度计MPU6050、MPU9250或更便宜的LIS3DH来捕捉身体运动的加速度变化。人在走路时加速度会在三个轴上呈现有规律的周期性波形。这里的关键不是硬件而是软件算法。最简单的计步算法是“阈值判断法”数据预处理读取加速度计的三轴数据(ax, ay, az)计算合加速度a_total sqrt(ax^2 ay^2 az^2)。这个值消除了手环方向的影响。滤波对a_total进行低通滤波比如滑动平均滤波滤除高频抖动。寻找波峰设置一个动态或固定的加速度阈值。当滤波后的合加速度值超过阈值并在之后一段时间内回落则计为一个有效步数。但这个简单算法误判率很高比如快速挥手也会被计步。更优的方案是结合“波峰波谷检测”和“时间窗口判决”。例如不仅要求超过阈值还要求两次有效步数之间的时间间隔在正常人步行频率范围内比如200ms到1.5秒之间。更进阶的可以引入姿态识别先判断设备是否处于佩戴状态以及佩戴部位手腕再启用计步算法这需要用到加速度计和陀螺仪MPU6050就包含陀螺仪进行姿态解算。实操心得对于毕业设计实现基础阈值算法完全足够。重点在于如何通过实测把手环戴在手上走几步来调整滤波参数和阈值使其在慢走、快走等不同场景下都能相对准确。你可以将实时加速度波形通过串口发送到电脑用串口绘图工具如Serial Plotter可视化这样调试起来非常直观。2.3 体温显示接触式与非接触式的权衡体温检测听起来简单但选型有讲究。核心区别在于接触式和非接触式。接触式最典型的就是DS18B20数字温度传感器。它的优点是精度高±0.5°C、接口简单单总线、价格便宜。但问题是它是测量环境温度或物体表面温度的。要测体温必须让传感器的金属探头紧贴皮肤。这在手环设计上会带来结构难题你需要为它设计一个必须紧贴皮肤的凸起结构用户体验不好且长期佩戴可能不适。非接触式即红外测温传感器如MLX90614。它通过测量人体皮肤表面辐射的红外能量来反推体温。优点是非接触可以集成在手环背面无需紧压皮肤。但它的测量结果极易受环境温度、测量距离、皮肤表面状况有无汗液影响。而且它测量的是体表温度通常比核心体温如口腔、腋下低1-2°C需要进行算法补偿。我的建议对于毕业设计从易用性和成本考虑可以优先选择DS18B20。你可以在手环的样品或仿真中将其安置在一个模拟“紧贴皮肤”的位置。在答辩时你需要清楚地说明这一点本设计采用接触式测温方案实际产品中需要考虑结构设计与用户舒适度。如果你选用MLX90614那么你必须在你的软件中增加温度补偿算法并且要在不同环境温度下进行校准测试这部分的工作量会大很多但同时也是答辩的加分项。2.4 信息显示OLED屏幕的驱动与界面设计显示部分无疑是提升项目“颜值”和完成度的关键。0.96寸或1.3寸的I2C接口OLED屏SSD1306驱动是绝配。它功耗低、分辨率够用128x64、接口简单且有成熟的驱动库如u8g2、Adafruit_SSD1306等都有STM32的移植版本。这里的技术重点不在于点亮屏幕而在于界面UI设计和信息刷新策略。界面布局小小的屏幕要显示心率、步数、体温、时间如果加了RTC甚至电量。你需要合理规划布局。可以采用分页轮播的方式比如第一页显示心率和实时波形第二页显示步数和体温第三页显示日期时间。通过一个按键或触摸感应进行切换。刷新优化频繁刷新全屏会导致屏幕闪烁且增加功耗。需要采用局部刷新策略。例如只有变化的数字部分才进行重绘静态的标签如“HR:”、“Step:”只绘制一次。STM32的硬件I2C速度很快足以支持平滑的刷新。字体与图形为了美观可以导入一些小字体和简单的图标心形、脚步、温度计符号。这些字模和图标可以用专门的取模软件生成以数组的形式存储在代码中。避坑指南很多同学在移植OLED驱动库时会卡在初始化不成功上。最常见的原因是I2C的引脚配置开漏输出、上拉电阻不对或者I2C的时序速度时钟频率设置过快。建议先用一个简单的I2C扫描程序确认STM32能正确识别到OLED屏幕的地址通常是0x3C或0x3D这是硬件连接和底层驱动正确的标志。3. 硬件系统架构与核心电路设计要点确定了“用什么”接下来就要规划“怎么连”。一个清晰可靠的硬件架构是软件稳定运行的基础。3.1 主控芯片选型STM32家族中的性价比之王STM32型号繁多对于这个项目我们不需要跑Linux不需要超大内存核心需求是足够的IO口、多个ADC通道、I2C和UART接口、较低的功耗。因此STM32F1系列的STM32F103C8T6蓝色小开发板核心芯片是经久不衰的性价比之王。它拥有72MHz主频、64KB Flash、20KB RAM、3个USART、2个I2C、2个SPI、2个ADC资源完全过剩。如果考虑更低功耗手环的终极追求可以看向STM32L系列如STM32L151C8T6。但F103的资料是最多的生态是最完善的在毕业设计这个阶段“减少不确定性”比“追求极致参数”更重要。3.2 电源管理设计续航能力的生命线这是手环类设备硬件设计的核心也是容易被学生忽略的部分。你不能一直用USB供电来演示。供电电池首选可充电的锂聚合物电池3.7V容量在200mAh到500mAh之间体积小巧。充电管理需要一个充电管理芯片如TP4056。它负责将USB口的5V电压安全地转换为对锂电池的恒流/恒压充电。电路非常简单基本是标准接法。电压转换锂电池电压是3.7V满电4.2V放电截止约3.0V而STM32和大多数传感器需要稳定的3.3V工作电压。因此需要一个低压差线性稳压器如AMS1117-3.3。这里要注意LDO的压差当电池电压降到3.5V时AMS1117可能就无法输出稳定的3.3V了。更优的选择是使用DC-DC降压芯片如MP2359它的转换效率高且能在更宽的输入电压范围内比如2.5V到5V输出稳定的3.3V能更充分地利用电池电量显著延长续航。电量检测为了在屏幕上显示电量需要检测电池电压。由于电池电压高于STM32的ADC测量范围通常0-3.3V需要用两个电阻组成分压电路将电池电压分压一半后再送入ADC引脚。计算公式很简单V_bat ADC_Value * (3.3V / 4096) * (R1R2)/R2。通常R1和R2可以都取100kΩ。重要提示在绘制PCB或焊接万用板时电源走线要尽量粗并且在关键芯片的电源引脚附近一定要放置一个0.1uF的陶瓷去耦电容并尽量靠近引脚。这是抑制电源噪声、保证系统稳定的基石很多莫名其妙的复位、数据错误都源于此。3.3 传感器与主控的连接拓扑所有传感器和屏幕都通过I2C总线连接这是最简洁的方案。但要注意I2C的总线负载和地址冲突。拓扑STM32的I2C引脚如PB6/PB7作为主机SCL时钟线和SDA数据线上并联连接所有从设备。记得在SDA和SCL线上各接一个4.7kΩ的上拉电阻到3.3V。地址冲突MPU6050的默认地址是0x68MLX90614的默认地址是0x5AOLED SSD1306的地址是0x3C。MAX30102的I2C地址是0x57。这些地址是错开的所以可以挂在同一总线上。如果遇到地址冲突比如两个相同型号的传感器可以通过芯片的地址选择引脚如果有来修改。除了I2CDS18B20如果选用使用单总线协议只需接一个GPIO口并接一个4.7kΩ的上拉电阻。计步按键或界面切换按键则接普通的GPIO输入口配置为上拉输入模式按键另一端接地。4. 软件系统框架与关键模块实现硬件是躯体软件是灵魂。一个好的软件框架能让开发、调试和维护事半功倍。4.1 开发环境与工程搭建首选STM32CubeIDE。它是ST官方推出的免费集成开发环境基于Eclipse集成了STM32CubeMX图形化配置工具。对于新手来说最大的好处是可以通过CubeMX直观地配置时钟、引脚、外设I2C、ADC、UART等自动生成初始化代码避免了繁琐的寄存器操作。创建工程步骤在CubeMX中选择你的芯片型号STM32F103C8Tx。配置系统时钟树通常使用外部8MHz晶振通过PLL倍频到72MHz。图形化配置引脚将用于I2C的PB6、PB7配置为I2C1 SCL和I2C1 SDA模式为开漏输出Open Drain并启用内部上拉。将连接DS18B20的引脚配置为GPIO_Output用于驱动和GPIO_Input用于读取初始化为高电平。将按键引脚配置为GPIO_Input并启用内部上拉。将用于ADC检测电池电压的引脚如PA0配置为ADC1_IN0。在Middleware中间件中如果需要可以启用FreeRTOS。对于这个项目使用一个简单的前后台超级循环系统完全够用更易于理解。但如果想挑战一下用FreeRTOS创建几个独立的任务如传感器数据采集任务、数据处理任务、显示任务会让程序结构更清晰也是嵌入式学习的一个进阶。生成工程代码用CubeIDE打开。4.2 驱动程序层与传感器对话这一层是直接操作硬件外设读取原始数据的部分。I2C驱动CubeMX生成的HAL库代码已经提供了HAL_I2C_Mem_Read和HAL_I2C_Mem_Write函数可以直接用来读写传感器寄存器。你需要为每个传感器编写一个封装函数例如MAX30102_ReadFIFO()、MPU6050_ReadAccel()。关键点每次I2C操作后要检查返回值做好错误处理。I2C通信容易受干扰增加重试机制是个好习惯。ADC驱动配置ADC为连续扫描模式DMA传输。这样可以在后台不间断地采集心率传感器的模拟信号如果使用模拟式PulseSensor和电池电压不占用CPU资源。对于MAX30102这类数字传感器则不需要ADC。单总线驱动为DS18B20编写严格的时序函数包括复位脉冲、写一位、读一位。单总线对时序要求非常苛刻建议将系统滴答定时器SysTick的延时函数精度提高到微秒级并关闭中断以保证时序关键段不被打断。OLED驱动移植一个轻量级的驱动库如u8g2。重点是实现其底层的u8x8_byte_hw_i2c回调函数该函数内部调用HAL库的I2C发送函数。4.3 数据处理与算法层从噪声中提取信息这是项目的精华所在决定了手环的“智能”程度。心率算法数据缓冲开辟一个数组持续存储MAX30102读取到的红光或绿光PPG数据比如每秒100个点。滤波先进行直流分量去除减去一段数据的平均值然后进行带通滤波例如0.5Hz到5Hz对应心率30-300 BPM滤除基线漂移和高频噪声。可以在STM32上实现一个简单的IIR或FIR滤波器。波峰检测在滤波后的数据流中寻找满足条件的波峰幅度超过阈值且是局部最大值。记录波峰出现的时间戳。心率计算计算连续两个波峰的时间间隔峰峰间隔PPI心率BPM 60 / PPI秒。为了显示稳定可以计算最近几个心率值的移动平均。注意PPG信号非常脆弱。算法中必须加入运动伪差检测。当检测到加速度计数据剧烈变化意味着用户在运动时可以提示用户保持静止或者此时的心率数据标注为不可信不更新显示。计步算法读取加速度计三轴数据计算向量模。进行低通滤波滤除高频抖动。设置一个动态阈值。一个简单的动态阈值更新方法是阈值 系数1 * 历史平均值 系数2 * 当前最大值。当滤波后的数据超过阈值并且与前一个有效步数的时间差在合理步行间隔内则计为一步同时更新步数和时间戳。体温补偿算法如果使用MLX90614 需要同时读取MLX90614测得的物体温度体温和环境温度。根据传感器数据手册提供的公式或查找表进行补偿计算。一个简化的思路是校正体温 测量体表温度 k * (测量环境温度 - 参考环境温度)其中k是一个经验系数需要通过实验标定。4.4 应用层与显示逻辑整合与呈现这一层负责调度各个功能模块并管理用户界面。// 伪代码示意主循环逻辑 int main(void) { // 硬件初始化 System_Init(); // 时钟、GPIO、外设 Sensor_Init(); // 所有传感器初始化 Display_Init(); // OLED初始化 Timer_Init(); // 定时器用于定时采集 while (1) { // 1. 检查定时标志定时采集传感器数据 if (data_ready_flag) { data_ready_flag 0; HeartRate_Sample(); // 读取MAX30102数据 Accel_Sample(); // 读取MPU6050数据 Temp_Sample(); // 读取温度传感器数据 Battery_Check(); // 读取电池电压 } // 2. 运行核心算法 HeartRate_Process(); // 处理数据更新心率值 Step_Process(); // 处理数据更新步数 Temp_Process(); // 处理温度数据 // 3. 处理用户输入按键 Key_Scan(); if (key_pressed) { page_index (page_index 1) % TOTAL_PAGES; // 切换显示页面 } // 4. 更新显示根据当前页面索引 Display_Refresh(page_index); // 5. 低功耗处理可选 // 如果没有任务可以进入休眠模式由定时器中断唤醒 // __WFI(); } }显示页面管理用一个全局变量current_page来记录当前页面。在Display_Refresh()函数里用switch-case根据current_page来绘制不同的内容。绘制时注意只更新变化的部分。5. 调试、优化与功能扩展思路系统能跑起来只是第一步让它跑得稳、跑得好才是毕业设计拿高分的关键。5.1 系统联调与问题排查当把所有代码整合在一起常常会遇到各种问题。一套高效的调试方法至关重要。“分而治之”永远不要一次性集成所有模块。应该先确保每个传感器单独工作正常。例如先写一个测试程序只读取MPU6050的数据并通过串口打印出来用串口助手或绘图工具看波形是否合理。然后再测试MAX30102最后再整合。串口调试助手是你的最佳伙伴充分利用串口打印日志。在关键函数入口、出口、错误分支加上printf输出变量值、状态标志。这能帮你快速定位程序卡在哪里。逻辑分析仪是神器如果条件允许用逻辑分析仪抓取I2C、单总线的波形。可以直观地看到通信时序是否正确数据内容是什么。这是排查硬件通信问题的终极手段。常见问题库I2C通信失败检查上拉电阻一定要接检查从设备地址是否正确用I2C扫描程序检查STM32的I2C引脚配置模式必须是开漏输出。心率数据全是0或乱跳检查MAX30102的FIFO是否已启用读取前先检查FIFO数据计数寄存器。确保LED电流设置合适不能太小。计步不准调整加速度计的量程±2g或±4g通常适合计步。重点调试滤波算法的参数和计步阈值。在不同人身上测试取一个折中的参数。OLED不显示除了检查I2C连接还要检查初始化序列是否正确发送。有些OLED模块需要较高的初始化电压确认VCC供电是否足3.3V。5.2 功耗优化初探虽然毕业设计对功耗可能不做硬性要求但如果你能提出来并做一些简单优化会是很大的亮点。外设电源管理不用的传感器可以通过一个GPIO口控制MOS管来切断其电源。例如心率监测不是连续的可以每2秒唤醒测量一次测量完就关闭MAX30102的电源。主控睡眠模式在超级循环的末尾如果没有任务要做可以让STM32进入睡眠模式Sleep或停止模式Stop。睡眠模式下由定时器中断唤醒停止模式功耗更低但唤醒时间稍长。使用HAL库的HAL_PWR_EnterSLEEPMode()或HAL_PWR_EnterSTOPMode()函数即可。降低主频在不需要高性能处理时可以通过降低系统时钟SYSCLK来节省功耗。例如平时以32MHz运行需要处理数据时再切换到72MHz。5.3 功能扩展与答辩亮点在完成基本功能后可以考虑以下扩展让你的设计脱颖而出无线数据传输增加一个蓝牙模块如HC-05、HC-08或更专业的BLE模块如nRF51822将心率、步数数据发送到手机APP上显示。这立刻将项目提升到了“物联网”层面。你需要学习蓝牙串口协议或BLE协议栈。数据存储与回顾增加一个SPI Flash芯片如W25Q16用于存储历史步数、心率曲线。可以设计一个界面查看过去一天或一周的统计。加入RTC实时时钟使用STM32内部的RTC需外接32.768kHz晶振或外部RTC芯片如DS1302实现时间显示和基于时间的运动数据统计。更复杂的健康算法除了瞬时心率可以计算心率变异性的简单指标或者根据持续监测的心率和运动量给出简单的“活力指数”评分。精美的外壳与结构设计用3D打印为你的手环制作一个定制外壳将电路板、电池、屏幕完美集成进去。一个外观精致、可佩戴的实物远比一堆散乱的开发板和杜邦线更有说服力。这个基于STM32的智能手环项目就像是一个微缩的嵌入式系统开发实战演练场。它串联起了传感器技术、模拟数字电路、实时信号处理、低功耗设计和人机交互等多个重要知识点。完成它的过程必然会遇到无数次的调试、失败和再尝试但这正是工程师成长的必经之路。当你最终看到屏幕上随着自己心跳而跳动的数字以及稳步增长的步数时那种成就感是无与伦比的。希望这份详细的拆解能为你点亮毕业设计路上的第一盏灯助你少走弯路做出一个让自己和导师都满意的作品。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进