在单片机上计算心率的方式有两种,但最重要的步骤是捕捉波峰。首先我们得了解什么是心率,心率则是一分钟内心脏搏动的次数,那转为为电信号则是每一次的波峰。然后在我们了解什么是心率的基础下就可以开始介绍两种计算心率的方法:第一种则是按理解的一分钟的波峰数量,一个一个的去数,当然也可以开启中断去叠加波峰数量。但我不建议采用第一种方式,因为得需要单片机运行个1分钟才能出来结果,不仅效率慢,而且对等的人也是折磨。在这里我采用的第二种方式:我们如果知道了第一个波峰与第二个波峰的时间间隔T,就可以用一分钟来除以这个时间间隔T的话就能得到一分钟内的波峰数量,计算时间快,效率高,并且准确。
那怎么去实现呢?我们用adc的时候是开启定时器的,我们能知道adc多久采样一次并且知道adc采样到的值,所以在这里可以用adc采样到的值做一个阈值法(当adc的值达到一次值时记为达到一次峰值)。注意!!!!这里必须要对采样到的信号进行滤波处理后才能进行阈值法,不然可能会有噪声干扰,让adc采到错误的值误以为达到了波峰。
这里adc是12位精度的,所以采样到的值将会是0——4095
付代码:
在4ms的时候adc采集一次波形数据,然后记录两次波峰的时间;这里有两个需要注意的点,也是值得学习的点,我需要存4个波形数据,数组为4,所以得循环着存,这里最好采用s_iPointCnt = (s_iPointCnt + 1) % 4;余数的方式,避免数组溢出多了莫名的bug。另外一个点就是计数的CountTime最好设置到32位是不会错的,万一太小了又得回来改。
if(Get2msFlag()) //判断2ms标志状态
{
if(ReadUART1(&uart1RecData, 1)) //读串口接收数据
{
ProcHostCmd(uart1RecData); //处理命令
}
s_iCnt4++; //计数增加
s_iCnt8++;
if(s_iCnt4>= 2) //达到4ms
{
if(ReadADCBuf(&adcData)) //从缓存队列中取出1个数据
{
waveData = WriteFilterBuf(adcData);
//printf("[[1,%d]]\r\n", waveData);
//printf("%d,",adcData);
CountTime++;
ecgHByte = waveData >> 8 ;
ecgLByte = waveData ;
//printf("[[2,%d]]\r\n", ecgLByte);
s_arrWaveData[s_iPointCnt] = ecgHByte;
s_iPointCnt = (s_iPointCnt + 1) % 4;
s_arrWaveData[s_iPointCnt] = ecgLByte;
s_iPointCnt = (s_iPointCnt + 1) % 4;
if(waveData >=2140 && waveData <= 2170 && Get1Peak == 0)
{
FirstCount = CountTime;
Get1Peak = 1;
}
else if( CountTime > FirstCount+10 && Get1Peak ==1)
{
if(waveData >= 2140 && waveData <= 2170 )
{
SecondCount = CountTime;
Get2Peak = 1;
Get1Peak = 0;
CountTime = 0;
//printf("%d,",60000/ ((SecondCount- FirstCount)*4));
}
}
// printf("[[1,%d]]\r\n", BMP);
}
s_iCnt4= 0; //准备下次的循环
}
if(s_iCnt8 >= 4 && s_iPointCnt == 0) //8ms并且数组接收完了就发送ecg
{
//printf("%d--%d--%d--%d\r\n",s_arrWaveData[0],s_arrWaveData[1],s_arrWaveData[2],s_arrWaveData[3]);
SendECGToHost(s_arrWaveData);
// SendWaveToHost(s_arrWaveData); //发送波形数据包
s_iCnt8 = 0;
}
LEDFlicker(250);//调用闪烁函数
Clr2msFlag(); //清除2ms标志
}
1sec的时候计算心率:
static void Proc1SecTask(void)
{
u8 ecgHByte = 0;
u8 ecgLByte = 0;
static u8 s_arrHRData[2];
if(Get1SecFlag()) //判断1s标志状态
{
if(Get2Peak == 1)
{
BMP = 60000/ ((SecondCount- FirstCount)*4);
Get2Peak =0;
if(BMP > 200)
{
BMP = 200;
}
else if(BMP <30)
{
BMP = 30;
}
ecgHByte = BMP >> 8 ;
ecgLByte = BMP ;
s_arrHRData[0] = ecgHByte;
s_arrHRData[1] = ecgLByte;
SendHeartRateToHost(s_arrHRData);
}
Clr1SecFlag(); //清除1s标志
}
}
经过验算,时间效率高,准确率也高!