2

max30100 i2c sensor gives heartrate and spo2 reading in serial and also can show values in lcd display. I want to show it's indication via LED.

If SpO2 value <94 , it will turn on Red led in digital pin 4

If SpO2 value >=94, it will urn on Green led in digital pin 5

Here pox.getSpO2() gives the SpO2 value.

How can I use this value to toggle between two digital pin. I understand it's easier to read analog pin value for toggling but I am searching for guidelines how I2C values can be use for this condition.

Thank you.

Here is the minimalistic code of SpO2

#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define REPORTING_PERIOD_MS     1000

PulseOximeter pox;
uint32_t tsLastReport = 0;

void setup()
{
    Serial.begin(9600);

    Serial.print("Initializing pulse oximeter..");

    if (!pox.begin()) {
        Serial.println("FAILED");
        for(;;);
    } else {
        Serial.println("SUCCESS");
    }
}

void loop()
{

    pox.update();

    if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
        Serial.print("SpO2:");
        Serial.print(pox.getSpO2());
        Serial.println("%");

        tsLastReport = millis();
    }
}
2

You've done all the hard work already by setting the sensor up and managing to read from it.

I'd define a constant for the SpO2 threshold near the top, and convenient names for the pins:

const uint8_t SpO2_threshold = 94;  // percent
const uint8_t red_pin = 4;
const uint8_t green_pin = 5;

Then set the pins to output mode in the setup() as usual. (Maybe set them both HIGH (or LOW) too in there, to indicate that no reading has been done yet.)

In the loop, inside the reporting section, simply grab the value and toggle the pins:

...
uint8_t spo2 = pox.getSpO2();
// Print it out to serial if needed, then:
if (spo2 < SpO2_threshold) {
  digitalWrite(green_pin, LOW);
  digitalWrite(red_pin, HIGH);
} else {
  digitalWrite(red_pin, LOW);
  digitalWrite(green_pin, HIGH);
}

A more involved version that pulses one LED (short on time, variable off time) depending on the value read from the sensor. It uses the same technique as the sensor reading timing (the one used in the "blink without delay" example).

Sensor readings are clamped (any value at or below spo2_min will result in the fasted blink time, over spo2_max the slowest). Then that range is mapped to a range of led off times. Don't use the values in this example, I'm not a medical doctor :-)

// pin mapping
const uint8_t led_pin = LED_BUILTIN;

// sensor readings (%)
const int spo2_min = 85;
const int spo2_max = 100;

// led timings (ms)
const unsigned long led_off_min = 50;
const unsigned long led_off_max = 5000;

unsigned long led_off_time = led_off_max; // variable off time
const unsigned long led_on_time = 50;     // fixed, short on time

// sensor reading timing (ms)
const unsigned long sensor_interval = 1000;

// led state
uint8_t led_state = LOW;

// "timer" state
unsigned long last_reading = 0;
unsigned long last_led_toggle = 0;

void setup() {
  pinMode(led_pin, OUTPUT);
  digitalWrite(led_pin, led_state);

  Serial.begin(9600);

  Serial.print("Initializing pulse oximeter..");
  if (!pox.begin()) {
    Serial.println("FAILED");
    for (;;);
  } else {
    Serial.println("SUCCESS");
  }
}

void loop() {
  pox.update();
  unsigned long current_millis = millis();

  /* sensor reading "timer" */
  if (current_millis - last_reading >= sensor_interval)
  {
    last_reading = current_millis;

    int spo2 = pox.getSpO2();

    // clamp reading to expected range
    int clamped = constrain(spo2, spo2_min, spo2_max);
    // map to off time range
    led_off_time = map(clamped,
                       spo2_min, spo2_max,
                       led_off_min, led_off_max);

    char buff[128];
    sprintf_P(buff, PSTR("reading: %d (%%) -> interval: %lu (ms)"),
              spo2, led_off_time);
    Serial.println(buff);
  }

  /* led toggling "timers" */
  unsigned long led_elapsed = current_millis - last_led_toggle;

  if ((led_state == LOW) && (led_elapsed >= led_off_time))
  {
    last_led_toggle = current_millis;
    led_state = HIGH;
    digitalWrite(led_pin, led_state);
  }
  else if ((led_state == HIGH) && (led_elapsed >= led_on_time))
  {
    last_led_toggle = current_millis;
    led_state = LOW;
    digitalWrite(led_pin, led_state);
  }

}
7
  • Thanks a lot. I already tried earlier same as this way and it's working. You explanations made it more clearly understandable to me. Thank you.
    – Sayzar
    Aug 13 at 16:18
  • Hello, how about using only single red led via giving pulse. If <94, led will blink rapidly. if >=94, led will blink slowly. I tried to add delay(); but it works when using around 10ms delay. but for 500ms delay, spo2 loops also gets delay and it only show 0%. Doesn't work for larger delay cycle. Any thoughts ?
    – Sayzar
    Aug 13 at 23:12
  • 1
    delay is not your friend. Use the same technique as you did for the sensor readings, i.e. check the time elapsed since you last toggled the LED, and toggle it if that is longer than your threshold. Added an example. Probably won't be great if you're only receiving ints in a rather small range - you don't have much granularity.
    – Mat
    Aug 14 at 8:10
  • 1
    Other note: if you need need more complicated than this, I'd recommend you find a timer library that you like, and look into state machines also. Lots of examples and docs on both these topics.
    – Mat
    Aug 14 at 8:33
  • 1
    There was an error in the printf format string, fixed it, but can't reproduce what you are seeing. The only place where the speed changes is in the sensor update part. If you want to print something based on the reading value, it must go in there. If you want to repeat it, then you need to save it so that the last reading is available elsewhere in the loop.
    – Mat
    Aug 16 at 21:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.