基于STM32的脉搏电子血压计系统设计
一、系统总体架构
1.1 系统框图
血压袖带压力 → 压力传感器 → 信号调理电路 → ADC采集
脉搏波信号 → 光电传感器 → 滤波放大电路 → ADC采集
↓
STM32F103C8T6
↓
LCD显示/按键控制/USB通信
二、硬件设计
2.1 主要硬件组件
| 模块 | 型号 | 功能 |
|---|---|---|
| MCU | STM32F103C8T6 | 主控制器 |
| 压力传感器 | MPXV5050GP | 血压压力测量 |
| 光电传感器 | SEN-11574 | 脉搏波检测 |
| 气泵 | DC 3V微型气泵 | 袖带充气 |
| 电磁阀 | 3V常闭型 | 袖带放气 |
| LCD显示 | OLED 0.96" SSD1306 | 数据显示 |
| ADC | STM32内置12位ADC | 信号采集 |
2.2 硬件连接图
STM32引脚配置:
PA0 - 压力传感器ADC输入
PA1 - 脉搏传感器ADC输入
PA2 - 气泵控制(推挽输出)
PA3 - 电磁阀控制(推挽输出)
PB6 - OLED_SCL(I2C)
PB7 - OLED_SDA(I2C)
PB8 - 开始按键(输入下拉)
PB9 - 停止按键(输入下拉)
PA9 - USB_DM(可选)
PA10 - USB_DP(可选)
三、软件设计
3.1 主程序架构
// main.c
#include "stm32f10x.h"
#include "adc.h"
#include "pump_valve.h"
#include "oled.h"
#include "algorithm.h"
#define SAMPLE_RATE 100 // 100Hz采样率
volatile uint32_t pressure_value = 0;
volatile uint32_t pulse_value = 0;
volatile uint8_t measurement_flag = 0;
int main(void)
{
System_Init();
ADC_Init();
OLED_Init();
Pump_Valve_Init();
Key_Init();
OLED_ShowString(0, 0, "BP Monitor Ready");
while(1)
{
if(Key_Scan() == KEY_START)
{
measurement_flag = 1;
BloodPressure_Measurement();
}
}
}
void BloodPressure_Measurement(void)
{
uint16_t pressure_buffer[1000];
uint16_t pulse_buffer[1000];
uint16_t index = 0;
uint32_t systolic = 0, diastolic = 0, heart_rate = 0;
// 1. 充气阶段
Pump_On();
while(pressure_value < 18000) // 180mmHg
{
pressure_buffer[index] = ADC_GetPressure();
pulse_buffer[index] = ADC_GetPulse();
index++;
Delay_ms(10);
if(index >= 1000) break;
}
Pump_Off();
// 2. 线性放气测量阶段
Valve_Open_Slow(); // 慢速放气
index = 0;
while(pressure_value > 6000) // 60mmHg
{
pressure_buffer[index] = ADC_GetPressure();
pulse_buffer[index] = ADC_GetPulse();
index++;
Delay_ms(10);
}
Valve_Close();
// 3. 算法处理
Process_BloodPressure(pressure_buffer, pulse_buffer, index,
&systolic, &diastolic, &heart_rate);
// 4. 显示结果
Display_Result(systolic, diastolic, heart_rate);
}
3.2 ADC采集模块
// adc.c
#include "stm32f10x.h"
void ADC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// 配置PA0, PA1为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 使能ADC
ADC_Cmd(ADC1, ENABLE);
// ADC校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
uint16_t ADC_GetPressure(void)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
uint16_t ADC_GetPulse(void)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
3.3 气泵与电磁阀控制
// pump_valve.c
#include "stm32f10x.h"
#include "pwm.h"
void Pump_Valve_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 气泵控制引脚PA2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 电磁阀控制引脚PA3 (PWM控制放气速度)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化PWM用于精确控制放气速度
PWM_Init(TIM2, 7200, 100); // 10kHz PWM
}
void Pump_On(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
void Pump_Off(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
void Valve_Open_Fast(void)
{
PWM_SetDuty(TIM2, 100); // 全速放气
}
void Valve_Open_Slow(void)
{
PWM_SetDuty(TIM2, 20); // 20%占空比,慢速放气
}
void Valve_Close(void)
{
PWM_SetDuty(TIM2, 0);
}
3.4 血压算法处理
// algorithm.c
#include <math.h>
#include "filter.h"
#define MAX_PRESSURE 20000 // 200mmHg
#define MIN_PRESSURE 6000 // 60mmHg
void Process_BloodPressure(uint16_t *pressure_data, uint16_t *pulse_data,
uint16_t length, uint32_t *systolic,
uint32_t *diastolic, uint32_t *heart_rate)
{
uint16_t i, max_amp = 0, max_index = 0;
float pressure_mmHg, pulse_amplitude;
float pulse_envelope[1000];
// 1. 滤波处理
Moving_Average_Filter(pulse_data, length, 5);
// 2. 提取脉搏波包络
for(i = 10; i < length - 10; i++)
{
pulse_envelope[i] = Calculate_Envelope(pulse_data, i, 10);
if(pulse_envelope[i] > max_amp)
{
max_amp = pulse_envelope[i];
max_index = i;
}
}
// 3. 寻找特征点(振荡法)
uint16_t systolic_idx = Find_Systolic_Point(pulse_envelope, max_index);
uint16_t diastolic_idx = Find_Diastolic_Point(pulse_envelope, max_index);
// 4. 转换为mmHg
*systolic = (uint32_t)(pressure_data[systolic_idx] * 200.0 / 4096.0);
*diastolic = (uint32_t)(pressure_data[diastolic_idx] * 200.0 / 4096.0);
// 5. 计算心率
*heart_rate = Calculate_HeartRate(pulse_data, length);
}
uint32_t Calculate_HeartRate(uint16_t *pulse_data, uint16_t length)
{
uint16_t peak_count = 0;
uint16_t last_peak = 0;
uint32_t total_interval = 0;
for(uint16_t i = 1; i < length - 1; i++)
{
if(pulse_data[i] > pulse_data[i-1] &&
pulse_data[i] > pulse_data[i+1] &&
pulse_data[i] > 2000) // 阈值检测
{
if(last_peak != 0)
{
total_interval += (i - last_peak);
}
last_peak = i;
peak_count++;
}
}
if(peak_count > 1)
{
float avg_interval = total_interval / (float)(peak_count - 1);
return (uint32_t)(6000.0 / avg_interval); // 100Hz采样率
}
return 0;
}
3.5 OLED显示模块
// oled.c
#include "ssd1306.h"
void Display_Result(uint32_t systolic, uint32_t diastolic, uint32_t heart_rate)
{
char buffer[20];
OLED_Clear();
// 显示标题
OLED_ShowString(24, 0, "BP Monitor");
OLED_DrawLine(0, 12, 127, 12);
// 显示收缩压
OLED_ShowString(0, 16, "SYS:");
sprintf(buffer, "%3d mmHg", systolic);
OLED_ShowString(40, 16, buffer);
// 显示舒张压
OLED_ShowString(0, 28, "DIA:");
sprintf(buffer, "%3d mmHg", diastolic);
OLED_ShowString(40, 28, buffer);
// 显示心率
OLED_ShowString(0, 40, "HR :");
sprintf(buffer, "%3d BPM", heart_rate);
OLED_ShowString(40, 40, buffer);
// 显示状态
OLED_ShowString(0, 52, "Status: OK");
}
3.6 滤波算法
// filter.c
// 移动平均滤波
void Moving_Average_Filter(uint16_t *data, uint16_t length, uint8_t window_size)
{
uint16_t temp[1000];
uint16_t i, j;
uint32_t sum;
for(i = window_size/2; i < length - window_size/2; i++)
{
sum = 0;
for(j = 0; j < window_size; j++)
{
sum += data[i - window_size/2 + j];
}
temp[i] = sum / window_size;
}
// 复制回原数组
for(i = window_size/2; i < length - window_size/2; i++)
{
data[i] = temp[i];
}
}
// 脉搏波包络提取
float Calculate_Envelope(uint16_t *data, uint16_t index, uint8_t window)
{
float max_val = 0;
uint16_t i;
for(i = index - window; i <= index + window; i++)
{
if(i < 1000 && data[i] > max_val)
{
max_val = data[i];
}
}
return max_val;
}
四、系统调试与校准
4.1 校准程序
void Calibration_Procedure(void)
{
OLED_ShowString(0, 0, "Calibration Mode");
OLED_ShowString(0, 16, "1. Release pressure");
OLED_ShowString(0, 28, "2. Press key when");
OLED_ShowString(0, 40, " ready");
while(!Key_Pressed());
uint32_t zero_offset = ADC_GetPressure();
OLED_Clear();
OLED_ShowString(0, 0, "Apply 100mmHg");
OLED_ShowString(0, 16, "standard pressure");
while(!Key_Pressed());
uint32_t ref_value = ADC_GetPressure();
// 保存校准参数到EEPROM/Flash
Save_Calibration(zero_offset, ref_value);
}
五、注意事项
-
安全要求:
- 袖带压力不应超过300mmHg
- 充气时间不宜过长,应有超时保护
- 加入硬件过压保护电路
-
精度优化:
- 使用多次测量取平均值
- 加入温度补偿算法
- 定期进行零点校准
-
电源管理:
- 使用3.3V LDO稳压
- 气泵使用单独电源供电
- 加入低功耗模式
-
EMC设计:
- 模拟信号使用屏蔽线
- 数字与模拟电源分离
- 加入滤波电容
六、扩展功能建议
- 数据存储:添加SD卡或EEPROM存储历史数据
- 蓝牙传输:添加HC-05模块实现手机APP连接
- 语音播报:添加语音芯片实现测量结果播报
- USB通信:实现与PC的数据通信和数据分析

498

被折叠的 条评论
为什么被折叠?



