Linking LED Matrix to Pulse Sensor???

Hi, so I have an Adafruit 8x8 LED Matrix (the 0.8") one, an Arduino Uno and a Pulse sensor from pulsesensor.com
When the IBI varies too much, I want it to use the LED Matrix to output the text I have placed.
This is the code placed in the Interrupt part of the Pulse sensor sequence:

 if (IBI - rate[8] <= -90){              //when the difference between the most recent IBI and the one before IBI is less than -90
        delay(1000000);
        if (IBI - rate[8] <= -90) {
          delay(100000);
          if (IBI - rate[8] <= -90) {
              //do something
          }
          else {      
     
          }
        }
        else {   
     
        }
      }
      else {
    
      }
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                       
  }

However, when I try combining the two together, the LED Matrix just stops and glitches out and the pulse sensor doesn't work at all.
This is my attempt at the main file:

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

//  Variables
int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13;                // pin to blink led at each beat
int fadePin = 5;                  // pin to do fancy classy fading blink at each beat
int fadeRate = 0;                 // used to fade LED on with PWM on fadePin


// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded! 
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat". 
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.

// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialVisual = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse 


void setup(){
  
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS 
   // IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE, 
   // UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN
//   analogReference(EXTERNAL);   
 matrix.begin(0x70);  // pass in the address
 
}



//  Where the Magic Happens
void loop(){
  matrix.clear();
    serialOutput() ;       
    
  if (QS == true){     // A Heartbeat Was Found
                       // BPM and IBI have been Determined
                       // Quantified Self "QS" true when arduino finds a heartbeat
        
        serialOutputWhenBeatHappens();   // A Beat Happened, Output that to serial.     
        QS = false;                      // reset the Quantified Self flag for next time    
  }
     

}

This is what I have inputted into the Interrupt ino file that depends on the main file (the one above):

      // keep a running total of the last 10 IBI values
      word 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 = true;                              // set Quantified Self flag 

      if (IBI - rate[8] <= -90){              //when the difference between the most recent IBI and the one before IBI is less than -90
        delay(1000000);
        if (IBI - rate[8] <= -90) {
          delay(100000);
          if (IBI - rate[8] <= -90) {
              matrix.setBrightness(3);
  matrix.setTextSize(1);
  matrix.setTextWrap(false);  // we dont want text to wrap so it scrolls nicely
  matrix.setTextColor(LED_ON);
  for (int8_t x=0; x>=-45; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("In 2 3 4");
    matrix.writeDisplay();
    delay(100);
  }
  for (int8_t x=9; x>=-90; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("Hold 2 3 4 5 6 7");
    matrix.writeDisplay();
    delay(100);
  }
  for (int8_t x=16; x>=-103; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("Out 2 3 4 5 6 7 8");
    matrix.writeDisplay();
    delay(100);
  }
  matrix.setRotation(0);
          }
          else {      
     matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
          }
        }
        else {   
     matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
        }
      }
      else {
    matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
      }
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                       
  }

  if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over
//    digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
    Pulse = false;                         // 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 (N > 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 = true;                      // set these to avoid noise
    secondBeat = false;                    // when we get the heartbeat back
  }

  sei();                                   // enable interrupts when youre done!
}// end isr

If you could help that would be so great!!!

This is my attempt at the main file:

It appears to be incomplete.

 if (IBI - rate[8] <= -90){              //when the difference between the most recent IBI and the one before IBI is less than -90
        delay(1000000);

Then wait for 1000 seconds, or 16 + minutes. WTF?

        if (IBI - rate[8] <= -90) {
          delay(100000);

If it is still different by more than -90, wait some more.

This is what I have inputted into the Interrupt ino

And all that crap is in an interrupt service routine. Dream on.

christychan14:
This is the code placed in the Interrupt part of the Pulse sensor sequence:

I see two possibilities for you to get out of trouble:

1.) AVOID interrupt programming as you are not able to do so.
Poll and evaluate the sensor values in certain time slices, then control your output to Serial, LED etc. as needed!

Or:
2.) Learn about the BASICS OF INTERRUPT PROGRAMMING and avoid such mistakes like trying to put a "delay()" into an interrupt handling routine!

jurs:
I see two possibilities for you to get out of trouble:

1.) AVOID interrupt programming as you are not able to do so.
Poll and evaluate the sensor values in certain time slices, then control your output to Serial, LED etc. as needed!

Or:
2.) Learn about the BASICS OF INTERRUPT PROGRAMMING and avoid such mistakes like trying to put a "delay()" into an interrupt handling routine!

How can I enable the IBI sequence to happen in the main file then? Thanks

How can I enable the IBI sequence to happen in the main file then?

You can't. What you can do is explain what you are trying to accomplish. Whatever it is, you need to do THAT in loop(), not in the interrupt service routine.

PaulS:
You can't. What you can do is explain what you are trying to accomplish. Whatever it is, you need to do THAT in loop(), not in the interrupt service routine.

Ok so I've inputted the stuff you guys told me to do into the main doc not the interrupt (sorry for annoying you guys) but it is now telling me "rate" is not declared in the scope, so how do I declare it?
Thank you guys so much.

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();

//  Variables
int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13;                // pin to blink led at each beat
int fadePin = 5;                  // pin to do fancy classy fading blink at each beat
int fadeRate = 0;                 // used to fade LED on with PWM on fadePin


// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded! 
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat". 
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.

// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialVisual = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse 


void setup(){
  
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS 
   // IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE, 
   // UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN
//   analogReference(EXTERNAL);   
 matrix.begin(0x70);  // pass in the address
 
}

static const uint8_t PROGMEM
  smile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
  neutral_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10111101,
    B10000001,
    B01000010,
    B00111100 },
  frown_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10011001,
    B10100101,
    B01000010,
    B00111100 };

//  Where the Magic Happens
void loop(){
  matrix.clear();
    serialOutput() ;       
    
  if (QS == true){     // A Heartbeat Was Found
                       // BPM and IBI have been Determined
                       // Quantified Self "QS" true when arduino finds a heartbeat
        
        serialOutputWhenBeatHappens();   // A Beat Happened, Output that to serial.     
        QS = false;                      // reset the Quantified Self flag for next time    

    if (IBI - rate[8] <= -90){              //when the difference between the most recent IBI and the one before IBI is less than -90
        delay(1000);
        if (IBI - rate[8] <= -90) {
          delay(1000);
          if (IBI - rate[8] <= -90) {
              matrix.setBrightness(3);
  matrix.setTextSize(1);
  matrix.setTextWrap(false);  // we dont want text to wrap so it scrolls nicely
  matrix.setTextColor(LED_ON);
  for (int8_t x=0; x>=-45; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("In 2 3 4");
    matrix.writeDisplay();
    delay(100);
  }
  for (int8_t x=9; x>=-90; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("Hold 2 3 4 5 6 7");
    matrix.writeDisplay();
    delay(100);
  }
  for (int8_t x=16; x>=-103; x--) {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print("Out 2 3 4 5 6 7 8");
    matrix.writeDisplay();
    delay(100);
  }
  matrix.setRotation(0);
          }
          else {      
     matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
          }
        }
        else {   
     matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
        }
      }
      else {
    matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
  matrix.writeDisplay();
  delay(500);
      }
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                       
  }
  }
     

}

christychan14:
so how do I declare it?

If "rate" compiled before you did the changes: Where was "rate" declared before you removed it from the program?

jurs:
If "rate" compiled before you did the changes: Where was "rate" declared before you removed it from the program?

In the interrupt sequence, I think in here:

volatile int rate[10];                    // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
volatile unsigned long lastBeatTime = 0;           // used to find IBI
volatile int P =512;                      // used to find peak in pulse wave, seeded
volatile int T = 512;                     // used to find trough in pulse wave, seeded
volatile int thresh = 525;                // used to find instant moment of heart beat, seeded
volatile int amp = 100;                   // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM


void interruptSetup(){     
  // Initializes Timer2 to throw an interrupt every 2mS.
  TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
  TCCR2B = 0x06;     // DON'T FORCE COMPARE, 256 PRESCALER 
  OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
  TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
  sei();             // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
} 


// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE. 
// Timer 2 makes sure that we take a reading every 2 miliseconds
ISR(TIMER2_COMPA_vect){                         // triggered when Timer2 counts to 124
  cli();                                      // disable interrupts while we do this
  Signal = analogRead(pulsePin);              // read the Pulse Sensor 
  sampleCounter += 2;                         // keep track of the time in mS with this variable
  int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

    //  find the peak and trough of the pulse wave
  if(Signal < thresh && N > (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 (N > 250){                                   // avoid high frequency noise
    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){        
      Pulse = true;                               // set the Pulse flag when we think there is a pulse
//      digitalWrite(blinkPin,HIGH);                // 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 = false;                  // 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 = false;                   // clear firstBeat flag
        secondBeat = true;                   // 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
      word 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 = true;                              // set Quantified Self flag 
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
      
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }                       
  }
                         
  

  if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over
//    digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
    Pulse = false;                         // 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 (N > 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 = true;                      // set these to avoid noise
    secondBeat = false;                    // when we get the heartbeat back
  }

  sei();                                   // enable interrupts when youre done!
}// end isr

christychan14:
In the interrupt sequence, I think in here:

So you removed variable declarations from the source code intentionally and now you are wondering why the compiler complains about missing declarations?

Hint: In every Arduino/C/C++ program you can only use variables and arrays which have been declared.

In the last code you showed, declaration was at the beginning of the code (not in the interrupt handler):

volatile int rate[10];                    // array to hold last ten IBI values

Why did you remove that?

jurs:
So you removed variable declarations from the source code intentionally and now you are wondering why the compiler complains about missing declarations?

Hint: In every Arduino/C/C++ program you can only use variables and arrays which have been declared.

In the last code you showed, declaration was at the beginning of the code (not in the interrupt handler):

volatile int rate[10];                    // array to hold last ten IBI values

Why did you remove that?

Yes that volatile int rate[10] is at the top of the interrupt handler........

Let's put aside the issue of HOW to accomplish the result you want. You need to describe WHAT you are trying to do, in English, not in code.

PaulS:
Let's put aside the issue of HOW to accomplish the result you want. You need to describe WHAT you are trying to do, in English, not in code.

Ok, so I want the LED Matrix to output the words "In 2 3 4" followed by "Hold 2 3 4 5 6 7" followed by "Out 2 3 4 5 6 7 8" WHEN the difference between the current IBI and the last IBI (rate [8]) is less than -90 AND it happens 3 times over a course of 2000 ms.
(Complicated I know, sorry)

WHEN the difference between the current IBI and the last IBI (rate [8]) is less than -90

I said to describe what you are trying to accomplish NOT using code. You need to illustrate that you know what IBI is holding and that you understand what rate[8] is holding.

It is not clear to me that you do understand.

Just tell me what the project is supposed to do. I don't care, in the slightest, how it does it. Pretend you are trying to sell me the device.

PaulS:
I said to describe what you are trying to accomplish NOT using code. You need to illustrate that you know what IBI is holding and that you understand what rate[8] is holding.

It is not clear to me that you do understand.

Just tell me what the project is supposed to do. I don't care, in the slightest, how it does it. Pretend you are trying to sell me the device.

Yes. Sorry.
The device is supposed to detect when you are overreacting or feeling overly emotional and tell you to breathe.
It detects this through heart rate variability which is the difference between the last inter beat interval and the current one.

In addition, when I placed the change in IBI stuff in the Interrupt sequence, it worked perfectly, but when I added the LED Matrix, everything got messed up.

It detects this through heart rate variability which is the difference between the last inter beat interval and the current one.

Then, the simplest solution is to create a new global volatile variable, CBI, and assign it a value in the ISR, at the same time rate[8] gets assigned a value.

PaulS:
Then, the simplest solution is to create a new global volatile variable, CBI, and assign it a value in the ISR, at the same time rate[8] gets assigned a value.

Ok, I'm so sorry for my dumbness, but I know how to create the new global volatile variable, but how do I assign it a value in the ISR at the same time that rate[8] gets assigned a value?
Basically.... I'm so dumb and do not understand how to do what you just said.
I'm really really sorry (you must be so fed up with right now)

but how do I assign it a value in the ISR at the same time that rate[8] gets assigned a value?

      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
      }

      CBI = rate[8]; // <----- Add this line
      rate[9] = IBI;                          // add the latest IBI to the rate array

Actually, the variable really should be called PBI (for previous), not CBI (for current).

PaulS:
Actually, the variable really should be called PBI (for previous), not CBI (for current).

Brilliant! It works perfectly, but how do i get the LED Matrix sequence to continue even if it says it's normal????

also, the serial monitor sometimes just pauses and then sets off the whole LED Matrix sequence. How do i stop this? Thank you so much!

but how do i get the LED Matrix sequence to continue even if it says it's normal?

You made some changes to some code. You didn't post the changed code.

You posted a question that lacks context. I do not know what you mean by "the LED Matrix sequence" or how it is supposed to "continue", nor do I know what "it" is or how it might say that something, whatever another mysterious "it" is, is "normal".

I really don't think that it is going to be possible to answer that question.

also, the serial monitor sometimes just pauses and then sets off the whole LED Matrix sequence.

Now, that seems highly unlikely. The Serial Monitor application is simply displaying what comes in from the serial port, and maybe sending some data to the serial port. It can not make the Arduino do anything. It certainly can not make the LED Matrix attached to the Arduino do anything.

How do i stop this?

Nothing to stop. What you describe is not possible, so it isn't happening (the way you describe).

It IS possible that the Arduino is not sending data to the serial port at a consistent rate, and that there is something that it is doing that "sets off the whole LED Matrix sequence". But that would be entirely up to your code, which you didn't post.