基于STM32指甲式脉搏血氧仪七大核心功能解析与实现

  作者:嵌入式芯视野 时间:2025-08-04来源:今日头条

基于STM32的SpO2-EVM

血氧仪开发套件 血氧仪开发套件

1. 血氧饱和度测量(40%~100%,精度 ±2%@70%~100%)

技术指标解析

STM32 方案实现

2. 脉率测量(30~250bpm,精度 ±1bpm)

技术指标解析

STM32 方案实现

3. 弱信号处理(弱灌注强度≤0.3%)

技术指标解析

STM32 方案实现

4. 彩色 OLED 同屏显示

功能架构

5. 无信号自动关机

功耗管理逻辑


6. 历史数据存储与管理

存储架构

7. 屏幕旋转功能

实现方案

/* 头文件与宏定义 */#include "stm32f10x_hal.h"#include "math.h"#define SAMPLE_RATE 1000        // 采样率1kHz#define BUFFER_DEPTH 256        // 数据缓冲区深度#define RED_LED_PORT GPIOA      // 红光LED端口#define RED_LED_PIN GPIO_PIN_0  #define IR_LED_PORT GPIOA       // 近红外LED端口#define IR_LED_PIN GPIO_PIN_1#define ADC_CHANNEL_RED 0       // 红光ADC通道#define ADC_CHANNEL_IR 1        // 近红外ADC通道/* 全局变量 */ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;uint16_t adcBuffer[2][BUFFER_DEPTH];  // ADC数据缓冲区 {红光, 近红外}float redSignal[BUFFER_DEPTH];        // 红光信号float irSignal[BUFFER_DEPTH];         // 近红外信号uint8_t spo2Value = 97;               // 血氧饱和度uint16_t pulseRate = 72;              // 脉率(bpm)uint8_t perfusionIndex = 0;           // 灌注指数/* 函数声明 */void SystemInit(void);void MX_GPIO_Init(void);void MX_ADC_Init(void);void MX_DMA_Init(void);void SPO2_Calculate(void);void PulseRate_Detect(void);void OLED_Display(void);void PowerManagement_Check(void);/* 主函数 */int main(void){  /* 系统初始化 */
 HAL_Init();
 SystemInit();  
 /* 外设初始化 */
 MX_GPIO_Init();
 MX_ADC_Init();
 MX_DMA_Init();  
 /* 启动ADC_DMA传输 */
 HAL_ADC_Start_DMA(&hadc, (uint32_t*)adcBuffer, 2 * BUFFER_DEPTH);  
 /* 主循环 */
 while (1)
 {    /* 血氧与脉率计算 */
   SPO2_Calculate();
   PulseRate_Detect();    
   /* 显示数据 */
   OLED_Display();    
   /* 低功耗检查 */
   PowerManagement_Check();    
   /* 延时处理 */
   HAL_Delay(10);
 }
}/* ADC初始化 */void MX_ADC_Init(void){
 ADC_ChannelConfTypeDef sConfig = {0};

 hadc.Instance = ADC1;
 hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
 hadc.Init.Resolution = ADC_RESOLUTION_12B;
 hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
 hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
 hadc.Init.ContinuousConvMode = ENABLE;
 hadc.Init.NbrOfConversion = 2;  // 红光+近红外双通道
 HAL_ADC_Init(&hadc);  /* 配置红光通道 */
 sConfig.Channel = ADC_CHANNEL_0;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);  
 /* 配置近红外通道 */
 sConfig.Channel = ADC_CHANNEL_1;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);
}/* 血氧饱和度计算 */void SPO2_Calculate(void){  static float redAC[BUFFER_DEPTH], redDC[BUFFER_DEPTH];  static float irAC[BUFFER_DEPTH], irDC[BUFFER_DEPTH];  float ratio, spo2;  
 /* 1. 转换ADC值为电压信号(假设参考电压3.3V) */
 for (uint16_t i = 0; i < BUFFER_DEPTH; i++) {
   redSignal[i] = (float)adcBuffer[0][i] * 3.3f / 4096.0f;
   irSignal[i] = (float)adcBuffer[1][i] * 3.3f / 4096.0f;
 }  
 /* 2. 分离AC和DC分量(简化版,实际需滤波) */
 for (uint16_t i = 0; i < BUFFER_DEPTH; i++) {
   redDC[i] = redSignal[i] * 0.95f + redDC[i] * 0.05f;  // 一阶低通滤波求DC
   redAC[i] = redSignal[i] - redDC[i];                  // AC分量
   
   irDC[i] = irSignal[i] * 0.95f + irDC[i] * 0.05f;
   irAC[i] = irSignal[i] - irDC[i];
 }  
 /* 3. 计算AC/DC比值 */
 float sumRedAC = 0, sumRedDC = 0;  float sumIrAC = 0, sumIrDC = 0;  for (uint16_t i = 0; i < BUFFER_DEPTH; i++) {
   sumRedAC += fabs(redAC[i]);
   sumRedDC += fabs(redDC[i]);
   sumIrAC += fabs(irAC[i]);
   sumIrDC += fabs(irDC[i]);
 }  
 float ratioRed = sumRedAC / sumRedDC;  float ratioIr = sumIrAC / sumIrDC;  
 /* 4. 计算灌注指数(PI) */
 perfusionIndex = (uint8_t)((ratioRed + ratioIr) * 10);  
 /* 5. 根据Beer-Lambert定律计算SpO2(简化公式) */
 ratio = ratioRed / ratioIr;  if (ratio > 1.0f) ratio = 1.0f / ratio;  // 范围限定
 spo2 = 94.0f - 25.0f * ratio;           // 经验公式,实际需校准
 
 /* 6. 结果校准与限幅 */
 if (spo2 > 100) spo2 = 100;  if (spo2 < 40) spo2 = 40;
 spo2Value = (uint8_t)spo2;
}/* 脉率检测 */void PulseRate_Detect(void){  static uint32_t lastPeakTime = 0;  static float peakBuffer[8] = {0};  static uint8_t peakIndex = 0;  uint32_t currentTime = HAL_GetTick();  float maxAmplitude = 0;  uint16_t peakPosition = 0;  
 /* 1. 寻找脉搏波峰值(简化版,实际需带通滤波) */
 for (uint16_t i = 0; i < BUFFER_DEPTH; i++) {    if (redSignal[i] > maxAmplitude) {
     maxAmplitude = redSignal[i];
     peakPosition = i;
   }
 }  
 /* 2. 计算脉搏周期(需排除异常峰值) */
 if (maxAmplitude > 0.1f && currentTime - lastPeakTime > 300 && currentTime - lastPeakTime < 2000) {    uint32_t periodMs = currentTime - lastPeakTime;
   pulseRate = (uint16_t)(60000.0f / periodMs);  // ms转bpm
   lastPeakTime = currentTime;    
   /* 3. 滑动平均滤波,平滑脉率显示 */
   peakBuffer[peakIndex] = pulseRate;
   peakIndex = (peakIndex + 1) % 8;    
   float avgPulse = 0;    for (uint8_t i = 0; i < 8; i++) {
     avgPulse += peakBuffer[i];
   }
   pulseRate = (uint16_t)(avgPulse / 8);
 }
}/* OLED显示函数 */void OLED_Display(void){  /* 实际项目中需调用OLED驱动库 */
 char displayBuf[32];  
 /* 显示血氧饱和度 */
 sprintf(displayBuf, "SpO2: %d%%", spo2Value);
 OLED_DrawString(0, 0, displayBuf);  
 /* 显示脉率 */
 sprintf(displayBuf, "PR: %dbpm", pulseRate);
 OLED_DrawString(0, 20, displayBuf);  
 /* 显示灌注指数 */
 sprintf(displayBuf, "PI: %d", perfusionIndex);
 OLED_DrawString(0, 40, displayBuf);  
 /* 绘制简化脉搏波形 */
 for (uint16_t i = 0; i < 128; i++) {    uint16_t point = i * BUFFER_DEPTH / 128;    uint8_t y = (uint8_t)(redSignal[point] * 30 + 50);
   OLED_DrawPoint(i, y);
 }
}/* 低功耗管理 */void PowerManagement_Check(void){  static uint32_t noSignalTime = 0;  static uint8_t signalStatus = 0;  
 /* 1. 检测信号有效性(通过灌注指数判断) */
 if (perfusionIndex > 1) {
   signalStatus = 1;
   noSignalTime = HAL_GetTick();
 } else {    if (signalStatus) {
     signalStatus = 0;
     noSignalTime = HAL_GetTick();
   }
 }  
 /* 2. 无信号超过20秒则关机 */
 if (!signalStatus && HAL_GetTick() - noSignalTime > 20000) {    /* 关闭外设,进入待机模式 */
   HAL_ADC_Stop_DMA(&hadc);
   HAL_GPIO_WritePin(RED_LED_PORT, RED_LED_PIN, GPIO_PIN_RESET);
   HAL_GPIO_WritePin(IR_LED_PORT, IR_LED_PIN, GPIO_PIN_RESET);
   OLED_PowerOff();    
   /* 进入低功耗模式 */
   HAL_PWR_EnterSTANDBYMode();
 }
}

功能协同与临床价值示意图


典型应用案例

技术对比表(STM32 方案 vs 传统方案)

功能点

STM32 方案优势

传统方案局限

弱信号处理

自适应增益 + 小波去噪,PI≤0.3% 可用

PI<1% 时测量失效

数据存储

16Mbit Flash 支持 7 天连续记录

仅保存最近 200 条记录

屏幕旋转

实时姿态检测,用户体验更友好

固定方向显示,视角受限

功耗控制

STANDBY 模式 < 10μA,续航≥15 小时

待机功耗 > 50μA,续航 < 8 小时


关键词: STM32

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章

查看电脑版