// project: interactive heart rate monitor with audio //================================================================================ // lcd shield libraries #include #include #include #include // waveshield libraries #include #include #include #include "WaveUtil.h" #include "WaveHC.h" // objects for audio SdReader card; // This object holds the information for the card FatVolume vol; // This holds the information for the partition on the card FatReader root; // This holds the information for the filesystem on the card FatReader f; // This holds the information for the file we're play WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time #define DEBOUNCE 100 // button debouncer, may not be needed //================================================================================ // adapted from Adafruit Waveshield website // methods for debugging void sdErrorCheck(void) // checks the SD card { if (!card.errorCode()) return; putstring("\n\rSD I/O error: "); Serial.print(card.errorCode(), HEX); putstring(", "); Serial.println(card.errorData(), HEX); while(1); } // adapted from Adafruit rgb lcd shield website // The rgb lcd shield uses the I2C SCL and SDA pins. On classic Arduinos // this is Analog 4 and 5 so you can't use those for analogRead() anymore // However, you can connect other I2C sensors to the I2C bus and share // the I2C bus. Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield(); // These #defines make it easy to set the backlight color #define RED 0x1 #define YELLOW 0x3 #define GREEN 0x2 #define TEAL 0x6 #define BLUE 0x4 #define VIOLET 0x5 #define WHITE 0x7 //================================================================================ // PULSE SENSOR CODE: adapted from Pulse Sensor website for this project /* >> Pulse Sensor Amped 1.2 << This code is for Pulse Sensor Amped by Joel Murphy and Yury Gitman www.pulsesensor.com >>> Pulse Sensor purple wire goes to Analog Pin 0 <<< Pulse Sensor sample aquisition and processing happens in the background via Timer 2 interrupt. 2mS sample rate. PWM on pins 3 and 11 will not work when using this code, because we are using Timer 2! The following variables are automatically updated: Signal : int that holds the analog signal data straight from the sensor. updated every 2mS. IBI : int that holds the time interval between beats. 2mS resolution. BPM : int that holds the heart rate value, derived every beat, from averaging previous 10 IBI values. QS : boolean that is made true whenever Pulse is found and BPM is updated. User must reset. Pulse : boolean that is true when a heartbeat is sensed then false in time with pin13 LED going out. */ // VARIABLES int pulsePin = 2; // Pulse Sensor purple wire connected to analog pin 2 (rgb lcd shield) int blinkPin = 6; // pin to blink led at each beat int fadeRate = 0; int heartvals[4]; int h = 0; // these variables are volatile because they are used during the interrupt service routine! volatile int BPM; // used to hold the pulse rate volatile int Signal; // holds the incoming raw data volatile int IBI = 600; // holds the time between beats, must be seeded! volatile boolean Pulse = false; // true when pulse wave is high, false when it's low volatile boolean QS = false; // becomes true when Arduoino finds a beat. //================================================================================ void setup() { pinMode( blinkPin, OUTPUT ); // pin that will blink to your heartbeat! // Set the output pins for the DAC control. This pins are defined in the library pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); // enable pull-up resistors on switch pins (analog inputs) digitalWrite(14, HIGH); digitalWrite(15, HIGH); digitalWrite(16, HIGH); digitalWrite(17, HIGH); digitalWrite(18, HIGH); digitalWrite(19, HIGH); Serial.begin( 9600 ); // debugging methods from waveshield website // if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you if (!card.init()) { //play with 8 MHz spi (default faster!) putstring_nl("Card init. failed!"); // Something went wrong, lets print out why sdErrorCheck(); while(1); // then 'halt' - do nothing! } // enable optimize read - some cards may timeout. Disable if you're having problems card.partialBlockRead(true); // Now we will look for a FAT partition! uint8_t part; for (part = 0; part < 5; part++) { // we have up to 5 slots to look in if (vol.init(card, part)) break; // we found one, lets bail } if (part == 5) { // if we ended up not finding one :( putstring_nl("No valid FAT partition!"); sdErrorCheck(); // Something went wrong, lets print out why while(1); // then 'halt' - do nothing! } // Lets tell the user about what we found putstring("Using partition "); Serial.print(part, DEC); putstring(", type is FAT"); Serial.println(vol.fatType(),DEC); // FAT16 or FAT32? // Try to open the root directory if (!root.openRoot(vol)) { putstring_nl("Can't open root dir!"); // Something went wrong, while(1); // then 'halt' - do nothing! } // secondary file with code for the Pulse Sensor interruptSetup(); // sets up to read Pulse Sensor signal every 2mS // UN-COMMENT THE NEXT LINE IF YOU ARE POWERING The Pulse Sensor AT LOW VOLTAGE, // AND APPLY THAT VOLTAGE TO THE A-REF PIN //analogReference(EXTERNAL); // set up for LCD lcd.begin( 16, 2 ); lcd.setBacklight( RED ); lcd.setCursor( 0, 0 ); lcd.print( "Welcome to your" ); lcd.setCursor( 0, 1 ); lcd.print( "Arduino HRM!" ); playcomplete("intro.wav"); // lcd.clear(); } // END OF VOID SETUP uint8_t i=0; //================================================================================ void loop() { uint8_t buttons = lcd.readButtons(); if ( buttons ) { lcd.clear(); lcd.setCursor( 0, 0 ); if ( buttons & BUTTON_UP ) { heartRate(); } if ( buttons & BUTTON_LEFT ) { playcomplete( "readings.wav" ); lcd.setCursor( 0, 0 ); lcd.print( "Last 4 readings: " ); lcd.setCursor( 0, 1 ); int i; for ( i=0; i<4; i++ ) { lcd.println( heartvals[i] ); } } if ( buttons & BUTTON_RIGHT ) { int randNumber = 0; randNumber = random( 1, 10 ); if ( randNumber == 1 ) { playcomplete("1.wav"); } if ( randNumber == 2 ) { playcomplete("2.wav"); } if ( randNumber == 3 ) { playcomplete("3.wav"); } if ( randNumber == 4 ) { playcomplete("4.wav"); } if ( randNumber == 5 ) { playcomplete("5.wav"); } if ( randNumber == 6 ) { playcomplete("6.wav"); } if ( randNumber == 7 ) { playcomplete("7.wav"); } if ( randNumber == 8 ) { playcomplete("8.wav"); } if ( randNumber == 9 ) { playcomplete("9.wav"); } if ( randNumber == 10 ) { playcomplete("10.wav"); } } if ( buttons & BUTTON_DOWN ) { averageH(); } if ( buttons & BUTTON_SELECT ) { lcd.print( "Select" ); playcomplete( "select.wav" ); } } } // END OF VOID LOOP //================================================================================ // methods needed for playing .wav files // adapted from waveshield website // Plays a full file from beginning to end with no pause. void playcomplete(char *name) { // call our helper to find and play this name playfile(name); while (wave.isplaying) { // do nothing while its playing } // now its done playing } void playfile(char *name) { // see if the wave object is currently doing something if (wave.isplaying) {// already playing something, so stop it! wave.stop(); // stop it } // look in the root directory and open the file if (!f.open(root, name)) { putstring("Couldn't open file "); Serial.print(name); return; } // OK read the file and turn it into a wave object if (!wave.create(f)) { putstring_nl("Not a valid WAV"); return; } // ok time to play! start playback wave.play(); } //================================================================================ // a method called to read and display BPM on lcd on UP button press void heartRate() { int x = 10; while ( x != 0 ) { if ( QS == true ){ // Quantified Self flag is true when arduino finds a heartbeat fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse lcd.setCursor( 0, 0 ); lcd.print( "Heart rate: " ); lcd.setCursor( 12, 0 ); lcd.println( BPM ); lcd.setCursor( 0, 1 ); lcd.print( "You are alive!" ); delay( 500 ); QS = false; // reset the Quantified Self flag for next time x--; } } heartvals[h] = BPM ; if ( h < 4 ) { h++; } else if ( h == 4 ) { h = 0; heartvals[h] = BPM ; } int i; for ( i=0; i<4; i++ ) { Serial.println( heartvals[i]); } playcomplete( "finished.wav" ); } // method to calculate the average of the 4 values in heartvals void averageH() { int average = 0; if ( heartvals[3] == 0 ) { lcd.setCursor( 4, 0 ); lcd.print( "Error..." ); lcd.setCursor( 0, 1 ); lcd.print( "4 values needed" ); } else { playcomplete( "average.wav" ); average = mean( heartvals, 4 ); lcd.setCursor( 0, 0 ); lcd.print( "Average: " ); lcd.setCursor( 9, 0 ); lcd.print( average ); } } //================================================================================