How to Make Heart Rate & Blood Oxygen Detection
How to Make Heart Rate & Blood Oxygen Detection with Pulse Oximeter using Arduino
Components and supplies
1
Jumper wires (generic)
1
Bread board
1
Max30102 Pulse oximeter
1
Push Button
1
Arduino Nano R3
1
SSD1306 LCD
Project description
Code
Code
arduino
1#include "ssd1306h.h" 2#include "MAX30102.h" 3#include "Pulse.h" 4#include <avr/pgmspace.h> 5#include <EEPROM.h> 6#include <avr/sleep.h> 7 8// Routines to clear and set bits 9#ifndef cbi 10#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 11#endif 12#ifndef sbi 13#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 14#endif 15 16 17SSD1306 oled; 18MAX30102 sensor; 19Pulse pulseIR; 20Pulse pulseRed; 21MAFilter bpm; 22 23#define LED LED_BUILTIN 24#define BUTTON 3 25#define OPTIONS 7 26 27static const uint8_t heart_bits[] PROGMEM = { 0x00, 0x00, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0xfe, 0xff, 28 0xfe, 0xff, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 29 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 30 0x00, 0x00 }; 31 32//spo2_table is approximated as -45.060*ratioAverage* ratioAverage + 30.354 *ratioAverage + 94.845 ; 33const uint8_t spo2_table[184] PROGMEM = 34 { 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99, 35 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 36 100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97, 37 97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91, 38 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81, 39 80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67, 40 66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 41 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29, 42 28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5, 43 3, 2, 1 } ; 44 45 46int getVCC() { 47 //reads internal 1V1 reference against VCC 48 #if defined(__AVR_ATmega1284P__) 49 ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega1284 50 #else 51 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 52 #endif 53 delay(2); // Wait for Vref to settle 54 ADCSRA |= _BV(ADSC); // Convert 55 while (bit_is_set(ADCSRA, ADSC)); 56 uint8_t low = ADCL; 57 unsigned int val = (ADCH << 8) | low; 58 //discard previous result 59 ADCSRA |= _BV(ADSC); // Convert 60 while (bit_is_set(ADCSRA, ADSC)); 61 low = ADCL; 62 val = (ADCH << 8) | low; 63 64 return (((long)1024 * 1100) / val)/100; 65} 66 67void print_digit(int x, int y, long val, char c=' ', uint8_t field = 3,const int BIG = 2) 68 { 69 uint8_t ff = field; 70 do { 71 char ch = (val!=0) ? val%10+'0': c; 72 oled.drawChar( x+BIG*(ff-1)*6, y, ch, BIG); 73 val = val/10; 74 --ff; 75 } while (ff>0); 76} 77 78 79/* 80 * Record, scale and display PPG Wavefoem 81 */ 82const uint8_t MAXWAVE = 72; 83 84class Waveform { 85 public: 86 Waveform(void) {wavep = 0;} 87 88 void record(int waveval) { 89 waveval = waveval/8; // scale to fit in byte 90 waveval += 128; //shift so entired waveform is +ve 91 waveval = waveval<0? 0 : waveval; 92 waveform[wavep] = (uint8_t) (waveval>255)?255:waveval; 93 wavep = (wavep+1) % MAXWAVE; 94 } 95 96 void scale() { 97 uint8_t maxw = 0; 98 uint8_t minw = 255; 99 for (int i=0; i<MAXWAVE; i++) { 100 maxw = waveform[i]>maxw?waveform[i]:maxw; 101 minw = waveform[i]<minw?waveform[i]:minw; 102 } 103 uint8_t scale8 = (maxw-minw)/4 + 1; //scale * 8 to preserve precision 104 uint8_t index = wavep; 105 for (int i=0; i<MAXWAVE; i++) { 106 disp_wave[i] = 31-((uint16_t)(waveform[index]-minw)*8)/scale8; 107 index = (index + 1) % MAXWAVE; 108 } 109 } 110 111void draw(uint8_t X) { 112 for (int i=0; i<MAXWAVE; i++) { 113 uint8_t y = disp_wave[i]; 114 oled.drawPixel(X+i, y); 115 if (i<MAXWAVE-1) { 116 uint8_t nexty = disp_wave[i+1]; 117 if (nexty>y) { 118 for (uint8_t iy = y+1; iy<nexty; ++iy) 119 oled.drawPixel(X+i, iy); 120 } 121 else if (nexty<y) { 122 for (uint8_t iy = nexty+1; iy<y; ++iy) 123 oled.drawPixel(X+i, iy); 124 } 125 } 126 } 127} 128 129private: 130 uint8_t waveform[MAXWAVE]; 131 uint8_t disp_wave[MAXWAVE]; 132 uint8_t wavep = 0; 133 134} wave; 135 136int beatAvg; 137int SPO2, SPO2f; 138int voltage; 139bool filter_for_graph = false; 140bool draw_Red = false; 141uint8_t pcflag =0; 142uint8_t istate = 0; 143uint8_t sleep_counter = 0; 144 145void button(void){ 146 pcflag = 1; 147} 148 149void checkbutton(){ 150 if (pcflag && !digitalRead(BUTTON)) { 151 istate = (istate +1) % 4; 152 filter_for_graph = istate & 0x01; 153 draw_Red = istate & 0x02; 154 EEPROM.write(OPTIONS, filter_for_graph); 155 EEPROM.write(OPTIONS+1, draw_Red); 156 } 157 pcflag = 0; 158} 159 160 161 162void Display_5(){ 163 if(pcflag && !digitalRead(BUTTON)){ 164 draw_oled(5); 165 delay(1100); 166 } 167 pcflag = 0; 168 169 170} 171 172void go_sleep() { 173 oled.fill(0); 174 oled.off(); 175 delay(10); 176 sensor.off(); 177 delay(10); 178 cbi(ADCSRA, ADEN); // disable adc 179 delay(10); 180 pinMode(0,INPUT); 181 pinMode(2,INPUT); 182 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 183 sleep_mode(); // sleep until button press 184 // cause reset 185 setup(); 186} 187 188void draw_oled(int msg) { 189 oled.firstPage(); 190 do{ 191 switch(msg){ 192 case 0: oled.drawStr(10,0,F("Device error"),1); 193 break; 194 case 1: oled.drawStr(13,10,F("PLACE"),1); 195 oled.drawStr(10,20,F("FINGER"),1); 196 oled.drawChar(100,0,voltage/10+'0'); 197 oled.drawChar(106,0,'.'); 198 oled.drawChar(112,0,voltage%10+'0'); 199 oled.drawChar(118,0,'V'); 200 oled.drawStr(84,14,F("Display"),1); 201 if (draw_Red) 202 oled.drawStr(84,24,F("Red"),1); 203 else 204 oled.drawStr(84,24,F("IR"),1); 205 if (filter_for_graph) 206 oled.drawStr(108,24,F("Avg"),1); 207 else 208 oled.drawStr(108,24,F("Raw"),1); 209 break; 210 case 2: print_digit(86,0,beatAvg); 211 wave.draw(8); 212 print_digit(98,16,SPO2f,' ',3,1); 213 oled.drawChar(116,16,'%'); 214 print_digit(98,24,SPO2,' ',3,1); 215 oled.drawChar(116,24,'%'); 216 break; 217 case 3: oled.drawStr(30,9,F("Welcome to "),1); 218 oled.drawStr(30,20,F("Fair Electro"),1); 219 //oled.drawXBMP(6,8,16,16,heart_bits); 220 221 break; 222 case 4: oled.drawStr(28,12,F("OFF IN"),1); 223 oled.drawChar(76,12,10-sleep_counter/10+'0'); 224 oled.drawChar(82,12,'s'); 225 break; 226 case 5: oled.drawStr(0,0,F("BMP:"),1); 227 print_digit(25,0,beatAvg); 228 oled.drawStr(0,15,F("SpO2:"),1); 229 print_digit(25,15,SPO2); 230 oled.drawXBMP(106,8,16,16,heart_bits); 231 break; 232 } 233 } while (oled.nextPage()); 234} 235 236void setup(void) { 237 pinMode(LED, OUTPUT); 238 pinMode(BUTTON, INPUT_PULLUP); 239 filter_for_graph = EEPROM.read(OPTIONS); 240 draw_Red = EEPROM.read(OPTIONS+1); 241 oled.init(); 242 oled.fill(0x00); 243 draw_oled(3); 244 delay(3000); 245 if (!sensor.begin()) { 246 draw_oled(0); 247 while (1); 248 } 249 sensor.setup(); 250 attachInterrupt(digitalPinToInterrupt(BUTTON),button, CHANGE); 251} 252 253long lastBeat = 0; //Time of the last beat 254long displaytime = 0; //Time of the last display update 255bool led_on = false; 256 257 258void loop() { 259 sensor.check(); 260 long now = millis(); //start time of this cycle 261 if (!sensor.available()) return; 262 uint32_t irValue = sensor.getIR(); 263 uint32_t redValue = sensor.getRed(); 264 sensor.nextSample(); 265 if (irValue<5000) { 266 voltage = getVCC(); 267 checkbutton(); 268 draw_oled(sleep_counter<=50 ? 1 : 4); // finger not down message 269 270 delay(200); 271 ++sleep_counter; 272 if (sleep_counter>100) { 273 go_sleep(); 274 sleep_counter = 0; 275 } 276 } else { 277 sleep_counter = 0; 278 279 int16_t IR_signal, Red_signal; 280 bool beatRed, beatIR; 281 if (!filter_for_graph) { 282 IR_signal = pulseIR.dc_filter(irValue) ; 283 Red_signal = pulseRed.dc_filter(redValue); 284 beatRed = pulseRed.isBeat(pulseRed.ma_filter(Red_signal)); 285 beatIR = pulseIR.isBeat(pulseIR.ma_filter(IR_signal)); 286 } else { 287 IR_signal = pulseIR.ma_filter(pulseIR.dc_filter(irValue)) ; 288 Red_signal = pulseRed.ma_filter(pulseRed.dc_filter(redValue)); 289 beatRed = pulseRed.isBeat(Red_signal); 290 beatIR = pulseIR.isBeat(IR_signal); 291 } 292 // invert waveform to get classical BP waveshape 293 wave.record(draw_Red ? -Red_signal : -IR_signal ); 294 // check IR or Red for heartbeat 295 if (draw_Red ? beatRed : beatIR){ 296 long btpm = 60000/(now - lastBeat); 297 if (btpm > 0 && btpm < 200) beatAvg = bpm.filter((int16_t)btpm); 298 lastBeat = now; 299 digitalWrite(LED, HIGH); 300 led_on = true; 301 // compute SpO2 ratio 302 long numerator = (pulseRed.avgAC() * pulseIR.avgDC())/256; 303 long denominator = (pulseRed.avgDC() * pulseIR.avgAC())/256; 304 int RX100 = (denominator>0) ? (numerator * 100)/denominator : 999; 305 // using formula 306 SPO2f = (10400 - RX100*17+50)/100; 307 // from table 308 if ((RX100>=0) && (RX100<184)) 309 SPO2 = pgm_read_byte_near(&spo2_table[RX100]); 310 } 311 // update display every 50 ms if fingerdown 312 if (now-displaytime>50) { 313 displaytime = now; 314 wave.scale(); 315 draw_oled(2); 316 317 } 318 Display_5(); 319 320 321 } 322 // flash led for 25 ms 323 if (led_on && (now - lastBeat)>25){ 324 digitalWrite(LED, LOW); 325 led_on = false; 326 } 327} 328
Code
arduino
1#include "ssd1306h.h" 2#include "MAX30102.h" 3#include "Pulse.h" 4#include <avr/pgmspace.h> 5#include <EEPROM.h> 6#include <avr/sleep.h> 7 8// Routines to clear and set bits 9#ifndef cbi 10#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 11#endif 12#ifndef sbi 13#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 14#endif 15 16 17SSD1306 oled; 18MAX30102 sensor; 19Pulse pulseIR; 20Pulse pulseRed; 21MAFilter bpm; 22 23#define LED LED_BUILTIN 24#define BUTTON 3 25#define OPTIONS 7 26 27static const uint8_t heart_bits[] PROGMEM = { 0x00, 0x00, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0xfe, 0xff, 28 0xfe, 0xff, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x0f, 29 0xc0, 0x07, 0x80, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 30 0x00, 0x00 }; 31 32//spo2_table is approximated as -45.060*ratioAverage* ratioAverage + 30.354 *ratioAverage + 94.845 ; 33const uint8_t spo2_table[184] PROGMEM = 34 { 95, 95, 95, 96, 96, 96, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 99, 99, 99, 99, 35 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 36 100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 97, 97, 37 97, 97, 96, 96, 96, 96, 95, 95, 95, 94, 94, 94, 93, 93, 93, 92, 92, 92, 91, 91, 38 90, 90, 89, 89, 89, 88, 88, 87, 87, 86, 86, 85, 85, 84, 84, 83, 82, 82, 81, 81, 39 80, 80, 79, 78, 78, 77, 76, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, 67, 40 66, 66, 65, 64, 63, 62, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 41 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 31, 30, 29, 42 28, 27, 26, 25, 23, 22, 21, 20, 19, 17, 16, 15, 14, 12, 11, 10, 9, 7, 6, 5, 43 3, 2, 1 } ; 44 45 46int getVCC() { 47 //reads internal 1V1 reference against VCC 48 #if defined(__AVR_ATmega1284P__) 49 ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega1284 50 #else 51 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 52 #endif 53 delay(2); // Wait for Vref to settle 54 ADCSRA |= _BV(ADSC); // Convert 55 while (bit_is_set(ADCSRA, ADSC)); 56 uint8_t low = ADCL; 57 unsigned int val = (ADCH << 8) | low; 58 //discard previous result 59 ADCSRA |= _BV(ADSC); // Convert 60 while (bit_is_set(ADCSRA, ADSC)); 61 low = ADCL; 62 val = (ADCH << 8) | low; 63 64 return (((long)1024 * 1100) / val)/100; 65} 66 67void print_digit(int x, int y, long val, char c=' ', uint8_t field = 3,const int BIG = 2) 68 { 69 uint8_t ff = field; 70 do { 71 char ch = (val!=0) ? val%10+'0': c; 72 oled.drawChar( x+BIG*(ff-1)*6, y, ch, BIG); 73 val = val/10; 74 --ff; 75 } while (ff>0); 76} 77 78 79/* 80 * Record, scale and display PPG Wavefoem 81 */ 82const uint8_t MAXWAVE = 72; 83 84class Waveform { 85 public: 86 Waveform(void) {wavep = 0;} 87 88 void record(int waveval) { 89 waveval = waveval/8; // scale to fit in byte 90 waveval += 128; //shift so entired waveform is +ve 91 waveval = waveval<0? 0 : waveval; 92 waveform[wavep] = (uint8_t) (waveval>255)?255:waveval; 93 wavep = (wavep+1) % MAXWAVE; 94 } 95 96 void scale() { 97 uint8_t maxw = 0; 98 uint8_t minw = 255; 99 for (int i=0; i<MAXWAVE; i++) { 100 maxw = waveform[i]>maxw?waveform[i]:maxw; 101 minw = waveform[i]<minw?waveform[i]:minw; 102 } 103 uint8_t scale8 = (maxw-minw)/4 + 1; //scale * 8 to preserve precision 104 uint8_t index = wavep; 105 for (int i=0; i<MAXWAVE; i++) { 106 disp_wave[i] = 31-((uint16_t)(waveform[index]-minw)*8)/scale8; 107 index = (index + 1) % MAXWAVE; 108 } 109 } 110 111void draw(uint8_t X) { 112 for (int i=0; i<MAXWAVE; i++) { 113 uint8_t y = disp_wave[i]; 114 oled.drawPixel(X+i, y); 115 if (i<MAXWAVE-1) { 116 uint8_t nexty = disp_wave[i+1]; 117 if (nexty>y) { 118 for (uint8_t iy = y+1; iy<nexty; ++iy) 119 oled.drawPixel(X+i, iy); 120 } 121 else if (nexty<y) { 122 for (uint8_t iy = nexty+1; iy<y; ++iy) 123 oled.drawPixel(X+i, iy); 124 } 125 } 126 } 127} 128 129private: 130 uint8_t waveform[MAXWAVE]; 131 uint8_t disp_wave[MAXWAVE]; 132 uint8_t wavep = 0; 133 134} wave; 135 136int beatAvg; 137int SPO2, SPO2f; 138int voltage; 139bool filter_for_graph = false; 140bool draw_Red = false; 141uint8_t pcflag =0; 142uint8_t istate = 0; 143uint8_t sleep_counter = 0; 144 145void button(void){ 146 pcflag = 1; 147} 148 149void checkbutton(){ 150 if (pcflag && !digitalRead(BUTTON)) { 151 istate = (istate +1) % 4; 152 filter_for_graph = istate & 0x01; 153 draw_Red = istate & 0x02; 154 EEPROM.write(OPTIONS, filter_for_graph); 155 EEPROM.write(OPTIONS+1, draw_Red); 156 } 157 pcflag = 0; 158} 159 160 161 162void Display_5(){ 163 if(pcflag && !digitalRead(BUTTON)){ 164 draw_oled(5); 165 delay(1100); 166 } 167 pcflag = 0; 168 169 170} 171 172void go_sleep() { 173 oled.fill(0); 174 oled.off(); 175 delay(10); 176 sensor.off(); 177 delay(10); 178 cbi(ADCSRA, ADEN); // disable adc 179 delay(10); 180 pinMode(0,INPUT); 181 pinMode(2,INPUT); 182 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 183 sleep_mode(); // sleep until button press 184 // cause reset 185 setup(); 186} 187 188void draw_oled(int msg) { 189 oled.firstPage(); 190 do{ 191 switch(msg){ 192 case 0: oled.drawStr(10,0,F("Device error"),1); 193 break; 194 case 1: oled.drawStr(13,10,F("PLACE"),1); 195 oled.drawStr(10,20,F("FINGER"),1); 196 oled.drawChar(100,0,voltage/10+'0'); 197 oled.drawChar(106,0,'.'); 198 oled.drawChar(112,0,voltage%10+'0'); 199 oled.drawChar(118,0,'V'); 200 oled.drawStr(84,14,F("Display"),1); 201 if (draw_Red) 202 oled.drawStr(84,24,F("Red"),1); 203 else 204 oled.drawStr(84,24,F("IR"),1); 205 if (filter_for_graph) 206 oled.drawStr(108,24,F("Avg"),1); 207 else 208 oled.drawStr(108,24,F("Raw"),1); 209 break; 210 case 2: print_digit(86,0,beatAvg); 211 wave.draw(8); 212 print_digit(98,16,SPO2f,' ',3,1); 213 oled.drawChar(116,16,'%'); 214 print_digit(98,24,SPO2,' ',3,1); 215 oled.drawChar(116,24,'%'); 216 break; 217 case 3: oled.drawStr(30,9,F("Welcome to "),1); 218 oled.drawStr(30,20,F("Fair Electro"),1); 219 //oled.drawXBMP(6,8,16,16,heart_bits); 220 221 break; 222 case 4: oled.drawStr(28,12,F("OFF IN"),1); 223 oled.drawChar(76,12,10-sleep_counter/10+'0'); 224 oled.drawChar(82,12,'s'); 225 break; 226 case 5: oled.drawStr(0,0,F("BMP:"),1); 227 print_digit(25,0,beatAvg); 228 oled.drawStr(0,15,F("SpO2:"),1); 229 print_digit(25,15,SPO2); 230 oled.drawXBMP(106,8,16,16,heart_bits); 231 break; 232 } 233 } while (oled.nextPage()); 234} 235 236void setup(void) { 237 pinMode(LED, OUTPUT); 238 pinMode(BUTTON, INPUT_PULLUP); 239 filter_for_graph = EEPROM.read(OPTIONS); 240 draw_Red = EEPROM.read(OPTIONS+1); 241 oled.init(); 242 oled.fill(0x00); 243 draw_oled(3); 244 delay(3000); 245 if (!sensor.begin()) { 246 draw_oled(0); 247 while (1); 248 } 249 sensor.setup(); 250 attachInterrupt(digitalPinToInterrupt(BUTTON),button, CHANGE); 251} 252 253long lastBeat = 0; //Time of the last beat 254long displaytime = 0; //Time of the last display update 255bool led_on = false; 256 257 258void loop() { 259 sensor.check(); 260 long now = millis(); //start time of this cycle 261 if (!sensor.available()) return; 262 uint32_t irValue = sensor.getIR(); 263 uint32_t redValue = sensor.getRed(); 264 sensor.nextSample(); 265 if (irValue<5000) { 266 voltage = getVCC(); 267 checkbutton(); 268 draw_oled(sleep_counter<=50 ? 1 : 4); // finger not down message 269 270 delay(200); 271 ++sleep_counter; 272 if (sleep_counter>100) { 273 go_sleep(); 274 sleep_counter = 0; 275 } 276 } else { 277 sleep_counter = 0; 278 279 int16_t IR_signal, Red_signal; 280 bool beatRed, beatIR; 281 if (!filter_for_graph) { 282 IR_signal = pulseIR.dc_filter(irValue) ; 283 Red_signal = pulseRed.dc_filter(redValue); 284 beatRed = pulseRed.isBeat(pulseRed.ma_filter(Red_signal)); 285 beatIR = pulseIR.isBeat(pulseIR.ma_filter(IR_signal)); 286 } else { 287 IR_signal = pulseIR.ma_filter(pulseIR.dc_filter(irValue)) ; 288 Red_signal = pulseRed.ma_filter(pulseRed.dc_filter(redValue)); 289 beatRed = pulseRed.isBeat(Red_signal); 290 beatIR = pulseIR.isBeat(IR_signal); 291 } 292 // invert waveform to get classical BP waveshape 293 wave.record(draw_Red ? -Red_signal : -IR_signal ); 294 // check IR or Red for heartbeat 295 if (draw_Red ? beatRed : beatIR){ 296 long btpm = 60000/(now - lastBeat); 297 if (btpm > 0 && btpm < 200) beatAvg = bpm.filter((int16_t)btpm); 298 lastBeat = now; 299 digitalWrite(LED, HIGH); 300 led_on = true; 301 // compute SpO2 ratio 302 long numerator = (pulseRed.avgAC() * pulseIR.avgDC())/256; 303 long denominator = (pulseRed.avgDC() * pulseIR.avgAC())/256; 304 int RX100 = (denominator>0) ? (numerator * 100)/denominator : 999; 305 // using formula 306 SPO2f = (10400 - RX100*17+50)/100; 307 // from table 308 if ((RX100>=0) && (RX100<184)) 309 SPO2 = pgm_read_byte_near(&spo2_table[RX100]); 310 } 311 // update display every 50 ms if fingerdown 312 if (now-displaytime>50) { 313 displaytime = now; 314 wave.scale(); 315 draw_oled(2); 316 317 } 318 Display_5(); 319 320 321 } 322 // flash led for 25 ms 323 if (led_on && (now - lastBeat)>25){ 324 digitalWrite(LED, LOW); 325 led_on = false; 326 } 327} 328
Downloadable files
screenshot_2021-04-08_215935_vNIX70bsPU.jpg
screenshot_2021-04-08_215935_vNIX70bsPU.jpg

Comments
Only logged in users can leave comments