现在越来越多的人们重视自己的健康,参加各类运动,强身健体,个人也喜欢跑步,但是最近好久都没跑步了。
运动过程中,都需要关注的一个参数就是自己的心率,心率过高过低都不行,所以检测心率是一个很重要的参数。
现在最普遍的心率传感器就是
PulseSensor 脉搏心率传感器
可以检测心率和脉搏;
原理主要就是通过光反射,转化为电压信号,单片机通过ADC采集电压,然后在通过算法得到心率和心跳;
其中算法部分代码都是现成,我们使用时只需要把ADC配置好,读取数据就可以得到需要的参数;
算法部分:
-
-
- 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);
- }
读值:
-
- 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 */
-
- }
- }
显示:
- 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);
-
- }
- }
图片看不清,把视频上传上来
本帖最后由 29447945 于 2017-9-14 10:58 编辑