
简介这是一份面向嵌入式初学者与高校实践教学的ESP32智能手环完整开发资源适用于毕业设计、课程设计、实训项目及物联网竞赛选题。项目实现心率血氧监测、Wi-Fi联网获取实时时间/天气/B站粉丝数、闹钟提醒喝水/吃药、秒表与计步功能代码经过实机测试可直接烧录运行。压缩包共20个文件含3份README说明文档、Fritzing电路图.fzz、PCB实物参考图.jpg/.png、核心固件源码.cpp/.h、配置文件.json/.ini及配套工具ImageChange2.0.exe结构清晰软硬协同完整。已有120人学习下载资源特别适配零PCB基础者——提供面包板模块连线方案降低复现门槛同时支持二次开发可快速扩展传感器或UI交互。所有内容聚焦真实嵌入式物联网开发流程涵盖硬件连接、FreeRTOS任务调度、HTTP/HTTPS通信、OLED驱动与低功耗优化等关键技术点。1. 项目缘起为什么选择ESP32来打造你的第一块智能手环如果你对物联网和嵌入式开发感兴趣想亲手做一个能戴在手腕上的、功能可定制的智能设备那么基于ESP32设计一款智能手环绝对是一个能让你从硬件到软件、从传感器到云端都玩个遍的绝佳练手项目。市面上成熟的智能手环产品很多但它们的固件是封闭的功能是固定的你很难去深度定制或者理解其内部运作的每一个环节。而自己动手从零开始意味着你拥有完全的掌控权心率监测的算法可以自己调表盘UI可以随心所欲地设计甚至可以把数据同步到你自己的服务器上。那么为什么是ESP32这几乎是当前DIY智能穿戴和物联网项目的“标准答案”。首先它集成了双核处理器和Wi-Fi、蓝牙包括经典蓝牙和低功耗蓝牙BLE功能于一身这意味着你的手环既能通过BLE与手机App高效、低功耗地通信也能在连接Wi-Fi时直接上传数据到云端无需手机中转。其次它拥有丰富的外设接口I2C, SPI, ADC, DAC等可以轻松连接心率传感器、加速度计、OLED显示屏等各类模块。最后其庞大的开源社区和丰富的开发资源如Arduino Core for ESP32、ESP-IDF让开发门槛大大降低。无论是用Arduino IDE快速原型验证还是用ESP-IDF或PlatformIO进行更专业的开发你都能找到海量的教程和库支持。这个项目适合有一定编程基础比如接触过C/C或Python的爱好者、学生或嵌入式开发者。它不只是一个简单的“点亮屏幕”的玩具而是一个涉及低功耗设计、传感器数据采集与滤波、蓝牙协议通信、嵌入式GUI如LVGL开发、电源管理等多个核心技术的综合性实战。通过完成它你获得的将是一块独一无二的手环更是一套完整的嵌入式系统开发经验。2. 核心硬件选型与电路设计要点动手之前硬件是骨架。对于智能手环我们需要在极小的空间内集成计算、感知、显示和供电单元选型必须精打细算。2.1 主控芯片ESP32家族型号详解ESP32本身是一个系列对于手环项目我们需要在性能、功耗和封装尺寸上做权衡。ESP32-WROOM-32系列最经典、资源最丰富的型号通常以模组形式出现集成了晶振、Flash、天线等。但对于手环来说它的尺寸约18mm x 25.5mm可能偏大功耗也相对较高。适合作为初期在开发板上验证功能的阶段使用。ESP32-S系列这是更推荐的选择。ESP32-S3尤其突出它性能更强支持USB OTG可用于直接烧录和调试蓝牙5.0且部分型号封装更小。ESP32-S2则主打单核和USB但缺少蓝牙不适合手环。因此ESP32-S3是平衡性能、功耗和未来扩展性如图像识别的优选。封装选择尽量选择QFN封装如ESP32-S3FN8它比WROOM模组体积小得多更适合集成到紧凑的腕带PCB中。你需要具备一定的焊接能力热风枪来处理这类芯片。注意如果追求极致低功耗和简单功能也有更小的ESP32-C3单核RISC-VBLE5.0可选但其生态系统和计算能力稍弱于S3。2.2 传感器模块让手环“感知”世界手环的智能源于传感器。以下是几个核心传感器及其选型接口心率与血氧传感器PPG这是健康监测的核心。MAX30102是一个经典且廉价的模块集成了红光和红外LED及光电探测器通过I2C接口输出原始光容积脉搏波PPG数据。但请注意它只提供原始数据心率HR和血氧饱和度SpO2算法需要你自己在ESP32上实现或集成现有库如“MAX30102lib”这对算法能力有一定要求。更高集成度的方案如生物传感器AFE但成本和复杂度也更高。运动传感器IMU用于计步、睡眠监测、手势识别。MPU60503轴加速度3轴陀螺仪或MPU9250再加磁力计是常见选择同样通过I2C通信。计步算法如峰值检测需要你在代码中实现。环境光传感器ALS用于自动调节屏幕亮度。BH1750I2C是简单可靠的选择。所有传感器都应选择小封装的贴片型号并尽量规划在PCB的同一面以便贴近手腕皮肤。2.3 显示与交互单元显示屏手环屏幕需要低功耗、高对比度。OLED有机发光二极管是首选因为它自发光黑色像素不耗电非常适合显示时间、心率等简单信息。常见尺寸为0.96英寸或1.3英寸分辨率128x64或128x128通信方式为I2C或SPI。SPI刷新更快适合动画I2C更省引脚。对于更复杂的UI可以选择驱动IC为ST7789或ILI9341的TFT液晶屏但功耗会显著增加。触摸与按键除了屏幕触摸如果选用电容触摸屏物理按键必不可少。通常需要1-2个贴片按键用于开关机、返回、功能切换。按键电路需做硬件消抖RC电路或在软件中处理。振动电机用于消息提醒、闹钟。选择一个微型扁平振动马达Coin Vibration Motor通过一个MOS管如AO3400由ESP32的GPIO控制其通断即可。2.4 电源管理与电路设计核心这是手环能否“智能”续航的关键也是最容易踩坑的地方。电池选用一块小型聚合物锂电池Li-Po容量在100mAh到200mAh之间电压3.7V。需要配套一个充放电管理芯片如TP4056它负责安全充电恒流/恒压并带有电池状态输出。电压转换ESP32及大部分传感器需要3.3V供电。电池电压在3.7V-4.2V之间变化因此需要一个低压差线性稳压器LDO如AMS1117-3.3将电压稳定在3.3V。LDO的效率虽不如DCDC但电路简单、噪声小。低功耗设计电源路径管理使用MOS管构建电源开关电路让ESP32在深度睡眠Deep Sleep时能彻底断开传感器、屏幕等外围电路的供电仅保留RTC电路和唤醒源的微弱电流。ESP32的睡眠模式充分利用ESP32的深度睡眠Deep Sleep模式。在此模式下仅RTC模块和ULP协处理器可处理简单传感器数据保持供电电流可降至10μA级别。可以通过定时器Timer Wake-up或外部引脚如按键中断Ext0/Ext1 Wake-up唤醒。外围电路选型选择支持关断Shutdown或睡眠模式的传感器并在代码中不使用时将其断电。电路设计时建议使用KiCad或EasyEDA这类工具绘制原理图和PCB。PCB应设计为柔性电路板FPC或刚性-柔性结合板以适应腕带的弯曲。布局上电池和振动电机等较重元件应靠近腕带扣合处以保持佩戴平衡。3. 固件开发从环境搭建到核心功能实现硬件准备就绪后我们进入软件世界。这里以PlatformIO Arduino框架为例因为它库管理方便生态丰富适合快速开发。3.1 开发环境搭建与项目初始化安装PlatformIO如果你使用VS Code直接安装PlatformIO IDE插件即可。它内置了ESP32的编译工具链无需手动配置。创建新项目在PlatformIO中新建项目选择Board为“Espressif ESP32 Dev Module”或其他具体型号如ESP32-S3-DevKitC-1Framework选择“Arduino”。管理库依赖在项目的platformio.ini配置文件中你可以声明所需的库。例如[env:esp32dev] platform espressif32 board esp32dev framework arduino monitor_speed 115200 ; 库依赖 lib_deps adafruit/Adafruit GFX Library ^1.11.9 adafruit/Adafruit SSD1306 ^2.5.10 sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library ^1.1.2 bblanchon/ArduinoJson ^6.21.3通过这种方式PlatformIO会自动下载和管理这些库比Arduino IDE的库管理器更清晰。3.2 驱动层传感器与屏幕的代码封装首先我们需要为每个硬件模块编写或封装驱动代码确保它们能稳定工作。// 示例MAX30102心率传感器驱动封装 (heart_sensor.h/cpp) class HeartRateSensor { public: bool begin(TwoWire wirePort Wire); // 初始化 bool isPresent(); // 检测传感器 void setLEDBrightness(uint8_t brightness); // 设置LED亮度以平衡功耗和信号质量 bool checkForData(); // 检查是否有新数据 uint32_t getRedValue(); // 获取红光原始值 uint32_t getIRValue(); // 获取红外原始值 void shutdown(); // 进入低功耗关断模式 void wakeUp(); // 从关断模式唤醒 private: MAX30105 sensor; // 使用现有的库对象 // 添加你的校准和滤波参数 };在实现类时关键点在于初始化序列严格按照传感器数据手册的时序要求。错误处理I2C通信可能失败必须有重试或故障上报机制。低功耗接口暴露shutdown()和wakeUp()方法供上层电源管理调用。屏幕驱动如Adafruit SSD1306和IMU驱动如MPU6050也采用类似的封装模式。这样在主程序里我们面对的就是一个个清晰的对象而非一堆全局函数和变量。3.3 应用层核心多任务与低功耗调度手环需要同时处理多项任务更新显示、读取传感器、处理蓝牙通信。在单线程的Arduino环境中我们需要用状态机和非阻塞延时来模拟多任务。// 主循环状态机示例 void loop() { unsigned long currentMillis millis(); // 任务1: 每100ms更新一次时间显示非阻塞 if (currentMillis - prevDisplayUpdate 100) { prevDisplayUpdate currentMillis; updateDisplay(); } // 任务2: 每20ms读取一次心率传感器数据 if (currentMillis - prevSensorRead 20) { prevSensorRead currentMillis; readSensorData(); processHRAlgorithm(); // 在缓冲区积累足够数据后计算心率 } // 任务3: 处理蓝牙事件事件驱动随时处理 handleBLEEvents(); // 任务4: 检查是否需要进入深度睡眠 if (shouldEnterDeepSleep()) { prepareForDeepSleep(); // 关闭传感器、屏幕保存状态 esp_deep_sleep_start(); // 进入深度睡眠等待中断唤醒 } }低功耗调度策略定义一个“活动级别”。例如级别0活跃用户正在操作屏幕常亮传感器全速采样蓝牙连接。级别1待机屏幕熄灭传感器降频采样如每秒一次蓝牙保持连接但降低广播间隔。级别2睡眠关闭所有外围设备ESP32进入轻度睡眠Light Sleep仅通过定时器或外部中断唤醒。级别3深度睡眠保存必要数据到RTC内存关闭绝大部分电路仅靠RTC定时器或按键中断唤醒用于长时间待机。通过判断用户无操作时间、是否在充电、时间点夜晚等因素在不同级别间切换。3.4 蓝牙BLE通信与手机App联动智能手环与手机的交互主要通过BLE完成。我们需要在ESP32上实现一个GATT通用属性配置文件服务器。定义GATT服务与特征值设备信息服务包含设备名称、厂商信息等。电池服务报告电池电量。自定义健康数据服务这是核心。创建一个自定义UUID的服务在其中定义多个特征值Characteristic心率测量通知Notify属性手机可以订阅当手环计算出新心率时自动推送。步数数据读Read或通知属性。传感器控制写Write属性手机App可以发送命令如开始测量、校准。使用Arduino BLE库ESP32 Arduino Core内置了BLEDevice、BLEServer、BLECharacteristic等类可以方便地构建上述结构。// 创建服务和特征值示例 BLEService *pHealthService pServer-createService(SERVICE_UUID); BLECharacteristic *pHeartRateChar pHealthService-createCharacteristic( HEART_RATE_CHAR_UUID, BLECharacteristic::PROPERTY_NOTIFY ); // 设置描述符用于客户端配置通知 pHeartRateChar-addDescriptor(new BLE2902());数据发送当有心率新数据时调用pHeartRateChar-setValue(hrValue, 1)和pHeartRateChar-notify()即可通知已连接的手机。手机端App可以使用MIT App Inventor图形化简单、React Native或Flutter需要编程来开发一个简易App扫描并连接手环订阅心率通知并显示数据。4. 进阶实战嵌入式GUI与数据算法基础功能跑通后我们可以让手环变得更“聪明”和“好看”。4.1 使用LVGL打造炫酷表盘当你的屏幕是彩色TFT且性能足够时LVGL是一个强大的开源嵌入式图形库可以让你设计出媲美商业产品的UI。在PlatformIO中集成LVGL通过库管理器安装lvgl/lvgl库。由于LVGL本身是一个图形库你还需要为你的屏幕驱动安装一个“显示驱动”和“输入设备驱动”接口库或者自己实现。初始化与基础循环#include lvgl.h #include TFT_eSPI.h // 假设使用TFT_eSPI驱动屏幕 TFT_eSPI tft TFT_eSPI(); static lv_disp_draw_buf_t draw_buf; static lv_color_t buf[TFT_WIDTH * 10]; // 定义显示缓冲区 void setup() { // 初始化屏幕 tft.begin(); tft.setRotation(1); // 初始化LVGL lv_init(); lv_disp_draw_buf_init(draw_buf, buf, NULL, TFT_WIDTH * 10); // 注册显示驱动 static lv_disp_drv_t disp_drv; lv_disp_drv_init(disp_drv); disp_drv.hor_res TFT_WIDTH; disp_drv.ver_res TFT_HEIGHT; disp_drv.flush_cb my_disp_flush; // 你需要实现这个函数用于将LVGL的图形数据刷到屏幕上 disp_drv.draw_buf draw_buf; lv_disp_drv_register(disp_drv); // 创建UI create_ui(); } void loop() { lv_timer_handler(); // 必须定期调用处理LVGL任务 delay(5); }设计UI你可以使用LVGL丰富的控件按钮、标签、图表、滑块等来构建表盘、菜单、设置页面。设计过程可以在PC端的模拟器上进行然后再移植到设备上大大提高效率。4.2 心率算法从理论到实现MAX30102等传感器给出的是原始的PPG波形数据从中提取心率是一个信号处理过程。数据预处理直流滤波PPG信号包含直流DC和交流AC分量。心率信息主要在AC分量中。可以使用一个高通滤波器如截止频率0.5Hz的巴特沃斯滤波器来移除DC偏移。去噪信号可能包含运动伪影Motion Artifacts和电源工频干扰。可以使用带通滤波器如0.5Hz - 5Hz来保留心率可能的频率范围对应30-300 BPM。在嵌入式环境下IIR滤波器比FIR滤波器计算量更小更常用。峰值检测在滤波后的信号中每个波峰对应一次心跳。算法需要动态计算信号的均值和标准差设定一个自适应的阈值。寻找超过阈值且是局部最大值的点记为波峰。计算连续波峰之间的时间间隔Inter-Beat Interval, IBI。心率计算与平滑瞬时心率 60 / IBI (单位BPM)。直接使用瞬时心率会因个别误检而跳动剧烈。需要平滑处理常用移动平均滤波器或中值滤波器。// 简化的峰值检测伪代码 float threshold mean stdDev * scaleFactor; // 自适应阈值 for (int i 1; i dataLength - 1; i) { if (filteredData[i] threshold filteredData[i] filteredData[i-1] filteredData[i] filteredData[i1]) { // 找到波峰索引 i long currentPeakTime millis(); if (lastPeakTime 0) { int ibi currentPeakTime - lastPeakTime; float instantBPM 60000.0 / ibi; // 计算瞬时BPM smoothedBPM alpha * instantBPM (1 - alpha) * smoothedBPM; // 一阶低通滤波平滑 } lastPeakTime currentPeakTime; } // 更新动态均值和标准差... }这是一个高度简化的示例。实际工程中还需要处理信号质量指数SQI在信号质量差时暂停报告并可能引入更复杂的算法如自相关分析或Pan-Tompkins算法。4.3 固件升级OTA与数据存储一个成熟的产品必须支持无线升级和掉电数据保存。OTA空中升级ESP32 Arduino Core内置了基本的OTA库。你需要在代码中初始化OTA并设置一个用于接收升级包的端口如ArduinoOTA.setPort(3232)。在手机App或电脑端将编译好的新固件.bin文件通过Wi-Fi或BLE发送到ESP32的这个端口。注意OTA会占用额外的Flash空间需要合理规划分区表Partition Table。在PlatformIO的platformio.ini中可以配置分区方案例如board_build.partitions default_ota.csv。数据存储步数、睡眠数据等需要掉电保存。可以使用Preferences库Arduino Core for ESP32提供的轻量级键值对存储库使用简单适合存储配置参数和小量数据。SPIFFS或LittleFS文件系统适合存储更大量的数据或文件如多款表盘主题的图片。需要先将数据写入文件再进行保存。5. 调试、优化与量产化思考将原型变成稳定可用的产品还有很长的路要走。5.1 硬件调试与常见问题排查电源问题这是最头疼的。现象可能是ESP32不断重启、传感器读数不准。排查用万用表测量3.3V电源轨的电压在ESP32射频发射Wi-Fi/BLE的瞬间观察电压是否被拉低跌落超过0.2V。如果是说明LDO输出能力不足或电源路径阻抗太大。解决在ESP32的电源引脚附近增加一个大容量如100μF的钽电容或电解电容并并联多个小容量0.1μF陶瓷电容以提供瞬时大电流。确保电池连接线足够粗且短。I2C通信失败多个I2C设备传感器、屏幕地址冲突或不响应。排查使用逻辑分析仪或示波器抓取SDA/SCL波形看起始信号、地址应答是否正常。也可以写一个简单的I2C扫描程序检查所有设备地址是否都能被发现。解决确保每个I2C设备地址唯一有些传感器可通过引脚配置改变地址。为I2C总线加上拉电阻通常4.7kΩ如果总线较长或设备多适当减小上拉电阻值如2.2kΩ以增强驱动能力。屏幕显示异常花屏、闪烁、不显示。排查检查SPI/I2C接线是否正确时钟频率是否在屏幕驱动IC支持范围内过高会导致乱码。用示波器看数据线是否有干扰。解决在屏幕的电源引脚并联一个10μF电容。如果使用SPI尝试降低时钟频率如从40MHz降到20MHz。确保初始化序列的延时符合数据手册要求。5.2 软件性能与功耗优化优化循环与延时彻底消除代码中的delay()长延时全部改为基于millis()的非阻塞定时。这能极大提高系统响应性和多任务协调能力。降低射频功耗Wi-Fi不用时调用WiFi.mode(WIFI_OFF)彻底关闭。BLE调整广播间隔Advertising Interval。连接后可以与手机协商更长的连接间隔Connection Interval和从机延迟Slave Latency让ESP32在多数时间处于睡眠状态。使用BLEDevice::setPower()降低发射功率如果距离很近。测量与验证功耗使用高精度的万用表可测μA级电流串联到电池供电回路中分别测量系统在不同模式全速运行、屏幕熄灭、深度睡眠下的电流。目标是深度睡眠电流 50μA待机仅BLE保持连接电流 500μA全速运行电流 80mA。如果深度睡眠电流过高逐一排查外围电路是否有漏电如LED、传感器未彻底关断。5.3 从原型到产品的思考如果你想让这个手环更像一个产品而不仅仅是一个实验品需要考虑以下几点结构设计使用3D建模软件如Fusion 360设计外壳和腕带考虑PCB的固定、按钮的手感、充电接口的密封性。可以尝试3D打印原型最终考虑开模。防水防尘电路板需要做三防漆Conformal Coating喷涂以抵御汗液和水汽。外壳需要设计密封圈O-ring和超声波焊接等工艺。认证与合规如果计划销售需要考虑无线电型号核准、电磁兼容EMC测试等这是一笔不小的投入。量产固件需要开发一个产测工具用于在工厂批量烧录固件、测试每个传感器和功能是否正常。这通常是一个运行在PC上的Python脚本通过串口或USB与手环通信发送测试指令并验证返回值。这个基于ESP32的智能手环项目就像一场漫长的徒步旅行。从点亮第一个LED到心率波形稳定地出现在屏幕上再到手机App收到第一条蓝牙通知每一步都充满挑战也充满成就感。它逼着你去学习电路原理、信号处理、低功耗设计和无线通信协议。我最深的体会是硬件项目的调试80%的时间都在和电源与信号完整性作斗争。务必养成“先测量后思考”的习惯示波器和逻辑分析仪是你最好的朋友。另外不要试图在第一版硬件上就做到完美预留测试点TP甚至预留一些冗余的GPIO和电源跳线会给调试带来巨大的便利。最后开源社区的力量是无穷的遇到难题时去GitHub上搜索相关库的Issue或者去ESP32官方论坛看看很可能已经有人遇到了同样的问题并给出了解决方案。祝你制作顺利早日戴上自己亲手打造的智能手环。本文还有配套的精品资源点击获取