Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // General Library
- #include <Arduino.h>
- #include "binary.h"
- // Math operation
- #include <math.h>
- // I2C & TWI communication
- #include <Wire.h>
- #include "I2Cdev.h"
- // Serial connection
- #include <SoftwareSerial.h>
- // LiquidCrystal Display
- #include <hd44780.h>
- #include <hd44780ioClass/hd44780_I2Cexp.h>
- // 7 segment
- #include "LedControl.h"
- // Library for heart rate & oxymeter
- #include "MAX30100_new.h"
- // Library for RTC
- #include <MyRealTimeClock.h>
- // Library for accelerometer
- #include "MPU6050_6Axis_MotionApps20.h"
- // Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
- // is used in I2Cdev.h
- #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
- #include "Wire.h"
- #endif
- // Definiting constants
- #define aref_voltage 3.3
- // uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
- // quaternion components in a [w, x, y, z] format (not best for parsing
- // on a remote host such as Processing or something though)
- // #define OUTPUT_READABLE_QUATERNION
- // uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
- // pitch/roll angles (in degrees) calculated from the quaternions coming
- // from the FIFO. Note this also requires gravity vector calculations.
- // Also note that yaw/pitch/roll angles suffer from gimbal lock (for
- // more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
- #define OUTPUT_READABLE_YAWPITCHROLL
- // uncomment "OUTPUT_TEAPOT" if you want output that matches the
- // format used for the InvenSense teapot demo
- //#define OUTPUT_TEAPOT
- // MCU defaults
- #define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
- #define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
- bool blinkState = false; //Indicate activity state
- // MPU control/status vars
- bool dmpReady = false; // set true if DMP init was successful
- uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
- uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
- uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
- uint16_t fifoCount; // count of all bytes currently in FIFO
- uint8_t fifoBuffer[64]; // FIFO storage buffer
- // orientation/motion vars
- Quaternion q; // [w, x, y, z] quaternion container
- VectorInt16 aa; // [x, y, z] accel sensor measurements
- VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
- VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
- VectorFloat gravity; // [x, y, z] gravity vector
- float euler[3]; // [psi, theta, phi] Euler angle container
- float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
- // packet structure for InvenSense teapot demo
- uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
- // Sensor class objects
- MAX30100_new* pulseOxymeter;
- SoftwareSerial BTserial(8,9); // RX | TX
- hd44780_I2Cexp lcd;
- LedControl lc=LedControl(12,11,10,1);
- MyRealTimeClock myRTC(5, 6, 7); // Assign Digital Pins
- MPU6050 mpu;
- // Constants
- const int LCD_COLS = 16;
- const int LCD_ROWS = 2;
- const int buttonPin = 3;
- // Temperature Sensor
- int tempSensorPin = A0;
- // Sound Sensor
- int audioVal = 0;
- int soundSensorPin = A3;
- // Pulse Oxymeter
- int heartRate = 0;
- int oxSat = 0;
- // Button
- int buttonState = 0;
- // Common variable for temp and stretch
- int readIndex = 0; // the index of the current reading
- const int numReadings = 50; // averaging parameter for stretch and temp
- // Averaging temperature parameter details
- //const int numReadingsTemp = 10;
- int readingsTemp[numReadings]; // the readings from the analog input
- int averageTemp = 0; // the average
- int totalTemp = 0; // the running total
- // Averaging stretching sensor values
- //const int numReadingsStretch = 10;
- int readingsStretch[numReadings]; // the readings from the analog input
- int averageStretch = 0; // the average
- int totalStretch = 0; // the running total
- // Variables for accelerometer
- //float yaw = 0.0;
- //float pitch = 0.0;
- //float roll = 0.0;
- long yaw = 0.0;
- long pitch = 0.0;
- long roll = 0.0;
- //Averaging accelerometer data
- long yawAvg = 0.0;
- long pitchAvg = 0.0;
- long rollAvg = 0.0;
- long yawTtl = 0.0;
- long pitchTtl = 0.0;
- long rollTtl = 0.0;
- long yprCount = 0;
- // Timer settings for printing each second
- int interval = 1000;
- unsigned long previousMillis = 0;
- unsigned long currentMillis;
- int heartBeatNotDetected = 0;
- // disp heart boundary
- byte sf[8]= {B00000000,B00100100,B01011010,B10000001,B10000001,B01000010,B00100100,B00011000};
- // disp heart inside
- byte nf[8]={B00000000, B00100100,B01111110,B11111111,B11111111,B01111110,B00111100,B00011000};
- // ================================================================
- // === INTERRUPT DETECTION ROUTINE ===
- // ================================================================
- // ================================================================
- volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
- void dmpDataReady() {
- mpuInterrupt = true;
- }
- void setup()
- {
- // ================================================================
- // join I2C bus (I2Cdev library doesn't do this automatically)
- #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
- Wire.begin();
- Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
- #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
- Fastwire::setup(400, true);
- #endif
- // Serial monitor settings
- Wire.begin();
- Serial.begin(115200); // pulse oxymeter
- //Serial.begin(9600); //temperature sensor
- BTserial.begin(9600);
- //BTserial.begin(115200);
- while (!Serial); // wait for Leonardo enumeration, others continue immediately
- // initialize device
- Serial.println(F("Initializing I2C devices..."));
- mpu.initialize();
- pinMode(INTERRUPT_PIN, INPUT);
- // verify connection
- Serial.println(F("Testing device connections..."));
- Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
- // wait for ready
- Serial.println(F("\nSend any character to begin DMP programming and demo: "));
- /* Read for sensor from bluetooth of mobile
- while (Serial.available() && Serial.read()); // empty buffer
- while (!Serial.available()); // wait for data
- while (Serial.available() && Serial.read()); // empty buffer again
- */
- while (BTserial.available() && BTserial.read()); // empty buffer
- while (!BTserial.available()); // wait for data
- while (BTserial.available() && BTserial.read()); // empty buffer again
- //
- // load and configure the DMP
- // ================================================================
- Serial.println(F("Initializing DMP..."));
- devStatus = mpu.dmpInitialize();
- // supply your own gyro offsets here, scaled for min sensitivity
- mpu.setXGyroOffset(220);
- mpu.setYGyroOffset(76);
- mpu.setZGyroOffset(-85);
- mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
- // make sure it worked (returns 0 if so)
- if (devStatus == 0) {
- // turn on the DMP, now that it's ready
- Serial.println(F("Enabling DMP..."));
- mpu.setDMPEnabled(true);
- // enable Arduino interrupt detection
- Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
- attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
- mpuIntStatus = mpu.getIntStatus();
- // set our DMP Ready flag so the main loop() function knows it's okay to use it
- Serial.println(F("DMP ready! Waiting for first interrupt..."));
- dmpReady = true;
- // get expected DMP packet size for later comparison
- packetSize = mpu.dmpGetFIFOPacketSize();
- } else {
- // ERROR!
- // 1 = initial memory load failed
- // 2 = DMP configuration updates failed
- // (if it's going to break, usually the code will be 1)
- Serial.print(F("DMP Initialization failed (code "));
- Serial.print(devStatus);
- Serial.println(F(")"));
- }
- // configure LED for output
- pinMode(LED_PIN, OUTPUT);
- // Board settings
- analogReference(EXTERNAL);
- // Necessary printing
- Serial.println("Pulse oxymeter initialized!");
- // Oxymeter settings
- pulseOxymeter = new MAX30100_new();
- // Reset clock to a new time while needed
- //myRTC.setDS1302Time(00, 14, 17, 4, 10, 5, 2018);
- // LCD settings
- lc.shutdown(0,false);
- lc.setIntensity(0,8);
- lc.clearDisplay(0);
- int status;
- status = lcd.begin(LCD_COLS, LCD_ROWS);
- if(status) // non zero status means it was unsuccesful
- {
- status = -status; // convert negative status value to positive number
- // begin() failed so blink error code using the onboard LED if possible
- hd44780::fatalError(status); // does not return
- }
- Serial.println("LCD initialized!");
- // Temp sensor settings
- for (int thisReading = 0; thisReading < numReadings; thisReading++) {
- readingsTemp[thisReading] = 0;
- readingsStretch[thisReading] = 0;
- }
- Serial.println("Temp Sensor initialized!");
- // Button settings
- pinMode(buttonPin, INPUT);
- // setSyncProvider( requestSync); //set function to call when sync required
- //Serial.println("Waiting for sync message");
- //setTime(11,58,00,16,4,2018);
- }
- void drawEmptyHeart(){
- lc.setRow(0,0,sf[0]);
- lc.setRow(0,1,sf[1]);
- lc.setRow(0,2,sf[2]);
- lc.setRow(0,3,sf[3]);
- lc.setRow(0,4,sf[4]);
- lc.setRow(0,5,sf[5]);
- lc.setRow(0,6,sf[6]);
- lc.setRow(0,7,sf[7]);
- }
- void drawHeart(){
- // Display no heart
- lc.setRow(0,0,nf[0]);
- lc.setRow(0,1,nf[1]);
- lc.setRow(0,2,nf[2]);
- lc.setRow(0,3,nf[3]);
- lc.setRow(0,4,nf[4]);
- lc.setRow(0,5,nf[5]);
- lc.setRow(0,6,nf[6]);
- lc.setRow(0,7,nf[7]);
- delay(10);
- }
- void printTerminal(uint8_t hourVal,uint8_t minVal, uint8_t secVal, uint8_t hrVal, uint8_t oxSatVal, uint8_t tempVal, uint8_t stretchVal, uint8_t audVal, long yawVal, long pitVal, long rollVal) {
- Serial.print(hourVal); // Element 4
- Serial.print(":");
- Serial.print(minVal); // Element 5
- Serial.print(":");
- Serial.println(secVal);
- Serial.print("HR: ");
- Serial.print(hrVal);
- Serial.print("bpm / O2: ");
- Serial.print(oxSatVal);
- Serial.print("% / T: ");
- Serial.print(tempVal);
- Serial.print(" / Stretch: ");
- Serial.println(stretchVal);
- Serial.print("Audio: ");
- Serial.print(audVal);
- Serial.print(" / Y: ");
- Serial.print(yawVal);
- Serial.print(" / P: ");
- Serial.print(pitVal);
- Serial.print(" / R: ");
- Serial.println(rollVal);
- }
- void printBT(uint8_t hourVal,uint8_t minVal, uint8_t secVal, uint8_t hrVal, uint8_t oxSatVal, uint8_t tempVal, uint8_t stretchVal, uint8_t audVal, long yawVal, long pitVal, long rollVal) {
- BTserial.write(Serial.read());
- BTserial.print("Time: /");
- BTserial.print(hourVal); // Element 4
- BTserial.print(":");
- BTserial.print(minVal); // Element 5
- BTserial.print(":");
- BTserial.print(secVal);
- BTserial.print("/\t");
- BTserial.print("HR: /");
- BTserial.print(hrVal);
- BTserial.print("/\tO2: /");
- BTserial.print(oxSatVal);
- BTserial.print("/% \tT: /");
- BTserial.print(tempVal);
- BTserial.print("/C\t Y:/");
- BTserial.print(yawVal);
- BTserial.print("/\t P:/");
- BTserial.print(pitVal);
- BTserial.print("/\t R:/");
- BTserial.print(rollVal);
- BTserial.print("/\t Aud:/");
- BTserial.print(audVal);
- BTserial.print("/\t Str:/");
- BTserial.print(stretchVal);
- BTserial.println("/");
- }
- void printLCD(uint8_t hourVal, uint8_t minVal, uint8_t tempVal, uint8_t hrVal, uint8_t oxSatVal) {
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print(hourVal); // Element 4
- lcd.print(":");
- lcd.print(minVal); // Element 5
- lcd.print(" / T: ");
- lcd.print(tempVal);
- lcd.print("C");
- lcd.setCursor(0,1);
- lcd.print("HR: ");
- lcd.print(hrVal);
- lcd.print("b / O2: ");
- lcd.print(oxSatVal);
- lcd.print("%");
- }
- void loop()
- {
- // ================================================================
- // if programming failed, don't try to do anything
- if (!dmpReady) return;
- // wait for MPU interrupt or extra packet(s) available
- while (!mpuInterrupt && fifoCount < packetSize) {
- }
- //while (!mpuInterrupt);
- // Update time
- myRTC.updateTime();
- // Default behavior
- drawEmptyHeart();
- // Button logic
- buttonState = digitalRead(buttonPin);
- // Sound sensor logic
- audioVal = analogRead(soundSensorPin);
- // Temp sensor reading
- int readingTemp = analogRead(tempSensorPin);
- //Reading Stretch Sensor
- int readingStretch = analogRead(A1);
- float tempVoltage = readingTemp * aref_voltage;
- // voltage /= 1024.0;
- // float temperatureC = (voltage - 0.5) * 100 ;
- // Averaging Temperature Results
- totalTemp = totalTemp - readingsTemp[readIndex];
- totalStretch = totalStretch - readingsStretch[readIndex];
- readingsTemp[readIndex] = tempVoltage;
- readingsStretch[readIndex] = readingStretch;
- totalTemp = totalTemp + readingsTemp[readIndex];
- totalStretch = totalStretch + readingsStretch[readIndex];
- readIndex = readIndex + 1;
- if (readIndex >= numReadings) {
- readIndex = 0;
- }
- averageTemp = totalTemp / numReadings;
- averageStretch = totalStretch / numReadings;
- // ================================================================
- // MCU Accelerometer
- // reset interrupt flag and get INT_STATUS byte
- mpuInterrupt = false;
- mpuIntStatus = mpu.getIntStatus();
- // get current FIFO count
- fifoCount = mpu.getFIFOCount();
- // check for overflow (this should never happen unless our code is too inefficient)
- // ================================================================
- mpu.resetFIFO();
- if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
- // reset so we can continue cleanly
- mpu.resetFIFO();
- Serial.println(F("FIFO overflow!"));
- // otherwise, check for DMP data ready interrupt (this should happen frequently)
- } else if (mpuIntStatus & 0x02) {
- // wait for correct available data length, should be a VERY short wait
- while (fifoCount < packetSize) {
- fifoCount = mpu.getFIFOCount();
- }
- // read a packet from FIFO
- mpu.getFIFOBytes(fifoBuffer, packetSize);
- // ================================================================
- //mpu.resetFIFO();
- // track FIFO count here in case there is > 1 packet available
- // (this lets us immediately read more without waiting for an interrupt)
- fifoCount -= packetSize;
- mpu.dmpGetQuaternion(&q, fifoBuffer);
- mpu.dmpGetGravity(&gravity, &q);
- mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
- yaw = ypr[0] * 180/M_PI;
- pitch = ypr[1] * 180/M_PI;
- roll = ypr[2] * 180/M_PI;
- // blink LED to indicate activity
- blinkState = !blinkState;
- digitalWrite(LED_PIN, blinkState);
- //delay(50);
- mpu.resetFIFO();
- }
- // Pulse oxymeter logic
- pulseoxymeter_t result = pulseOxymeter->update();
- if(result.pulseDetected == true) {
- drawHeart();
- // Receving Sensor Values
- heartRate = result.heartBPM;
- } else {
- heartBeatNotDetected = heartBeatNotDetected + 1;
- if (heartBeatNotDetected >= 500) {
- heartRate = 0;
- oxSat = 0;
- heartBeatNotDetected = 0;
- }
- }
- // Averaging Yaw, Pitch, Roll
- yawTtl = yawTtl + yaw;
- pitchTtl = pitchTtl + pitch;
- rollTtl = rollTtl + roll;
- yprCount = yprCount + 1;
- currentMillis = millis();
- if((unsigned long)(currentMillis - previousMillis) >= interval) {
- yawAvg = yawTtl / yprCount;
- pitchAvg = pitchTtl / yprCount;
- rollAvg = rollTtl / yprCount;
- printTerminal(myRTC.hours, myRTC.minutes, myRTC.seconds, heartRate, oxSat, averageTemp, averageStretch, audioVal, yawAvg, pitchAvg, rollAvg);
- printBT(myRTC.hours, myRTC.minutes, myRTC.seconds, heartRate, oxSat, averageTemp, averageStretch, audioVal, yawAvg, pitchAvg, rollAvg);
- printLCD(myRTC.hours, myRTC.minutes,averageTemp, heartRate, oxSat);
- previousMillis = currentMillis;
- yprCount = 0;
- yawTtl = 0;
- pitchTtl = 0;
- rollTtl = 0;
- yawAvg = 0;
- pitchAvg = 0;
- rollAvg = 0;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment