基于STM32指甲式脈搏血氧儀七大核心功能解析與實現(xiàn)
基于STM32的SpO2-EVM

血氧儀開發(fā)套件 血氧儀開發(fā)套件
1. 血氧飽和度測量(40%~100%,精度 ±2%@70%~100%)
技術(shù)指標(biāo)解析
測量范圍:覆蓋臨床緊急低氧(40%)到正常(100%)場景,滿足 ICU 重癥監(jiān)護(hù)與家庭健康監(jiān)測需求;
精度分級:70%~100% 時 ±2%(臨床診斷級),40%~70% 時 ±4%(低氧預(yù)警級),符合 YY/T 0784-2010 行業(yè)標(biāo)準(zhǔn)。
STM32 方案實現(xiàn)
硬件基礎(chǔ):12 位 ADC(ADS1258)采集光信號,分辨率達(dá) 0.08mV(3.3V 參考電壓);雙波長 LED(660nm 紅光 / 940nm 近紅外)分時驅(qū)動,減少環(huán)境光干擾。
軟件算法:采用 Beer-Lambert 定律結(jié)合校準(zhǔn)系數(shù)查表法,如前文中SPO2_Calculate函數(shù)通過 AC/DC 比值計算 SpO2;動態(tài)溫度補(bǔ)償:內(nèi)置溫度傳感器修正光吸收系數(shù)隨溫度的漂移。
2. 脈率測量(30~250bpm,精度 ±1bpm)
技術(shù)指標(biāo)解析
范圍覆蓋:從新生兒靜息心率(30bpm)到運動極限心率(250bpm);
精度控制:±1bpm 滿足臨床心率變異性(HRV)分析需求。
STM32 方案實現(xiàn)
信號處理:帶通濾波提取脈搏波頻率(0.5~5Hz),抑制運動偽影;峰值檢測算法(如前文中PulseRate_Detect函數(shù))結(jié)合滑動平均濾波(8 點緩沖),消除異常脈沖。
抗干擾設(shè)計:采用自適應(yīng)閾值跟蹤脈搏波幅度變化,避免弱信號漏檢;周期校驗機(jī)制:若相鄰脈率差 > 20%,則丟棄該次測量結(jié)果。
3. 弱信號處理(弱灌注強(qiáng)度≤0.3%)
技術(shù)指標(biāo)解析
灌注指數(shù)(PI):≤0.3% 表示極弱血流(如失血性休克、低溫癥),傳統(tǒng)設(shè)備易測量失敗。
STM32 方案實現(xiàn)
硬件增強(qiáng):高增益儀表運放(ISL28470)放大微弱光電流信號,增益可達(dá) 1000 倍;低噪聲電源(ISL9001)抑制紋波對前端信號的干擾。
軟件優(yōu)化:自適應(yīng)增益控制:當(dāng) PI<1% 時,自動提高 LED 驅(qū)動電流(如前文中NLAS4053模擬開關(guān)調(diào)節(jié));小波變換去噪:分解信號至不同頻段,保留脈搏波特征分量。
4. 彩色 OLED 同屏顯示
功能架構(gòu)
顯示內(nèi)容:數(shù)值區(qū):SpO2(大字體突出)、脈率、PI 值;波形區(qū):實時脈搏波(128 點趨勢圖);狀態(tài)區(qū):電池電量、信號質(zhì)量圖標(biāo)。
STM32 驅(qū)動方案:SPI 接口控制 OLED 驅(qū)動 IC(如 SSD1351),刷新率≥25fps;動態(tài)刷新率調(diào)節(jié):弱信號時提高刷新率至 50fps,增強(qiáng)波形穩(wěn)定性。
5. 無信號自動關(guān)機(jī)
功耗管理邏輯
檢測機(jī)制:連續(xù) 20 秒檢測到 PI<0.2% 且 SpO2 值固定不變(如 40%),判定為無有效信號;硬件 watchdog(X5043)監(jiān)控 MCU 運行狀態(tài),防止程序卡死導(dǎo)致功耗異常。
低功耗實現(xiàn):STM32 進(jìn)入 STANDBY 模式,功耗 < 10μA;切斷 LED、OLED 等外設(shè)電源,僅保留 RTC(ISL12022M)計時。

6. 歷史數(shù)據(jù)存儲與管理
存儲架構(gòu)
硬件配置:串行 Flash(M25P16,16Mbit)可保存≥2000 條記錄(每條含 SpO2、脈率、時間戳);I2C 接口 EEPROM(M24C64)存儲校準(zhǔn)參數(shù)與用戶配置。
軟件功能:周期性存儲:每 5 分鐘自動保存一次數(shù)據(jù),支持手動觸發(fā)保存;數(shù)據(jù)管理:支持按日期查詢、刪除指定記錄,F(xiàn)IFO 循環(huán)覆蓋舊數(shù)據(jù)。
7. 屏幕旋轉(zhuǎn)功能
實現(xiàn)方案
硬件:三軸加速度傳感器(LIS33DE)檢測設(shè)備姿態(tài),分辨率達(dá) ±2g;
程序示例:基于 STM32F103 的血氧儀數(shù)據(jù)處理
以下是核心功能的 C 語言實現(xiàn)(使用 HAL 庫):
/* 頭文件與宏定義 */#include "stm32f10x_hal.h"#include "math.h"#define SAMPLE_RATE 1000 // 采樣率1kHz#define BUFFER_DEPTH 256 // 數(shù)據(jù)緩沖區(qū)深度#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數(shù)據(jù)緩沖區(qū) {紅光, 近紅外}float redSignal[BUFFER_DEPTH]; // 紅光信號float irSignal[BUFFER_DEPTH]; // 近紅外信號uint8_t spo2Value = 97; // 血氧飽和度uint16_t pulseRate = 72; // 脈率(bpm)uint8_t perfusionIndex = 0; // 灌注指數(shù)/* 函數(shù)聲明 */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);/* 主函數(shù) */int main(void){ /* 系統(tǒng)初始化 */
HAL_Init();
SystemInit();
/* 外設(shè)初始化 */
MX_GPIO_Init();
MX_ADC_Init();
MX_DMA_Init();
/* 啟動ADC_DMA傳輸 */
HAL_ADC_Start_DMA(&hadc, (uint32_t*)adcBuffer, 2 * BUFFER_DEPTH);
/* 主循環(huán) */
while (1)
{ /* 血氧與脈率計算 */
SPO2_Calculate();
PulseRate_Detect();
/* 顯示數(shù)據(jù) */
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. 轉(zhuǎn)換ADC值為電壓信號(假設(shè)參考電壓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. 計算灌注指數(shù)(PI) */
perfusionIndex = (uint8_t)((ratioRed + ratioIr) * 10);
/* 5. 根據(jù)Beer-Lambert定律計算SpO2(簡化公式) */
ratio = ratioRed / ratioIr; if (ratio > 1.0f) ratio = 1.0f / ratio; // 范圍限定
spo2 = 94.0f - 25.0f * ratio; // 經(jīng)驗公式,實際需校準(zhǔn)
/* 6. 結(jié)果校準(zhǔn)與限幅 */
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轉(zhuǎn)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顯示函數(shù) */void OLED_Display(void){ /* 實際項目中需調(diào)用OLED驅(qū)動庫 */
char displayBuf[32];
/* 顯示血氧飽和度 */
sprintf(displayBuf, "SpO2: %d%%", spo2Value);
OLED_DrawString(0, 0, displayBuf);
/* 顯示脈率 */
sprintf(displayBuf, "PR: %dbpm", pulseRate);
OLED_DrawString(0, 20, displayBuf);
/* 顯示灌注指數(shù) */
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. 檢測信號有效性(通過灌注指數(shù)判斷) */
if (perfusionIndex > 1) {
signalStatus = 1;
noSignalTime = HAL_GetTick();
} else { if (signalStatus) {
signalStatus = 0;
noSignalTime = HAL_GetTick();
}
}
/* 2. 無信號超過20秒則關(guān)機(jī) */
if (!signalStatus && HAL_GetTick() - noSignalTime > 20000) { /* 關(guān)閉外設(shè),進(jìn)入待機(jī)模式 */
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();
/* 進(jìn)入低功耗模式 */
HAL_PWR_EnterSTANDBYMode();
}
}
應(yīng)用場景:支持手持、桌面等多場景使用,自動適配顯示方向。
功能協(xié)同與臨床價值示意圖

典型應(yīng)用案例
秦皇島康泰醫(yī)學(xué):采用 STM32F101C6T6 方案,結(jié)合 LIS33DE 與 M25P80 Flash,實現(xiàn) 24 小時連續(xù)監(jiān)測,數(shù)據(jù)可通過 USB 導(dǎo)出至醫(yī)院 HIS 系統(tǒng);
北京超思電子:在遠(yuǎn)程血氧監(jiān)護(hù)儀中加入 4G 通信模塊,當(dāng) SpO2<90% 且持續(xù) 5 分鐘時,自動向家屬手機(jī)推送報警信息,結(jié)合歷史數(shù)據(jù)存儲功能,支持醫(yī)生遠(yuǎn)程調(diào)閱趨勢圖。
技術(shù)對比表(STM32 方案 vs 傳統(tǒng)方案)
功能點 | STM32 方案優(yōu)勢 | 傳統(tǒng)方案局限 |
弱信號處理 | 自適應(yīng)增益 + 小波去噪,PI≤0.3% 可用 | PI<1% 時測量失效 |
數(shù)據(jù)存儲 | 16Mbit Flash 支持 7 天連續(xù)記錄 | 僅保存最近 200 條記錄 |
屏幕旋轉(zhuǎn) | 實時姿態(tài)檢測,用戶體驗更友好 | 固定方向顯示,視角受限 |
功耗控制 | STANDBY 模式 < 10μA,續(xù)航≥15 小時 | 待機(jī)功耗 > 50μA,續(xù)航 < 8 小時 |
評論