社区导航

 

搜索
查看: 3007|回复: 4

[设计过程分享] Max32630(四)——心率传感器

[复制链接]

447

TA的帖子

3

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2017-9-14 10:52 | 显示全部楼层 |阅读模式
本帖最后由 29447945 于 2017-9-14 10:58 编辑

现在越来越多的人们重视自己的健康,参加各类运动,强身健体,个人也喜欢跑步,但是最近好久都没跑步了。
运动过程中,都需要关注的一个参数就是自己的心率,心率过高过低都不行,所以检测心率是一个很重要的参数。
现在最普遍的心率传感器就是 PulseSensor 脉搏心率传感器
QQ截图20170914104627.png
可以检测心率和脉搏;
QQ截图20170914104639.png
原理主要就是通过光反射,转化为电压信号,单片机通过ADC采集电压,然后在通过算法得到心率和心跳;
IMG_2248.gif

其中算法部分代码都是现成,我们使用时只需要把ADC配置好,读取数据就可以得到需要的参数;
算法部分:


  1. void SensorTimer_handler(void)
  2. {
  3.         float temp = 0;
  4.         unsigned int runningTotal;
  5.         
  6.         
  7.                 ADC_GetData(&Signal);                                         // read the Pulse Senso
  8.         temp = Signal * 1.818;
  9.         Signal = (u16)temp-1;
  10.                 sampleCounter += 2;                         // keep track of the time in mS with this variable
  11.                 Num = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise
  12.                 ADC_StartConvert(ADC_CH_1_DIV_5, 0, 1);                                                        //restart ADC conversion

  13.                 //  find the peak and trough of the pulse wave
  14.   if(Signal < thresh && Num > (IBI/5)*3){       // avoid dichrotic noise by waiting 3/5 of last IBI
  15.     if (Signal < T){                        // T is the trough
  16.       T = Signal;                         // keep track of lowest point in pulse wave
  17.     }
  18.   }

  19.   if(Signal > thresh && Signal > P){          // thresh condition helps avoid noise
  20.     P = Signal;                             // P is the peak
  21.   }                                        // keep track of highest point in pulse wave

  22.   //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  23.   // signal surges up in value every time there is a pulse
  24.   if (Num > 250){                                   // avoid high frequency noise
  25.     if ( (Signal > thresh) && (Pulse == 0) && (Num > (IBI/5)*3) ){        
  26.       Pulse = 1;                               // set the Pulse flag when we think there is a pulse
  27. //      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);                // turn on pin 13 LED
  28.       IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
  29.       lastBeatTime = sampleCounter;               // keep track of time for next pulse

  30.       if(secondBeat){                        // if this is the second beat, if secondBeat == TRUE
  31.         secondBeat = 0;                  // clear secondBeat flag
  32.         for(int i=0; i<=9; i++){             // seed the running total to get a realisitic BPM at startup
  33.           rate[i] = IBI;                     
  34.         }
  35.       }

  36.       if(firstBeat){                         // if it's the first time we found a beat, if firstBeat == TRUE
  37.         firstBeat = 0;                   // clear firstBeat flag
  38.         secondBeat = 1;                   // set the second beat flag
  39. //       sei();                               // enable interrupts again
  40.         return;                              // IBI value is unreliable so discard it
  41.       }   


  42.       // keep a running total of the last 10 IBI values
  43.       runningTotal = 0;                  // clear the runningTotal variable   

  44.       for(int i=0; i<=8; i++){                // shift data in the rate array
  45.         rate[i] = rate[i+1];                  // and drop the oldest IBI value
  46.         runningTotal += rate[i];              // add up the 9 oldest IBI values
  47.       }

  48.       rate[9] = IBI;                          // add the latest IBI to the rate array
  49.       runningTotal += rate[9];                // add the latest IBI to runningTotal
  50.       runningTotal /= 10;                     // average the last 10 IBI values
  51.       BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
  52.       QS = 1;                              // set Quantified Self flag
  53.       // QS FLAG IS NOT CLEARED INSIDE THIS ISR
  54.     }                       
  55.   }

  56.   if (Signal < thresh && Pulse == 1){   // when the values are going down, the beat is over
  57. //     HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);            // turn off pin 13 LED
  58.     Pulse = 0;                         // reset the Pulse flag so we can do it again
  59.     amp = P - T;                           // get amplitude of the pulse wave
  60.     thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
  61.     P = thresh;                            // reset these for next time
  62.     T = thresh;
  63.   }

  64.   if (Num > 2500){                           // if 2.5 seconds go by without a beat
  65.     thresh = 512;                          // set thresh default
  66.     P = 512;                               // set P default
  67.     T = 512;                               // set T default
  68.     lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
  69.     firstBeat = 1;                      // set these to avoid noise
  70.     secondBeat = 0;                    // when we get the heartbeat back
  71.   }

  72.     TMR32_ClearFlag(MXC_TMR2);
  73. }
复制代码

读值:

  1. int BPM;                   // used to hold the pulse rate
  2. u16 Signal;                // holds the incoming raw data
  3. int IBI = 600;             // holds the time between beats, must be seeded!
  4. unsigned char Pulse = 0;     // true when pulse wave is high, false when it's low
  5. unsigned char QS = 0;        // becomes true when Arduoino finds a beat.
  6. int rate[10];                    // array to hold last ten IBI values
  7. unsigned long sampleCounter = 0;          // used to determine pulse timing
  8. unsigned long lastBeatTime = 0;           // used to find IBI
  9. int P =426;                      // used to find peak in pulse wave, seeded
  10. int T = 426;                     // used to find trough in pulse wave, seeded
  11. int thresh = 426;                // used to find instant moment of heart beat, seeded
  12. int amp = 100;                   // used to hold amplitude of pulse waveform, seeded
  13. int Num;
  14. unsigned char firstBeat = 1;        // used to seed rate array so we startup with reasonable BPM
  15. unsigned char secondBeat = 0;      // used to seed rate array so we startup with reasonable BPM

  16. void sendDataToProcessing(char symbol, int dat )
  17. {
  18.     putchar(symbol);                // symbol prefix tells Processing what type of data is coming
  19.                 printf("%d\r\n",dat);                                                // the data to send culminating in a carriage return
  20. }

  21. int Sensor_Task(void)
  22. {
  23.         static u32 PointM = 0;
  24.         
  25.     uint16_t adc_val[4];
  26.     unsigned int overflow[4];
  27.     uint8_t fmtstr[40];   
  28.     /* Initialize ADC */
  29.    
  30.    
  31.         if( ( OsDelayCCnt - PointM ) >= T_20MS)
  32.         {
  33.                 PointM = OsDelayCCnt;
  34.         /* Convert channel 0 */
  35.         sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
  36.                 if (QS == 1)
  37.                 {
  38.                         User.BPM = BPM;
  39.                         User.IBI = IBI;
  40.                                 sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
  41.                                 sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
  42.                                 QS = 0;                      // reset the Quantified Self flag for next time
  43.                 }
  44.         /* Delay for 1/4 second before next reading */

  45.     }
  46. }
复制代码
显示:
  1. void OLED_Task(void)
  2. {
  3.         static u32 PointM = 0;
  4.         static u8 mState = 0;
  5.         char Data_Time[9] = "hh:mm:ss";
  6.         char Data_Data[11] = "yyyy-mm-dd";
  7.         char Data_Sensor[19] = "BMP:xxxx  IBI:xxxx";
  8.         LCD_P8x16Str(36,0,"MAX32630");
  9. //        LCD_P8x16Str(0,2,"EEWORLD");
  10. //        LCD_P8x16Str(0,4,"Smart Watch");
  11.         if( ( OsDelayCCnt - PointM ) >= T_1S)
  12.         {
  13.                 PointM = OsDelayCCnt;
  14. //                LCD_CLS();
  15.                 sprintf(Data_Sensor,"BMP:%03d IBI:%04d",User.BPM,User.IBI);
  16.                 LCD_P8x16Str(0,2,Data_Sensor);
  17.                 sprintf(Data_Data,"%04d-%02d-%02d",User.RtcTime.Year + 2000,User.RtcTime.Mon,User.RtcTime.Day);
  18.                 LCD_P8x16Str(0,4,Data_Data);
  19.                 sprintf(Data_Time,"%02d:%02d:%02d",User.RtcTime.Hour,User.RtcTime.Min,User.RtcTime.Sec);
  20.                 LCD_P8x16Str(0,6,Data_Time);
  21.                
  22.         }
  23. }
复制代码
IMG_2249.PNG 图片看不清,把视频上传上来 IMG_2248.mp4 (1.61 MB, 下载次数: 4)

评分

1

查看全部评分



回复

使用道具 举报

13

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2018-1-31 09:43 | 显示全部楼层


回复

使用道具 举报

3

TA的帖子

3

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2018-7-6 19:14 | 显示全部楼层
大佬使用什么单片机写的啊


回复

使用道具 举报

3

TA的帖子

3

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2018-7-6 19:15 | 显示全部楼层
大佬使用什么单片机写的啊

点评

ST或者美信都可以  详情 回复 发表于 2018-7-9 09:26


回复

使用道具 举报

447

TA的帖子

3

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

 楼主| 发表于 2018-7-9 09:26 | 显示全部楼层
风斩冰宁霜 发表于 2018-7-6 19:15
大佬使用什么单片机写的啊

ST或者美信都可以


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/7 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

词云| Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-7-13 22:32 , Processed in 0.210394 second(s), 28 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表