第三章 系统架构概览:硬件系统框图、核心模块划分

好,咱们进入正题。这一章我带你从高空俯瞰整个血压计的硬件系统。说白了,就是先画一张「地图」,搞清楚每个模块在哪儿、干什么、怎么连。

我刚开始做这个项目时,也犯过「先焊板子再想架构」的毛病。结果呢?电源纹波干扰传感器,气路密封不严导致测量偏差,折腾了两周才改回来。所以啊,架构设计这一步,千万别省。

3.1 硬件系统框图

先给你看一个我常用的系统框图。它不算复杂,但每个模块都经过实际项目验证。

┌─────────────────────────────────────────────────────────┐
│                    血压计硬件系统                          │
│                                                         │
│  ┌──────────┐    ┌──────────┐    ┌──────────────────┐  │
│  │  气路模块  │───▶│  传感器   │───▶│     MCU 主控     │  │
│  │ (气泵+阀)  │    │ (压力+脉搏)│    │ (STM32L0系列)    │  │
│  └──────────┘    └──────────┘    └───────┬──────────┘  │
│                                          │              │
│  ┌──────────┐    ┌──────────┐           │              │
│  │  电源模块  │───▶│  显示模块  │◀──────────┘              │
│  │ (电池+LDO) │    │ (段码LCD) │                          │
│  └──────────┘    └──────────┘                          │
│                                                         │
│  ┌──────────┐    ┌──────────┐                          │
│  │  按键模块  │───▶│  存储模块  │                          │
│  │ (3个按键)  │    │ (EEPROM)  │                          │
│  └──────────┘    └──────────┘                          │
└─────────────────────────────────────────────────────────┘

这个框图里,箭头代表数据流和控制流。你看,传感器采集到的模拟信号,经过MCU内部的ADC转换成数字量,然后算法算出收缩压和舒张压,最后送到显示模块。

核心设计原则:每个模块之间用「使能引脚」隔开。不工作时,MCU直接关掉传感器和气泵的电源。这是低功耗的关键。

3.2 核心模块划分

我把整个系统拆成5个核心模块。每个模块都有它的脾气,咱们一个一个说。

3.2.1 传感器模块

传感器是整个系统的「眼睛」。我一般选两种传感器:

  • 压力传感器:测量袖带内的气压,范围0~300mmHg。我常用的是MPS20N0040D,精度0.5%FS,价格适中。
  • 脉搏传感器:其实很多压力传感器内部集成了脉搏检测功能。比如XGZP6847,它同时输出压力和脉搏信号,省一个芯片。

这里有个坑:传感器输出的是差分信号,MCU的ADC通常是单端输入。所以中间要加一级运放。我习惯用AD8605,它功耗低(每个通道才1mA),而且轨到轨输出,很适合电池供电。

我的经验:传感器和MCU之间加一个RC低通滤波器,截止频率设在100Hz左右。可以滤掉气泵的机械振动噪声。我第一版没加,结果波形上全是毛刺,算法根本没法跑。

3.2.2 MCU主控模块

MCU是大脑。选型时我主要看三点:功耗、ADC性能、休眠模式。

我个人偏爱STM32L0系列。为什么?

  • 休眠电流低至0.4μA,比很多专用MCU还省电
  • 内置12位ADC,采样率足够(1Msps)
  • 有硬件RTC,可以定时唤醒做自检

你看这个代码片段,是MCU进入休眠前的配置:

// 进入Stop模式前的准备
HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);  // 关闭不需要的唤醒源
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 醒来后,先稳定时钟,再开传感器
SystemClock_Config();  // 重新配置时钟
HAL_ADC_Start(&hadc);  // 启动ADC采集

嗯,这里要注意:从休眠醒来后,时钟需要重新稳定。我遇到过醒来后ADC采样值飘了10%的情况,就是因为时钟没稳定就开采集。后来加了50ms的延时,问题解决。

3.2.3 电源模块

电源是命脉。血压计用两节AAA电池(3V),但传感器和运放需要3.3V。所以需要升压。

我推荐用TPS61099,它效率高达95%,而且静态电流只有1μA。升压到3.3V后,再用一个LDO给MCU供电,纹波控制在10mV以内。

供电轨电压最大电流用途
V_BAT2.0~3.2V200mA气泵电机(直接供电)
V_3V33.3V50mAMCU、传感器、运放
V_LCD3.0V5mA段码LCD显示

警告:气泵启动瞬间电流可达150mA,会导致电池电压瞬间跌落。我建议在气泵供电线上并联一个470μF的钽电容。否则MCU可能会复位,测量到一半突然重启,你说气不气人?

3.2.4 气路模块

气路是机械部分,但电气设计也得配合。核心部件就三个:气泵、泄气阀、袖带。

  • 气泵:我用的是微型隔膜泵,工作电压3V,最大气压300mmHg。注意选型时看「流量」参数,一般200mL/min就够了。
  • 泄气阀:电磁阀,常闭型。测量结束后打开,快速放气。我吃过亏:第一次选的阀响应时间50ms,结果放气太慢,患者不舒服。后来换成10ms的。
  • 袖带:标准成人袖带,气囊尺寸22~32cm。袖带和传感器之间用硅胶管连接,长度不超过50cm,否则压力信号会衰减。

气路控制逻辑其实很简单:

// 气路控制状态机
typedef enum {
    IDLE,       // 待机
    INFLATE,    // 充气
    MEASURE,    // 测量(缓慢放气)
    DEFLATE,    // 快速放气
    DONE        // 完成
} PumpState;

void Pump_Control(PumpState state) {
    switch(state) {
        case INFLATE:
            HAL_GPIO_WritePin(PUMP_GPIO, GPIO_PIN_SET);   // 开气泵
            HAL_GPIO_WritePin(VALVE_GPIO, GPIO_PIN_RESET); // 关泄气阀
            break;
        case MEASURE:
            HAL_GPIO_WritePin(PUMP_GPIO, GPIO_PIN_RESET);  // 关气泵
            // 泄气阀用PWM控制,实现缓慢放气
            TIM1->CCR1 = 50;  // 占空比20%,放气速度约3mmHg/s
            break;
        case DEFLATE:
            HAL_GPIO_WritePin(VALVE_GPIO, GPIO_PIN_SET);   // 全开放气
            break;
        default:
            break;
    }
}

你想想看,测量阶段为什么要用PWM控制泄气阀?因为放气速度直接影响测量精度。放太快,脉搏信号采不到;放太慢,患者手臂会麻。我一般控制在2~5mmHg/s。

3.2.5 显示模块

显示我用段码LCD,不是TFT彩屏。为什么?省电啊!段码LCD功耗只有几十μA,TFT动不动就几十mA。

我常用的型号是HT1621驱动的段码屏,3V供电,显示3位数字(收缩压、舒张压、心率)和几个图标(电池、错误、单位)。

驱动代码很简单:

// 显示收缩压 120
void LCD_Display_SYS(uint16_t value) {
    uint8_t digits[3];
    digits[0] = value / 100;      // 百位
    digits[1] = (value % 100) / 10; // 十位
    digits[2] = value % 10;       // 个位
    HT1621_Write_Digit(0, digits[0]);  // 写入段码
    HT1621_Write_Digit(1, digits[1]);
    HT1621_Write_Digit(2, digits[2]);
    HT1621_Update();  // 刷新显示
}

这里有个小技巧:段码LCD刷新频率不用太高,30Hz就够了。我见过有人用60Hz刷新,白白多耗一倍的电流。其实人眼对静态数字的闪烁不敏感,30Hz完全够用。

3.3 模块间的交互流程

最后,我画一个典型的测量流程,帮你把模块串起来:

  1. 用户按下「开始」键,MCU从休眠中唤醒
  2. MCU打开传感器电源,等待100ms稳定
  3. MCU打开气泵,开始充气,同时ADC实时监测压力值
  4. 当压力达到180mmHg(或比上次收缩压高30mmHg),关闭气泵
  5. 打开泄气阀(PWM控制),开始缓慢放气,同时采集脉搏波
  6. 算法实时计算收缩压和舒张压
  7. 测量完成,快速放气,显示结果
  8. MCU保存数据到EEPROM,然后进入休眠

你看,整个流程里,每个模块各司其职,配合得严丝合缝。这就是架构设计的意义——让每个模块只做自己的事,互不干扰。

总结一下:系统架构不是画几张图就完事了。它决定了你的产品能不能稳定工作、功耗能不能做低、后期好不好改。我建议你动手之前,先在纸上把每个模块的接口、时序、功耗都列清楚。磨刀不误砍柴工,这话一点不假。

下一章,咱们深入传感器模块,聊聊压力传感器和脉搏传感器的选型细节。到时候我会分享一个我踩过的坑——传感器输出信号漂移的问题,折腾了我整整一周才找到原因。