Go Down

Topic: Max30102 Heart Rate + Bluetooth (Read 109 times) previous topic - next topic

ddesousa

Nov 17, 2017, 01:47 am Last Edit: Nov 17, 2017, 02:01 am by ddesousa
Hi there I am using the Max30102 Ref Design #117

( https://www.maximintegrated.com/en/design/reference-design-center/system-board/6300.html )

and a Bluetooth module

( https://www.amazon.ca/gp/product/B01D8GEO4K/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1 )

Both work seperatly but together, but as soon as I implemented the heart rate sensor, I started reading data like this where the hours go missing:

Code: [Select]
7:40:51 PM
7:40:52 PM
7:40:53 PM
7:40:54 PM
:40:55 PM
7:40:56 PM
7:40:57 PM
7:40:58 PM
7:40:59 PM
:41:00 PM
:41:01 PM
:41:02 PM
:41:03 PM
:41:04 PM
:41:05 PM
7:41:07 PM
7:41:08 PM


Other components used: SAMD21 breakout mini, uSD from Adafruit, MPU6050 from DFRobot, 0.96 inch display from Adafruit.

Some of my code is here:
Code: [Select]
#include <SAMD_AnalogCorrection.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "I2Cdev.h"
#include "MAX30105.h"
#include "heartRate.h"

extern "C" char *sbrk(int i);

// Bluetooth and Clock Variables
char dateBT[15]; // date info MM/DD/YYYY
char timeBT[15]; // time info HH:MM:SS MM
char callBT[20]; // caller number info
char textBT[20]; // text number info
bool isBTConnected; // used to determine if Bluetooth device is connected
bool isRTCInit; // determines if RTC has been initialized
unsigned long btLastConnected; // time which Bluetooth was last connected
RTCZero rtc; // instance of RTCZero class
byte lastSecondDisplayUpdated; // last second which display was updated (only update display every second)

// Step Counting Variables
Quaternion q; // quaternion container [w, x, y, z]
const double stepDiffMinThreshold = 0.025; // minimum difference between step max and min for considered step
int stepCount = 0; // total number of steps taken
double stepMax = 0; // peak of quaternion data
double stepMin = 0; // trough of quaternion data
double currentQData[3]; // array storing recent quaternion values

// Heart Rate Variables
MAX30105 heartRateSensor; // instance of MAX30105 class
const byte arraySizeHR = 5; // size of array containing latest HR values
byte heartRates[arraySizeHR]; // array containing latest HR values
byte heartRateIndex = 0; // index latest value was inputted into array
long prevHeartBeat = 0; // time at which the last heart beat occurred
float heartRate; // current heart rate
int heartRateAvg; // average heart rate which will we be displayed

// Bootloader
void setup()
{
  Serial1.begin(9600);
  SerialUSB.begin(9600);
  Wire.begin();
 
  // Define Displays I2C address and display boot screen
  u8g2.begin();
  u8g2.firstPage();
  do {
    u8g2.drawXBMP(32, 0, 64, 64, boot);
  } while ( u8g2.nextPage() );
 
  // setup MPU6050
  mpu.initialize(); // power up device and take out of sleep mode
  pinMode(mpu6050_int, INPUT);
  mpu.dmpInitialize(); // load DMP flash and configure the DMP
  mpu.setDMPEnabled(true); // turn on the DMP, now that it's ready

  // setup MPU6050 interrupt
  attachInterrupt(digitalPinToInterrupt(mpu6050_int), dmpDataReady, RISING);
  mpuIntStatus = mpu.getIntStatus();

  // get expected DMP packet size
  packetSize = mpu.dmpGetFIFOPacketSize();

  // initialize SD card
  SD.begin(sd_CS);
 
  // initialize Real Time Clock
  rtc.begin();

  // Turn on and setup heart rate sensor
  heartRateSensor.begin(Wire, I2C_SPEED_STANDARD); // 100 KHz
  heartRateSensor.setup(); // configure sensor with default settings
  heartRateSensor.setPulseAmplitudeRed(0x0A); // red LED to low to indicate sensor is running
  heartRateSensor.setPulseAmplitudeGreen(0); // turn off Green LED
 
  delay(3000);
}

// Function which reads and parses BT data from mobile
void readBTData()
{
  // save date
  memset(dateBT, 0, strlen(dateBT)); // clear
  Serial1.readBytesUntil('|', dateBT, 20);
  str_replace(dateBT, " ", "");
  Serial1.read();

  // save time
  memset(timeBT, 0, strlen(timeBT));
  Serial1.readBytesUntil('|', timeBT, 20);
  Serial1.read();
  SerialUSB.println(timeBT);
}

// Function used to calculate users heart rate
void calculateHR()
{
  // obtain infrared value
  long irValue = heartRateSensor.getIR();

  // if heart beat was detected
  if (checkForBeat(irValue) == true)
  {
    // calculate time difference between 2 beats
    long heartBeatTimeDiff = millis() - prevHeartBeat;
    prevHeartBeat = millis();

    // use the difference to calculate the heart rate
    heartRate = 60 / (heartBeatTimeDiff / 1000.0); // 60 s in 1 min, 1000 ms in 1 s

    // only use valid heart rates
    if (heartRate < 120 && heartRate > 40)
    {
      // store heart rate
      heartRates[heartRateIndex++] = (byte)heartRate;
      heartRateIndex %= arraySizeHR; // use modulus op. to determine current index

      // calcute average heart rate
      heartRateAvg = 0; // reset
      for (int i = 0; i < arraySizeHR; i++)
        heartRateAvg += heartRates[i]; // add up all heart rates
      heartRateAvg /= arraySizeHR; // determine average by dividing
    }
  }
}

void loop()
{
  // only read BT data if device is connected
  if (Serial1.available())
  {
    isBTConnected = true;
    readBTData();

    // remove seconds
    str_remove(timeBT, strlen(timeBT) - 6, 3);
   
    // update display
    u8g2.firstPage();
    do {
      updateDisplay();
    } while ( u8g2.nextPage() );

    // open log file
    logFile = SD.open("Esperto.txt", FILE_WRITE);
    // write date, time, HR, and step data to SD if its open
    if (logFile)
    {
      logFile.write(dateBT, strlen(dateBT));
      logFile.print(" ");
      logFile.write(timeBT, strlen(timeBT));
      logFile.println(" | Step Count = " + String(stepCount*2) + " | Heart Rate = " + String(heartRateAvg) + " bpm");
      logFile.close();
    }
   
    // update the time at which Bluetooth was last connected
    btLastConnected = millis();
  }
  else if((isBTConnected == true || isRTCInit == true) && ((millis() - btLastConnected) > 5000) && lastSecondDisplayUpdated != rtc.getSeconds())
  {
    // set time based off last Bluetooth connection
    if(isBTConnected == true)
    {
      setRTCTime();
    }
   
    // update display
    u8g2.firstPage();
    do {
      updateDisplay();
    } while ( u8g2.nextPage() );

     // open log file
    logFile = SD.open("Esperto.txt", FILE_WRITE);
    // write date, time, HR, and step data to SD if its open
    if (logFile)
    {
      logFile.print(String(rtc.getMonth()) + "/" + String(rtc.getDay()) + "/20" + String(rtc.getYear()));
      logFile.print(" " + String(rtc.getHours()) + ":" + String(rtc.getMinutes()) + ":" + String(rtc.getSeconds()));
      logFile.println(" | Step Count = " + String(stepCount*2) + " | Heart Rate = " + String(heartRateAvg) + " bpm");
      logFile.close();
    }
   
    // update statuses
    isRTCInit = true;
    isBTConnected = false;
    lastSecondDisplayUpdated = rtc.getSeconds();
  }

  // wait for MPU interrupt to process steps
  if (mpuInterrupt)
  {
    mpuInterrupt = false; // reset interrupt flag
    countSteps();
  }
 
  // calculate heart rate
  calculateHR();
}

// HELPER FUNCTIONS

// Function which replaces char(s) with new char(s) in a char array
void str_replace(char *src, char *oldchars, char *newchars)
{
  char *p = strstr(src, oldchars); // returns a pointer to the first occurrence of oldchars in src
  char buf[20];
  do {
    memset(buf, 0, strlen(buf));
    // until pointer points to null or zero
    if (p) {
      // if replacing char from beginining
      if (src == p) {
        strcpy(buf, newchars);
        strcat(buf, p + strlen(oldchars));
      } else {
        strncpy(buf, src, strlen(src) - strlen(p));
        strcat(buf, newchars);
        strcat(buf, p + strlen(oldchars));
      }
      memset(src, 0, strlen(src));
      strcpy(src, buf);
    }
  } while (p && (p = strstr(src, oldchars)));
}

// Function which removes a "count" of chars from a char array starting at "index"
void str_remove(char *src, int index, int count)
{
  char *p = src + index; // create pointer at index location
  char buf[20];
  // if removing char from beginining
  if (src == p) {
    strcat(buf, p + count);
  } else {
    strncpy(buf, src, index);
    strcat(buf, p + count);
  }
  memset(src, 0, strlen(src));
  strcpy(src, buf);
}

// Function which convert a number in a char array to a byte data type
byte stringToByte(char *src, int numBytes)
{
  // intermediate buffers used during conversions
  char charBuffer[4];

  memcpy(charBuffer, src, numBytes);

  // cast from char[] to int to byte
  return (byte)atoi(charBuffer);
}

// Function which determines amount of free SRAM
int freeRam ()
{
  char stack_dummy = 0;
  return &stack_dummy - sbrk(0);
}

Go Up