简介
PulseSensor是一款用于脉搏心率测量的光电反射式模拟传感器。将其佩戴于手指、耳垂等处,通过导线连接可将采集到的模拟信号传输给单片机用来转换为数字信号,再通过单片机简单计算后就可以得到心率数值。其适用于心率方面的科学研究和教学演示,也非常适合用于二次开发。
性能参数
供电电压 | 3.3v或5v |
---|---|
输出信号类型 | 模拟信号 |
输出信号大小 | 0-3.3v或0-5v |
电流大小 | 4ma(5V下) |
原理说明
传统的脉搏测量方法主要有三种:一是从心电信号中提取;二是从测量血压时压力传感器测到的波动来计算脉率;三是光电容积法。前两种方法提取信号都会限制病人的活动,如果长时间使用会增加病人生理和心理上的不舒适感。而光电容积法脉搏测量作为监护测量中最普遍的方法之一,其具有方法简单、佩戴方便、可靠性高等特点。光电容积法的基本原理是利用人体组织在血管搏动时造成透光率不同来进行脉搏测量的。其使用的传感器由光源和光电变换器两部分组成,通过绑带或夹子固定在病人的手指或耳垂上。光源一般采用对动脉血中氧和血红蛋白有选择性的一定波长(500nm-700nm)的发光二极管。当光束透过人体外周血管,由于动脉搏动充血容积变化导致这束光的透光率发生改变,此时由光电变换器接收经人体组织反射的光线,转变为电信号并将其放大和输出。由于脉搏是随心脏的搏动而周期性变化的信号,动脉血管容积也周期性变化,因此光电变换器的电信号变化周期就是脉搏率。根据相关文献和实验结果,560nm波长左右的波可以反映皮肤浅部微动脉信息,适合用来提取脉搏信号。该传感器采用了峰值波长为515nm的绿光LED,型号为AM2520,而光接收器采用了APDS-9008,这是一款环境光感受器,感受峰值波长为565nm,两者的峰值波长相近,灵敏度较高。此外,由于脉搏信号的频带一般在 0. 05-200Hz之间,信号幅度均很小,一般在亳伏级水平,容易受到各种信号干扰。在感受器后面使用了低通滤波器和由运放MCP6001构成的放大器,将信号放大了331倍,同时采用分压电阻设置直流偏置电压为电源电压的1/2,使放大后的信号可以很好地被单片机的AD采集到。
心率结构图
心率采样数据
变量说明
Variable Name | Refresh rate | What It Is |
---|---|---|
Signal | 2mS | raw Pulse Sensor signal |
IBI | every beat | time between heartbeats in mS |
BPM | every beat | beats per minute |
QS | set true every beat | must be cleared by user |
Pulse | set true every beat | cleared by ISR |
上表中,最主要的是IBI和BPM两个值。IBI 表示连续的两个心跳之间的时间差,而BPM是心率值,表示每分钟心跳数,则BPM=60/IBI。
采样
主要通过ADC单元来采样传感器输出的脉搏模拟信号。
滤波
由于脉搏波在动脉中的反射,往往会出现一个重搏波(如下图)。为了避免重搏波的干扰,在程序中每隔0.6个IBI的值才开始跟踪脉搏的上升。
阈值选取
为了适应不同信号的波峰检测,需要根据信号振幅来调整阈值。对一个周期内的信号进行多次采样,得出信号的最高和最低电压值,由此算出阈值,再用这个阈值对采集的电压值进行判定,考虑是否为波峰。即电压信号的处理分为两步,首先动态计算出参考阈值,然后用用阈值对信号判定、识别一个波峰。
计算
上面得出一段有效波形,接着是进行心率的计算,根据相邻两个脉搏波的上升段的中间值之差来确定的IBI的数值(如下图),BPM是通过对前10个IBI时间段的平均值得出的每拍心率,由此就可以算出BPM的数值。
连线
STM32 | PulseSensor | OLED |
---|---|---|
3.3V | VCC | VCC |
GND | GND | GND |
PA0 | S | - |
PB9 | - | SCL |
PB8 | - | SDA |
代码
Timer.c(部分)
if(Signal < thresh && N > (IBI/5)*3)
{
if (Signal < T)
{
T = Signal;
}
}
if(Signal > thresh && Signal > P)
{
P = Signal;
}
变量P和T分别表示峰值和谷值。thresh变量在运行开始时初始化为512(模拟范围的中点),为了避免噪声和错误读数,必须经过3/5个IBI的时间周期后更新T。
runningTotal = 0;
for(i=0; i<=8; i++)
{
rate[i] = rate[i+1];
runningTotal += rate[i];
}
rate[9] = IBI;
runningTotal += rate[9];
runningTotal /= 10;
BPM = 60000/runningTotal;
QS = true;
}
}
要保留最后10个IBI值的运行总数。采集10次,再进行一次采集时,需要把第二到第十个数据往前移,把第一数据去掉了,保存10个数据取平均值后再进行心率计算。
main.c
int main(void)
{
unsigned char tp[16]=" ";
u8 datatemp[SIZE];
_Bool Heart_OK = 0; //读取到正确心率标志位
unsigned char Heart = 0; //心率值
SystemInit();//配置系统时钟为72M
delay_init(72);
USART1_Config();//串口初始化
LED_Init();
LED_On();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//设置中断优先级分组为组3:2位抢占优先级,2位响应优先级
USART1_Config();//串口初始化
OLED_Init();
printf("Start \n");
delay_ms(1000);
OLED_ShowString(16,0,"PulseSensor",16,1);
OLED_ShowString(0,32,"Heart rate",16,1);
OLED_ShowChar(80,32,':',16,1);
ADCx_Init();
TIM3_Int_Init(1999,71); //定时2ms中断
TIM2_Int_Init(199,7199); //10Khz的计数频率,计数到500为20ms
while(1)
{
if(Timer_Flag==1) //500ms到 读取数据
{
Timer_Flag = 0; //清除标志
TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE ); //使能指定的TIM3中断,允许更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE ); //使能指定的TIM3中断,允许更新中断
delay_ms(500);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
TIM_Cmd(TIM2, ENABLE); //使能TIMx
if (QS == true) //读取到了心率信号
{
QS = false; //清除标志 等待下一次读取
if(BPM>HEART_MIN_ERROR&&BPM<HEART_MAX_ERROR) //读取到的值再正常心率区间 40-160内
{
Heart_OK = 1; //标志位置一
Heart = BPM; //心率传递给Heart
}
else
{
Heart_OK = 0; //标志位清零
Heart = 0; //设置为0
}
}
}
delay_ms(20);
if(Heart_OK==1) //读取到正确心率
{
OLED_ShowNum(88,32,Heart,3,16,1);
printf("Heart rate:");
printf("%d\r\n",Heart);
}
else
{
OLED_ShowString(88,32,"---",16,1);
printf("not found\r\n");
}
}
}
在主函数while(1)中当读取到的数据在正常心率区间40-160内时,就把心率值打印在串口和显示在OLED上,否则将没有数据。
结果
串口打印心率值:
OLED显示心率值:
总结
在进行心率检测时,需要注意以下几点:
(1)保持指尖干净无潮湿并与传感器接触良好。
(2)不要太用力按传感器, 否则可能造成血液不循环而无法检测到脉搏数据。
(3)测量时尽量不要移动身体和手指,否则可能会影响测量数据的准确性。