29447945 发表于 2017-9-14 10:52

Max32630(四)——心率传感器

本帖最后由 29447945 于 2017-9-14 10:58 编辑

现在越来越多的人们重视自己的健康,参加各类运动,强身健体,个人也喜欢跑步,但是最近好久都没跑步了。
运动过程中,都需要关注的一个参数就是自己的心率,心率过高过低都不行,所以检测心率是一个很重要的参数。
现在最普遍的心率传感器就是 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 = 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 = rate;                  // and drop the oldest IBI value
      runningTotal += rate;            // add up the 9 oldest IBI values
      }

      rate = IBI;                        // add the latest IBI to the rate array
      runningTotal += rate;                // 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;                  // 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;
    unsigned int overflow;
    uint8_t fmtstr;   
    /* 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 = "hh:mm:ss";
      char Data_Data = "yyyy-mm-dd";
      char Data_Sensor = "BMP:xxxxIBI: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);
               
      }
}图片看不清,把视频上传上来






TankTseng 发表于 2018-1-31 09:43

{:1_103:}{:1_103:}{:1_103:}

风斩冰宁霜 发表于 2018-7-6 19:14

大佬使用什么单片机写的啊

风斩冰宁霜 发表于 2018-7-6 19:15

大佬使用什么单片机写的啊

29447945 发表于 2018-7-9 09:26

风斩冰宁霜 发表于 2018-7-6 19:15
大佬使用什么单片机写的啊

ST或者美信都可以
页: [1]
查看完整版本: Max32630(四)——心率传感器