第一章:血氧仪系统架构概述

大家好,我是老张。做血氧仪开发有些年头了。今天咱们聊聊系统架构。

很多人一上来就盯着算法,或者纠结传感器选型。其实,先把整个链路理清楚,后面会省很多事。我个人习惯,拿到项目先画一张大图——从手指头到屏幕,信号是怎么走的。

1.1 完整信号链路:从指尖到屏幕

血氧仪的核心原理,说白了就是光学测量。你想想看,手指里动脉血和静脉血对红光和红外光的吸收率不一样。我们通过这个差异,算出SpO2值。

信号链路大致分四段:

  • 光电转换:LED发光穿过手指,被光电二极管接收。光信号变成微弱的电流信号。
  • 模拟前端调理:电流转电压,放大,滤波。去掉噪声,把信号拉到ADC能采样的范围。
  • 模数转换与数字处理:ADC采样,然后做数字滤波、去基线漂移、提取脉搏波。
  • 算法计算与显示:根据红光和红外光的交流分量比值,算出血氧饱和度。最后驱动OLED或LCD显示。

嗯,这里要注意:每一级都会引入误差。我在项目中遇到过,模拟前端的地没处理好,导致整个波形都是毛刺,算法根本算不准。

关键点:信号链路的信噪比,决定了血氧仪的精度下限。别指望算法能弥补硬件上的缺陷。

1.2 硬件模块划分

硬件上,我习惯把血氧仪拆成这几个模块。你照着这个思路去设计,不容易漏东西。

模块 核心器件 我的经验
传感器驱动 红光LED(660nm)、红外LED(940nm)、光电二极管 LED的驱动电流要精确控制,我曾经因为电阻选错,导致光强不够,信号弱得可怜。
模拟前端(AFE) 跨阻放大器、可编程增益放大器、低通滤波器 AFE芯片的布局要远离数字电路。我吃过亏,数字噪声串进来,波形上全是毛刺。
主控MCU ARM Cortex-M0/M4,带ADC和DMA 建议选带硬件I2C和SPI的,省事。ADC采样率至少100Hz,否则脉搏波细节抓不住。
电源管理 锂电池、升压芯片、LDO 血氧仪对电源纹波敏感。我习惯在AFE供电前加一级LC滤波。
显示与交互 OLED屏、按键、蜂鸣器 OLED刷新率别太高,否则功耗扛不住。我一般控制在30Hz。

避坑指南:我曾经在AFE和MCU之间用了长排线,结果信号串扰得一塌糊涂。后来改成短走线+屏蔽罩,问题才解决。布局时,模拟地和数字地要单点连接。

1.3 软件任务分解

软件这块,我习惯按实时性要求来分任务。说白了,就是哪些事必须马上做,哪些可以等等再做。

1.3.1 高实时性任务(中断级)

  • ADC采样与DMA传输:定时器触发ADC,DMA自动把数据搬到内存。CPU几乎不花时间。
  • LED时序控制:红光和红外LED要分时点亮,不能同时亮。我一般用定时器中断来切换。
  • 按键消抖:用定时器中断做10ms消抖,别在主循环里傻等。

1.3.2 中等实时性任务(主循环或RTOS任务)

  • 数字滤波与波形提取:IIR高通滤波器去掉直流分量,提取脉搏波。这个计算量不大,但每来一个采样点都要算。
  • 心率计算:通过脉搏波峰值间隔算心率。我习惯用滑动窗口,窗口长度2秒。
  • 血氧算法:计算红光和红外光的AC/DC比值,查表或公式算出SpO2。

1.3.3 低实时性任务(后台处理)

  • 显示刷新:每秒更新30次就够了。别跟ADC抢CPU。
  • 数据存储与通信:如果需要记录历史数据,或者通过蓝牙上传,放后台慢慢做。
  • 低功耗管理:检测到手指离开,进入休眠模式。我一般用定时器唤醒,每100ms检查一次。

警告:千万别在ADC中断里做血氧算法!中断服务程序要短平快。我曾经犯过这个错,导致中断嵌套,采样数据丢失。算法放主循环或低优先级任务里跑。

1.4 一个典型的软件流程图

我画个伪代码,你感受一下整体流程:

// 伪代码:血氧仪主循环
void main() {
    init_hardware();      // 初始化时钟、GPIO、ADC、DMA
    init_algorithm();     // 初始化滤波器系数、血氧查找表
    
    while(1) {
        // 1. 检查是否有新采样数据(由DMA中断设置标志)
        if (new_sample_ready) {
            process_digital_filter();   // 高通+低通滤波
            extract_pleth_waveform();   // 提取脉搏波
            calculate_hr();             // 计算心率
            calculate_spo2();           // 计算血氧
            new_sample_ready = 0;
        }
        
        // 2. 更新显示(每33ms一次)
        if (display_tick) {
            update_oled_screen();
            display_tick = 0;
        }
        
        // 3. 处理按键和低功耗
        handle_key_press();
        check_power_management();
        
        // 4. 进入休眠(等待中断唤醒)
        enter_sleep_mode();
    }
}

你看,这个结构很清晰。ADC采样靠DMA,不占CPU。主循环只做滤波和计算。显示和按键都是定时轮询。功耗也能控制住。

1.5 总结一下

系统架构这东西,说白了就是分而治之。硬件上把模拟和数字分开,软件上把实时和非实时分开。你照着这个思路去搭框架,后面调试会轻松很多。

我记得第一次做血氧仪时,没注意模拟前端的地回路,结果波形上全是50Hz工频干扰。后来花了两天时间重新布线,才把问题搞定。嗯,这些坑,后面章节我会一个个细讲。

下一章,咱们聊聊模拟前端的调试技巧。那个环节最容易出问题,也最考验耐心。