Heart rate sensor with arduino nano

Hello everyone, I have an Arduino Nano with the old bootloader (ATmega328P), and I'm encountering an issue when attempting to print data to the serial monitor. Specifically, while it does display the rate, there are instances where it sends data at random intervals. Could you please assist me with resolving this issue?

You'll have to post your code so folks can take a look. Please don't forget to use code tags.

Ok. Here is the code

int pulsePin = A0; // Define pulse sensor pin
int blinkPin = 13; // Define LED indicator pin

volatile int BPM; // Variable to store heart rate (beats per minute)
volatile int Signal; // Variable to store raw analog signal from pulse sensor
volatile int IBI = 600; // Initial value for time interval between beats
volatile boolean Pulse = false; // Flag to indicate pulse detection
volatile boolean QS = false; // Flag to indicate Quantified Self event

static boolean serialVisual = true; // Flag to enable ASCII visual representation

volatile int rate[10]; // Array to store last ten IBI values
volatile unsigned long sampleCounter = 0; // Counter to track time
volatile unsigned long lastBeatTime = 0; // Time of last beat
volatile int P = 512; // Peak value of pulse waveform
volatile int T = 512; // Trough value of pulse waveform
volatile int thresh = 525; // Threshold to find instant of heart beat
volatile int amp = 100; // Amplitude of pulse waveform
volatile boolean firstBeat = true; // Flag to indicate first beat
volatile boolean secondBeat = false; // Flag to indicate second beat

void setup() {
  pinMode(blinkPin, OUTPUT); // Set LED pin as output
  Serial.begin(57600); // Set baud rate to 57600 for serial communication
  interruptSetup(); // Setup interrupt for pulse sensor
}

void loop() {
  serialOutput(); // Output data to serial monitor

  if (QS == true) { // If heart beat detected
    serialOutputWhenBeatHappens(); // Output heart beat data
    QS = false; // Reset Quantified Self flag
  }

  delay(20); // Delay for stability
}

void interruptSetup() {
  TCCR2A = 0x02; // Configure Timer2 for CTC mode
  TCCR2B = 0x06; // Set prescaler to 256
  OCR2A = 0X7C; // Set top value for 500Hz sample rate
  TIMSK2 = 0x02; // Enable interrupt on match between Timer2 and OCR2A
  sei(); // Enable global interrupts
}

void serialOutput() {
  if (serialVisual == true) { // If ASCII visual representation enabled
    arduinoSerialMonitorVisual('-', Signal); // Output visual representation
  } else {
    sendDataToSerial('S', Signal); // Otherwise, send raw data
  }
}

void serialOutputWhenBeatHappens() {
  if (serialVisual == true) { // If ASCII visual representation enabled
    Serial.print(" Heart-Beat Found "); // Print heart beat message
    Serial.print("BPM: "); // Print heart rate label
    Serial.println(BPM); // Print heart rate value
  } else {
    sendDataToSerial('B', BPM); // Otherwise, send heart rate data
    sendDataToSerial('Q', IBI); // Also, send time between beats data
  }
}

void arduinoSerialMonitorVisual(char symbol, int data) {
  const int sensorMin = 0; // Minimum sensor value
  const int sensorMax = 1024; // Maximum sensor value
  int sensorReading = data; // Current sensor reading
  int range = map(sensorReading, sensorMin, sensorMax, 0, 11); // Map sensor reading to range of 0-11
  // Further actions based on mapped range can be implemented here
}

void sendDataToSerial(char symbol, int data) {
  Serial.print(symbol); // Send symbol prefix
  Serial.println(data); // Send data value
}

ISR(TIMER2_COMPA_vect) { // Interrupt service routine for Timer2
  cli(); // Disable interrupts

  Signal = analogRead(pulsePin); // Read analog signal from pulse sensor
  sampleCounter += 2; // Increment sample counter
  int N = sampleCounter - lastBeatTime; // Calculate time since last beat

  // Check for peak and trough of pulse waveform
  if (Signal < thresh && N > (IBI / 5) * 3) {
    if (Signal < T) {
      T = Signal; // Update trough value
    }
  }

  if (Signal > thresh && Signal > P) {
    P = Signal; // Update peak value
  }

  // Look for heartbeat signal surge
  if (N > 250) {
    if ((Signal > thresh) && (Pulse == false) && (N > (IBI / 5) * 3)) {
      Pulse = true; // Set pulse detection flag
      digitalWrite(blinkPin, HIGH); // Turn on LED indicator
      IBI = sampleCounter - lastBeatTime; // Calculate time interval between beats
      lastBeatTime = sampleCounter; // Update time of last beat

      if (secondBeat) {
        secondBeat = false; // Clear secondBeat flag
        for (int i = 0; i <= 9; i++) {
          rate[i] = IBI; // Seed running total with latest IBI value
        }
      }

      if (firstBeat) {
        firstBeat = false; // Clear firstBeat flag
        secondBeat = true; // Set secondBeat flag
        sei(); // Enable interrupts
        return; // Exit ISR
      }

      word runningTotal = 0; // Variable to hold running total of last 10 IBI values

      // Shift data in rate array and add up 9 oldest IBI values
      for (int i = 0; i <= 8; i++) {
        rate[i] = rate[i + 1]; // Shift data
        runningTotal += rate[i]; // Add up values
      }

      rate[9] = IBI; // Add latest IBI value
      runningTotal += rate[9]; // Add latest IBI value to runningTotal
      runningTotal /= 10; // Calculate average of last 10 IBI values
      BPM = 60000 / runningTotal; // Calculate heart rate
      QS = true; // Set Quantified Self flag
    }
  }

  // Check for heartbeat signal decline
  if (Signal < thresh && Pulse == true) {
    digitalWrite(blinkPin, LOW); // Turn off LED indicator
    Pulse = false

I think maybe you've got too much going on in the ISR. I was under the impression that ISRs had to be very quick, set a flag and do all the other stuff in the main loop.
Maybe someone else who is more expert than me can weigh in on how much you can get away with in an ISR, though.

2 Likes

Now I can not recieve data xd

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.