|
| 1 | +/* |
| 2 | + Optical SP02 Detection (SPK Algorithm) using the MAX30105 Breakout |
| 3 | + By: Nathan Seidle @ SparkFun Electronics |
| 4 | + Date: October 19th, 2016 |
| 5 | + https://github.com/sparkfun/MAX30105_Breakout |
| 6 | +
|
| 7 | + This demo shows heart rate and SPO2 levels. |
| 8 | +
|
| 9 | + It is best to attach the sensor to your finger using a rubber band or other tightening |
| 10 | + device. Humans are generally bad at applying constant pressure to a thing. When you |
| 11 | + press your finger against the sensor it varies enough to cause the blood in your |
| 12 | + finger to flow differently which causes the sensor readings to go wonky. |
| 13 | +
|
| 14 | + This example is based on MAXREFDES117 and RD117_LILYPAD.ino from Maxim. Their example |
| 15 | + was modified to work with the SparkFun MAX30105 library and to compile under Arduino 1.6.11 |
| 16 | + Please see license file for more info. |
| 17 | +
|
| 18 | + Hardware Connections (Breakoutboard to Arduino): |
| 19 | + -5V = 5V (3.3V is allowed) |
| 20 | + -GND = GND |
| 21 | + -SDA = A4 (or SDA) |
| 22 | + -SCL = A5 (or SCL) |
| 23 | + -INT = Not connected |
| 24 | + |
| 25 | + The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend powering the board with 5V |
| 26 | + but it will also run at 3.3V. |
| 27 | +*/ |
| 28 | + |
| 29 | +#include <Wire.h> |
| 30 | +#include "MAX30105.h" |
| 31 | +#include "spo2_algorithm.h" |
| 32 | + |
| 33 | +MAX30105 particleSensor; |
| 34 | + |
| 35 | +#define MAX_BRIGHTNESS 255 |
| 36 | + |
| 37 | +//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format |
| 38 | +//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data. |
| 39 | +uint16_t irBuffer[100]; //infrared LED sensor data |
| 40 | +uint16_t redBuffer[100]; //red LED sensor data |
| 41 | + |
| 42 | +int32_t bufferLength; //data length |
| 43 | +int32_t spo2; //SPO2 value |
| 44 | +int8_t validSPO2; //indicator to show if the SPO2 calculation is valid |
| 45 | +int32_t heartRate; //heart rate value |
| 46 | +int8_t validHeartRate; //indicator to show if the heart rate calculation is valid |
| 47 | + |
| 48 | +byte pulseLED = 11; //Must be on PWM pin |
| 49 | +byte readLED = 13; //Blinks with each data read |
| 50 | + |
| 51 | +void setup() |
| 52 | +{ |
| 53 | + Serial.begin(115200); // initialize serial communication at 115200 bits per second: |
| 54 | + |
| 55 | + pinMode(pulseLED, OUTPUT); |
| 56 | + pinMode(readLED, OUTPUT); |
| 57 | + |
| 58 | + // Initialize sensor |
| 59 | + if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed |
| 60 | + { |
| 61 | + Serial.println(F("MAX30105 was not found. Please check wiring/power.")); |
| 62 | + while (1); |
| 63 | + } |
| 64 | + |
| 65 | + Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion")); |
| 66 | + while (Serial.available() == 0) ; //wait until user presses a key |
| 67 | + Serial.read(); |
| 68 | + |
| 69 | + byte ledBrightness = 60; //Options: 0=Off to 255=50mA |
| 70 | + byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32 |
| 71 | + byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green |
| 72 | + byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200 |
| 73 | + int pulseWidth = 411; //Options: 69, 118, 215, 411 |
| 74 | + int adcRange = 4096; //Options: 2048, 4096, 8192, 16384 |
| 75 | + |
| 76 | + particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings |
| 77 | +} |
| 78 | + |
| 79 | +void loop() |
| 80 | +{ |
| 81 | + bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps |
| 82 | + |
| 83 | + //read the first 100 samples, and determine the signal range |
| 84 | + for (byte i = 0 ; i < bufferLength ; i++) |
| 85 | + { |
| 86 | + while (particleSensor.available() == false) //do we have new data? |
| 87 | + particleSensor.check(); //Check the sensor for new data |
| 88 | + |
| 89 | + redBuffer[i] = particleSensor.getRed(); |
| 90 | + irBuffer[i] = particleSensor.getIR(); |
| 91 | + particleSensor.nextSample(); //We're finished with this sample so move to next sample |
| 92 | + |
| 93 | + Serial.print(F("red=")); |
| 94 | + Serial.print(redBuffer[i], DEC); |
| 95 | + Serial.print(F(", ir=")); |
| 96 | + Serial.println(irBuffer[i], DEC); |
| 97 | + } |
| 98 | + |
| 99 | + //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples) |
| 100 | + maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); |
| 101 | + |
| 102 | + //Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second |
| 103 | + while (1) |
| 104 | + { |
| 105 | + //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top |
| 106 | + for (byte i = 25; i < 100; i++) |
| 107 | + { |
| 108 | + redBuffer[i - 25] = redBuffer[i]; |
| 109 | + irBuffer[i - 25] = irBuffer[i]; |
| 110 | + } |
| 111 | + |
| 112 | + //take 25 sets of samples before calculating the heart rate. |
| 113 | + for (byte i = 75; i < 100; i++) |
| 114 | + { |
| 115 | + while (particleSensor.available() == false) //do we have new data? |
| 116 | + particleSensor.check(); //Check the sensor for new data |
| 117 | + |
| 118 | + digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read |
| 119 | + |
| 120 | + redBuffer[i] = particleSensor.getRed(); |
| 121 | + irBuffer[i] = particleSensor.getIR(); |
| 122 | + particleSensor.nextSample(); //We're finished with this sample so move to next sample |
| 123 | + |
| 124 | + //send samples and calculation result to terminal program through UART |
| 125 | + Serial.print(F("red=")); |
| 126 | + Serial.print(redBuffer[i], DEC); |
| 127 | + Serial.print(F(", ir=")); |
| 128 | + Serial.print(irBuffer[i], DEC); |
| 129 | + |
| 130 | + Serial.print(F(", HR=")); |
| 131 | + Serial.print(heartRate, DEC); |
| 132 | + |
| 133 | + Serial.print(F(", HRvalid=")); |
| 134 | + Serial.print(validHeartRate, DEC); |
| 135 | + |
| 136 | + Serial.print(F(", SPO2=")); |
| 137 | + Serial.print(spo2, DEC); |
| 138 | + |
| 139 | + Serial.print(F(", SPO2Valid=")); |
| 140 | + Serial.println(validSPO2, DEC); |
| 141 | + } |
| 142 | + |
| 143 | + //After gathering 25 new samples recalculate HR and SP02 |
| 144 | + maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); |
| 145 | + } |
| 146 | +} |
| 147 | + |
0 commit comments