Devices & Components
Arduino Nano
STEMMA QT / Qwiic JST SH 4-pin Premium Female Headers Cable
Rubber Band
STEMMA QT / Qwiic 5 Port Hub
Max30102 Pulse oximeter
0.91" I2C OLED 128x32
Hardware & Tools
3D printer
Soldering kit
Software & Tools
Arduino IDE
Bambu Lab
TinkerCAD
Project description
Code
Code
cpp
1// max30102 libraries 2#include <Wire.h> 3#include "MAX30105.h" 4#include "spo2_algorithm.h" 5 6// oled libraries 7#include <SSD1306Ascii.h> 8#include <SSD1306AsciiWire.h> 9 10MAX30105 particleSensor; 11SSD1306AsciiWire oled; 12 13#define MAX_BRIGHTNESS 255 14 15uint16_t irBuffer[100]; //infrared LED sensor data 16uint16_t redBuffer[100]; //red LED sensor data 17 18int32_t bufferLength; //data length 19int32_t spo2; //SPO2 value 20int8_t validSPO2; //indicator to show if the SPO2 calculation is valid 21int32_t heartRate; //heart rate value 22int8_t validHeartRate; //indicator to show if the heart rate calculation is valid 23 24byte pulseLED = 11; //Must be on PWM pin 25byte readLED = 13; //Blinks with each data read 26 27int prevPulse = 0; 28int prevO2 = 0; 29 30void setup() 31{ 32 Serial.begin(115200); // initialize serial communication at 115200 bits per second: 33 Wire.begin(); 34 35 // set-up for the oled 36 oled.begin(&Adafruit128x32, 0x3C); 37 oled.setFont(Verdana12); 38 oled.clear(); 39 oled.setCursor(0, 0); 40 41 pinMode(pulseLED, OUTPUT); 42 pinMode(readLED, OUTPUT); 43 44 // Initialize sensor 45 if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed 46 { 47 Serial.println(F("MAX30105 was not found. Please check wiring/power.")); 48 while (1); 49 } 50 51 Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion")); 52 oled.println("Place finger on"); 53 oled.println("sensor"); 54 while (Serial.available() == 0) ; //wait until user presses a key 55 Serial.read(); 56 57 byte ledBrightness = 60; //Options: 0=Off to 255=50mA 58 byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32 59 byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green 60 byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200 61 int pulseWidth = 411; //Options: 69, 118, 215, 411 62 int adcRange = 4096; //Options: 2048, 4096, 8192, 16384 63 64 particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings 65} 66 67void loop() 68{ 69 bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps 70 71 //read the first 100 samples, and determine the signal range 72 for (byte i = 0 ; i < bufferLength ; i++) 73 { 74 while (particleSensor.available() == false) //do we have new data? 75 particleSensor.check(); //Check the sensor for new data 76 77 redBuffer[i] = particleSensor.getRed(); 78 irBuffer[i] = particleSensor.getIR(); 79 particleSensor.nextSample(); //We're finished with this sample so move to next sample 80 81 Serial.print(F("red=")); 82 Serial.print(redBuffer[i], DEC); 83 Serial.print(F(", ir=")); 84 Serial.println(irBuffer[i], DEC); 85 } 86 87 //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples) 88 maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); 89 90 //Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second 91 while (1) 92 { 93 //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top 94 for (byte i = 25; i < 100; i++) 95 { 96 redBuffer[i - 25] = redBuffer[i]; 97 irBuffer[i - 25] = irBuffer[i]; 98 } 99 100 //take 25 sets of samples before calculating the heart rate. 101 for (byte i = 75; i < 100; i++) 102 { 103 while (particleSensor.available() == false) //do we have new data? 104 particleSensor.check(); //Check the sensor for new data 105 106 digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read 107 108 redBuffer[i] = particleSensor.getRed(); 109 irBuffer[i] = particleSensor.getIR(); 110 particleSensor.nextSample(); //We're finished with this sample so move to next sample 111 112 //send samples and calculation result to terminal program through UART 113 114 Serial.print(F("red=")); 115 Serial.print(redBuffer[i], DEC); 116 Serial.print(F(", ir=")); 117 Serial.print(irBuffer[i], DEC); 118 119 Serial.print(F(", HRvalid=")); 120 Serial.print(validHeartRate, DEC); 121 122 Serial.print(F(", SPO2Valid=")); 123 Serial.println(validSPO2, DEC); 124 125 int HR = validSPO2; 126 Serial.println(HR); 127 128 if (validSPO2 == 1 && (prevPulse != heartRate || prevO2 != spo2)) { 129 oled.clear(); 130 131 oled.setCursor(0, 0); 132 oled.print("HR: "); 133 oled.println(heartRate, DEC); 134 135 136 oled.print("SPO2: "); 137 oled.print(spo2, DEC); 138 } 139 140 prevO2 = spo2; 141 prevPulse = heartRate; 142 } 143 144 maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate); 145 } 146}
Downloadable files
Spark Fun MAX3010x Sensor Library
https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library
SSD1306Ascii Library
https://github.com/greiman/SSD1306Ascii?search=1
Pulse Oximeter Case
https://www.tinkercad.com/things/gct4yC6dcym-pulse-oximeter?sharecode=6VDBdbNTsEqyapK9OLpTUQiLS6e3KTB10SsZqJU1rCI
Documentation
Wiring Diagram
IMG_1868.jpg

Comments
Only logged in users can leave comments