硬件:STM32mini板,心率传感器
为了让下肢康复机器在使用时能够实时检测使用者的身体状况,往上面添加一个心率传感器来检测使用者的心率,现对它进行测试和程序编写。
实物图如下:
供电电压:3.3~5v
输出信号类型:模拟信号
输出信号大小:0~3.3v
佩戴实物:
为了对输出信号进行检测,使用单片机提供的3.3v电压对传感器进行供电,并通过示波器进行观察,波形如下:
可见波形还是比较清晰的,由于心率信号的周期较长,这里设置示波器的一个单位电压为100mV,设置时基500ms,Yposition为-1.5v,如果设置不合理,波形观察不到。
程序编写
使用外设:ADC1的通道1(PA1)、定时器3、与电脑通信的串口、LED0
IBI:两次心跳之间的间隔时间 BPM:心率
根据设想我们要测量的是下图中t1和t2之间的间隔时间
算法的大致思路是:
在一个固定的周期内进行多次ADC采样,取这个周期中的中间值为阈值
把采集的实时值与阈值比较,大于阈值即为有效波峰,计算这两次波峰之间的时间差
多次采集这个时间差,并且取它们的平均值,再用60s除以这个时间差即为BPM
先编写一个毫秒级的延时函数
TIM_TimeBaseStructure.TIM_Period = ms*10-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 time=(Period+1)(Prescaler+1)/(72000000)
TIM_TimeBaseStructure.TIM_Prescaler =7199; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_SelectOnePulseMode(TIM3, TIM_OPMode_Single);//选择单次计时模式
TIM_ClearFlag(TIM3,TIM_IT_Update);//清除标志位
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
while(!TIM_GetFlagStatus(TIM3, TIM_IT_Update)){}//等待计时的结束
TIM_Cmd(TIM3, DISABLE); //使能TIMx外设
TIM_ClearFlag(TIM3,TIM_IT_Update);//清除标志位
}
while(1)
{
pre_data=cur_data;
adcx=(Get_Adc_Average(ADC_Channel_1,10))-1500;//取到10次原始数据的平均值,并将整体下移
cur_data=adcx;
if(abs(cur_data-pre_data)<=filter)//简单滤除噪声
data[n++]=adcx;
else
continue;//直接进入下次的循环
PRE_PULSE=PULSE;
if(n>=SIZE)//这组数据采集已经满了
{
max=Max(data,SIZE);//重新取最大值、最小值、中间值、滤波值
min=Min(data,SIZE);
mid=(max+min)/2;
filter=(max-min)/2;
n=0;
k=0;
BPM=sum/j;//取均值
if(BPM>50&&BPM<180)//心率值在50~180之间显示
printf("BPM=%d\r\n",BPM);
sum=0;
j=0;
LED0=!LED0;
}
PULSE=(adcx>mid)?TRUE:FALSE;//有效波峰
if(PRE_PULSE == FALSE && PULSE == TRUE)//在上升沿达到了阈值
{
k++;
if(k%2==1)
FirTimCou=n;//记下在奇数上升沿处的时间次数
else
SecTimCou=n;//记下在偶数上升沿处的时间次数
Timtcount=abs(SecTimCou-FirTimCou);//得到两次上升沿之间的时间计数的次数
if(Timtcount>0)
{
temp=60000/(Timtcount*PERIOD);//得到瞬时的心率
if(temp>50&&temp<180)//取60~200之间的值
{
sum+=60000/(Timtcount*PERIOD);
j++;
}
}
}
Timer_3_Delay_ms(PERIOD);//延时一个时间周期
}
把程序烧写进单片机后,打开串口调试助手如下图所示,可见心率测量值还算比较准确