2026 M-Design设计竞赛 - 基于 XIAO nRF52840 Sense的智能健康穿戴手表
该项目使用了XIAO nRF52840 Sense,实现了智能健康穿戴手表的设计,它的主要功能为:一款集心率血氧监测、计步追踪、姿态识别与蓝牙无线传输于一体的可穿戴健康管理设备。
标签
2026 M-Design设计竞赛
XIAO nRF52840 Sense
智能健康穿戴手表
lyh114
更新2026-06-09
25

一、项目介绍和创意介绍

  我参加的是方向二:可穿戴设备生命体征实时采集方向。本项目名为"基于 XIAO nRF52840 Sense的智能健康穿戴手表",是一款集心率血氧监测、计步追踪、姿态识别与蓝牙无线传输于一体的可穿戴健康管理设备。

本项目的核心设计理念是"低功耗、高交互、专业化":通过有限状态机(FSM)管理三个页面(主页、心率血氧页、息屏页),结合LSM6DS3六轴传感器的姿态识别能力,实现了抬腕亮屏、放平息屏、久坐提醒等自然交互体验;同时利用MAX30102光学传感器的反射式血氧检测原理,配合滑动平均滤波算法和经验校准策略,让一枚小小的开发板具备了心率血氧仪的测量能力。此外,通过 BLE 蓝牙协议栈,手表可以将心率、血氧、步数和当前时间等数据与手机App 进行双向通信,真正实现"测量传输记录"的完整数据闭环。


二、使用的硬件介绍

  1. Seeed Studio XIAO nRF52840 Sense(来自贸泽电子平台):搭载 Nordic nRF52840 芯片,ARM Cortex-M4 内核,内建 BLE 5.0蓝牙协议栈。板载 LSM6DS3 六轴IMU传感器和PDM数字麦克风。尺寸仅 21×17.5mm,极为适合可穿戴场景。

  2. MAX30102/MAX30105 心率血氧传感器模块:集成红外LED880nm)和红光LED660nm),利用光电容积描记法(PPG)原理,通过检测皮肤下血管随心跳的透光率变化来计算心率与血氧饱和度。

  3. ST7789 240×135 TFT LCD 屏幕:1.14英寸彩色IPS显示屏,SPI通信接口,色彩细腻,作为手表的交互界面。

  4. 无源蜂鸣器:用于按键反馈、久坐报警等声音提示。

  5. 轻触按键:连接至 XIAO D6 引脚,配合内部下拉电阻,用于页面切换操作。

 

三、方案框图和项目设计思路

  系统架构框图:

image.png

  设计思路:

  项目采用"有限状态机 (FSM) + 硬件中断 + 定时轮询"的混合架构。系统被划分为三个页面状态(主页 PAGE_HOME、心率页PAGE_HR、息屏页 PAGE_SLEEP),每个页面拥有独立的 run 函数。按键切换通过硬件中断实现,可以在任何时立即响应,解决了传统轮询式按键检测在阻塞算法中失灵的问题。

  IMU 数据采集在主循环的每个周期都会执行,保证了姿态识别的实时性。心率血氧算法则只在心率页被激活时运行为了休眠省电,采用滑动窗口更新来提高心率准确性。BLE蓝牙广播和通知在主循环中以非阻塞方式执行,不影响传感器读取和 UI 刷新。

 

四、原理图和PCB介绍

为了方便演示,我画了一个简单的PCB。按键和蜂鸣器各使用一个gpio控制,OLED连接spi外设控制,血氧传感器使用一路iic通讯。

原理图如下:

PCB连接图:


五、软件流程图和关键代码介绍

  软件流程图:

image.png

 

关键代码介绍:

(1)    buttonISR()

中断服务函数在按键上升沿时被硬件瞬间调用,内部只做最少量的工作(修改页面状态、设置标志位),200ms的去抖动逻辑确保不会因按键抖动而误触发。

 void buttonISR() {

  unsigned long interruptTime = millis();

  if (interruptTime - lastInterruptTime > 200) {

    lastPage = currentPage;

    currentPage++;

    if (currentPage > 2) currentPage = 0;


    needRedraw = true;

    buttonPressed = true;


    lastManualActionTime = interruptTime;

    lastInterruptTime = interruptTime;

  }

}

(2)    IMU 姿态识别算法:

通过反复测试,确定当屏幕竖起面向面部时,地球重力加速度使Y轴接近 -1.0G,因此使用 y < -0.6 && abs(x) < 0.5 && z> -0.2 && z < 0.6 的组合条件来精准识别抬腕动作。放平息屏则通过 Z 轴接近 1.0G(屏幕平放)来判断。

  float x = imu.readFloatAccelX();

  float y = imu.readFloatAccelY();

  float z = imu.readFloatAccelZ();

  if (currentPage == PAGE_SLEEP) {

    if (y < -0.6 && abs(x) < 0.5 && z > -0.2 && z < 0.6) {

      lastPage = currentPage;

      currentPage = PAGE_HOME;

      needRedraw = true;

    }

  }

  if (currentPage == PAGE_HOME) {

    if (millis() - lastManualActionTime > 2000) {

      if (z > 0.8 && abs(x) < 0.3 && abs(y) < 0.3) {

        lastPage = currentPage;

        currentPage = PAGE_SLEEP;

        needRedraw = true;

      }

    }

  }

 

(3)    心率血氧滑动窗口处理

使用100点循环缓冲区,首次进入时预填充全部数据,后续每次仅增量采样 25个新点,将旧数据前移。maxim_heart_rate_and_oxygen_saturation() 算法负责从红外/红光两路 PPG信号中提取心率和血氧值。

  for (byte i = 25; i < 100; i++) {
    redBuffer[i - 25] = redBuffer[i];
    irBuffer[i - 25] = irBuffer[i];
  }
  for (byte i = 75; i < 100; i++) {
    while (particleSensor.available() == false) {
      particleSensor.check();
      if(currentPage != PAGE_HR) return;
    }
    redBuffer[i] = particleSensor.getRed();
    irBuffer[i] = particleSensor.getIR();
    particleSensor.nextSample();
  }
 
  if (currentPage != PAGE_HR) return;


  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);


4UI 局部刷新机制: 为避免全屏重绘导致的闪屏问题,采用"静态框架一次绘制 + 动态数据局部覆盖"的策略。时间、步数、心率 、血氧数值各自维护上一次显示值的缓存,仅在数据变化时才用背景色矩形覆盖旧值后写入新值:

void updateStatus(const char* msg) {

  tft.setTextSize(1);

  tft.setTextColor(0x07E0, COLOR_CARD);

  char buf[20];

  sprintf(buf, "%-15s", msg);

  tft.setCursor(140, 6);

  tft.print(buf);

}

 

void updateData(int hr, int ox) {

  tft.setTextSize(4);

  char buf[10];

  tft.setTextColor(COLOR_HR, COLOR_CARD);

  tft.setCursor(20, 80);

  if(hr == 0) tft.print("--  ");

  else { sprintf(buf, "%-3d ", hr); tft.print(buf); }

 
  tft.setTextColor(COLOR_SPO2, COLOR_CARD);

  tft.setCursor(140, 80);

  if(ox == 0) tft.print("--  ");

  else { sprintf(buf, "%-3d ", ox); tft.print(buf); }

}


六、功能展示图及说明

页面

功能说明

交互方式

主页

显示当前时间(蓝牙同步)、实时步数

抬腕自动亮屏;放平自动息屏

心率血氧

实时显示心率和血氧饱和度数值,顶部状态栏显示传感器工作状

手指放置于传感器上,自动识别无手指/调整手指/测量中三种状态

息屏页

屏幕背光关闭,进入省电模式

抬腕自动唤醒,久坐自动弹窗报警

久坐提醒

红色弹窗显示"Time to Move!" + 蜂鸣器持续报警

步数不增加超阈值即触发

BLE 连接

手机 App可扫描到"M-Design Watch"设备,接收实时心率/血氧/步数数据

手机端发送时间同步指令

 未上电硬件图:

image.png

主页展示:

image.png

心率血氧测量:

image.png

放平自动息屏:

image.png

久坐提醒:

image.png

可通过BLE 连接手机查看数据、修改时间:

image.png

七、设计中遇到的难题和解决方法

  1.最初使用轮询式 checkButton() 函数,但在 100 次循环预填充传感器数据时,CPU被完全占用,按键检测被"饿死"。后来改用硬件中,按键信号可以在任何时刻强行打断CPU正在执行的任务,将页面切换逻辑放在 ISR 中直接完成才彻底解决问题。

  2.MAX30102 在某些情况下会因重搏波(dicrotic notch)将一次心跳误判为两次,导致读数为实际值的两倍。我通过多次测试,得出经验:当原始值超过 95 BPM 时,乘以 0.7 进行修正。同时引入 5点滑动平均滤波,消除短暂的信号干扰。

 

八、对本次竞赛的心得体会

  参加2026 M-Design设计竞赛,我第一次体验到了Seeed Studio XIAO nRF52840 Sense这款开发板,对比我之前使用的开发板,它小到极致,但是麻雀虽小五脏俱全,其他开发板该有的功能spiiicuart等功能他都具有,让我惊讶的是他板载了一个麦克风和imu,加上蓝牙功能,他的性能十分强大,让我收获远超预期。同时我也第一次接触使用Arduino进行开发,从最初"点亮屏幕、读取传感器数据"的基础目标,到最终实现抬腕亮屏、放平息屏、久坐提醒、BLE 蓝牙同步等交互功能,让我收获许多。



软硬件
电路图
附件下载
demo.ino
2026 M-Design (1).zip
团队介绍
无团队,电子信息工程学生一枚
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号