现在越来越多的人们重视自己的健康,参加各类运动,强身健体,个人也喜欢跑步,但是最近好久都没跑步了。
运动过程中,都需要关注的一个参数就是自己的心率,心率过高过低都不行,所以检测心率是一个很重要的参数。
现在最普遍的心率传感器就是PulseSensor 脉搏心率传感器
可以检测心率和脉搏;
原理主要就是通过光反射,转化为电压信号,单片机通过ADC采集电压,然后在通过算法得到心率和心跳;
其中算法部分代码都是现成,我们使用时只需要把ADC配置好,读取数据就可以得到需要的参数;
算法部分:
[C] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
void
SensorTimer_handler(
void
)
{
float
temp = 0;
unsigned
int
runningTotal;
ADC_GetData(&Signal);
// read the Pulse Senso
temp = Signal * 1.818;
Signal = (u16)temp-1;
sampleCounter += 2;
// keep track of the time in mS with this variable
Num = sampleCounter - lastBeatTime;
// monitor the time since the last beat to avoid noise
ADC_StartConvert(ADC_CH_1_DIV_5, 0, 1);
//restart ADC conversion
// find the peak and trough of the pulse wave
if
(Signal < thresh && Num > (IBI/5)*3){
// avoid dichrotic noise by waiting 3/5 of last IBI
if
(Signal < T){
// T is the trough
T = Signal;
// keep track of lowest point in pulse wave
}
}
if
(Signal > thresh && Signal > P){
// thresh condition helps avoid noise
P = Signal;
// P is the peak
}
// keep track of highest point in pulse wave
// NOW IT'S TIME TO LOOK FOR THE HEART BEAT
// signal surges up in value every time there is a pulse
if
(Num > 250){
// avoid high frequency noise
if
( (Signal > thresh) && (Pulse == 0) && (Num > (IBI/5)*3) ){
Pulse = 1;
// set the Pulse flag when we think there is a pulse
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); // turn on pin 13 LED
IBI = sampleCounter - lastBeatTime;
// measure time between beats in mS
lastBeatTime = sampleCounter;
// keep track of time for next pulse
if
(secondBeat){
// if this is the second beat, if secondBeat == TRUE
secondBeat = 0;
// clear secondBeat flag
for
(
int
i=0; i<=9; i++){
// seed the running total to get a realisitic BPM at startup
rate[i] = IBI;
}
}
if
(firstBeat){
// if it's the first time we found a beat, if firstBeat == TRUE
firstBeat = 0;
// clear firstBeat flag
secondBeat = 1;
// set the second beat flag
// sei(); // enable interrupts again
return
;
// IBI value is unreliable so discard it
}
// keep a running total of the last 10 IBI values
runningTotal = 0;
// clear the runningTotal variable
for
(
int
i=0; i<=8; i++){
// shift data in the rate array
rate[i] = rate[i+1];
// and drop the oldest IBI value
runningTotal += rate[i];
// add up the 9 oldest IBI values
}
rate[9] = IBI;
// add the latest IBI to the rate array
runningTotal += rate[9];
// add the latest IBI to runningTotal
runningTotal /= 10;
// average the last 10 IBI values
BPM = 60000/runningTotal;
// how many beats can fit into a minute? that's BPM!
QS = 1;
// set Quantified Self flag
// QS FLAG IS NOT CLEARED INSIDE THIS ISR
}
}
if
(Signal < thresh && Pulse == 1){
// when the values are going down, the beat is over
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); // turn off pin 13 LED
Pulse = 0;
// reset the Pulse flag so we can do it again
amp = P - T;
// get amplitude of the pulse wave
thresh = amp/2 + T;
// set thresh at 50% of the amplitude
P = thresh;
// reset these for next time
T = thresh;
}
if
(Num > 2500){
// if 2.5 seconds go by without a beat
thresh = 512;
// set thresh default
P = 512;
// set P default
T = 512;
// set T default
lastBeatTime = sampleCounter;
// bring the lastBeatTime up to date
firstBeat = 1;
// set these to avoid noise
secondBeat = 0;
// when we get the heartbeat back
}
TMR32_ClearFlag(MXC_TMR2);
}
读值:
[C] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int
BPM;
// used to hold the pulse rate
u16 Signal;
// holds the incoming raw data
int
IBI = 600;
// holds the time between beats, must be seeded!
unsigned
char
Pulse = 0;
// true when pulse wave is high, false when it's low
unsigned
char
QS = 0;
// becomes true when Arduoino finds a beat.
int
rate[10];
// array to hold last ten IBI values
unsigned
long
sampleCounter = 0;
// used to determine pulse timing
unsigned
long
lastBeatTime = 0;
// used to find IBI
int
P =426;
// used to find peak in pulse wave, seeded
int
T = 426;
// used to find trough in pulse wave, seeded
int
thresh = 426;
// used to find instant moment of heart beat, seeded
int
amp = 100;
// used to hold amplitude of pulse waveform, seeded
int
Num;
unsigned
char
firstBeat = 1;
// used to seed rate array so we startup with reasonable BPM
unsigned
char
secondBeat = 0;
// used to seed rate array so we startup with reasonable BPM
void
sendDataToProcessing(
char
symbol,
int
dat )
{
putchar
(symbol);
// symbol prefix tells Processing what type of data is coming
printf
(
"%d\r\n"
,dat);
// the data to send culminating in a carriage return
}
int
Sensor_Task(
void
)
{
static
u32 PointM = 0;
uint16_t adc_val[4];
unsigned
int
overflow[4];
uint8_t fmtstr[40];
/* Initialize ADC */
if
( ( OsDelayCCnt - PointM ) >= T_20MS)
{
PointM = OsDelayCCnt;
/* Convert channel 0 */
sendDataToProcessing(
'S'
, Signal);
// send Processing the raw Pulse Sensor data
if
(QS == 1)
{
User.BPM = BPM;
User.IBI = IBI;
sendDataToProcessing(
'B'
,BPM);
// send heart rate with a 'B' prefix
sendDataToProcessing(
'Q'
,IBI);
// send time between beats with a 'Q' prefix
QS = 0;
// reset the Quantified Self flag for next time
}
/* Delay for 1/4 second before next reading */
}
}
显示:
[C] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void
OLED_Task(
void
)
{
static
u32 PointM = 0;
static
u8 mState = 0;
char
Data_Time[9] =
"hh:mm:ss"
;
char
Data_Data[11] =
"yyyy-mm-dd"
;
char
Data_Sensor[19] =
"BMP:xxxx IBI:xxxx"
;
LCD_P8x16Str(36,0,
"MAX32630"
);
// LCD_P8x16Str(0,2,"EEWORLD");
// LCD_P8x16Str(0,4,"Smart Watch");
if
( ( OsDelayCCnt - PointM ) >= T_1S)
{
PointM = OsDelayCCnt;
// LCD_CLS();
sprintf
(Data_Sensor,
"BMP:%03d IBI:%04d"
,User.BPM,User.IBI);
LCD_P8x16Str(0,2,Data_Sensor);
sprintf
(Data_Data,
"%04d-%02d-%02d"
,User.RtcTime.Year + 2000,User.RtcTime.Mon,User.RtcTime.Day);
LCD_P8x16Str(0,4,Data_Data);
sprintf
(Data_Time,
"%02d:%02d:%02d"
,User.RtcTime.Hour,User.RtcTime.Min,User.RtcTime.Sec);
LCD_P8x16Str(0,6,Data_Time);
}
}
(下载iPhone或Android应用“经理人分享”,一个只为职业精英人群提供优质知识服务的分享平台。不做单纯的资讯推送,致力于成为你的私人智库。)