multiple timed operations for a single device

hey guys, I have asked a similar question before and I was redirected to study millis. After a bit of struggle I sorted it out. I still dont understand millis completely. Please dont redirect me to tutorials again. I have to do this quick or my project lead(design engineer) will maul me.

The code I have turns on a led for 1.5 secs when the heart rate is high and then turns it off for 10 secs even if the heart rate is still high.

if(hr_average>70)
{
unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >=interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == 0)
    {
      interval = ONTIME;
      ledState = 150;
       }
    else
    {
     interval = OFFTIME; 
     ledState = 0;
    }
    // set the LED with the ledState of the variable:
    analogWrite(ledPin, ledState);
  }
  

  

}
else{
analogWrite(ledPin, 0);
}

The challenge is that I need the led to blink 3 times(turn on 1 sec and turn off 1 sec, 3 times) and then turn off for 10 seconds.
Sounds simple but trust me, I did try.
Your help is very much appreciated.

It's no 100% clear (to me) what you're asking....

Does it mean that when the rate GOES over ( as opposed to IS over) 70 do 3x blinks then turn off after 10 seconds? But not sure what it means to go off after 10 seconds: does that mean it stays on after the blinks then goes off after 10 seconds?

If so, then what happens? Does it stay off if rate stays over 70 and only do the 3x blink/10 second thing if it goes below 70 and then comes back up?

Edit: what happens if I'm right so far and it goes under 70 during the 3x blink/10 seconds?

@ardy_guy

Thank you very much for responding.
The algorithm is:
if hr>70,
Blink three times(ontime=offtime=1000millisecs)
turn off for 10 seconds
if the hr is still > 70, the above repeats again.
If hr<70,
the led stays off

Well? Can someone please respond. I am running out of time and I am not able to figure it out.

Your algorithm seems rather straightforward :

/*
  if hr>70,
  Blink three times(ontime=offtime=1000millisecs)
  turn off for 10 seconds
  if the hr is still > 70, the above repeats again.
  If hr<70,
  the led stays off
*/


uint32_t hr_average;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(A0, INPUT);
}

void loop() {

  // Todo : update here the last value of hr_average
  // e.g. hr_average = analogRead(A0); ??


  if (hr_average > 70) {
    Blink();
   
  }
  
}

void Blink() {
  // blink once
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(1000);

  // blink twice
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(1000);

  // blink a third time then turn OFF for 10 seconds
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(11000);

}

Why have you started another Thread about this?

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing. It may help with understanding the technique. It has a few different timings.

...R

@ard_newbie

Thanks for the effort. But i have to do the same thing without delays.

fame3096:
But i have to do the same thing without delays.

That is the entire purpose of my demo !

...R

@Robin,

Call me dumb but I have been on your demo for the past one hour.

A pattern of timings for a single led isnt explained in your demo and I Can't seem to figure it out.

3 blinks and turn it off for 10 seconds. This has repeat.

Try this snippet, it should work (not tested though) :

/*
  if hr>70,
  Blink three times(ontime=offtime=1000millisecs)
  turn off for 10 seconds
  if the hr is still > 70, the above repeats again.
  If hr<70,
  the led stays off
  WITHOUT delay()
*/


uint32_t hr_average;
uint32_t OldMillis;
uint32_t Flag_Blink;
boolean Flag_InProgress;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(A0, INPUT);
  OldMillis = millis();

}

void loop() {

  // Todo : update here the last value of hr_average
  // e.g. hr_average = analogRead(A0); ??


  if (hr_average > 70) {          // If heartbeats are too high
    Flag_InProgress = true;       // Enter Blink process and set Flag accordingly
    
    while (Flag_InProgress == true) {

      if (Flag_Blink < 3 ) {        // If the LED has blinked less than 3 times

        if ((millis() - OldMillis) < 1000 ) {  // If 1 second timstamp is not over
          digitalWrite(LED_BUILTIN, true);

        }
        else {
          if ((millis() - OldMillis) < 2000 ) {  // If 1 second < timestamp < 2 seconds
            digitalWrite(LED_BUILTIN, false);

          }
          else {                                // If timestamp > 2 seconds
            OldMillis = millis();
            Flag_Blink ++;
          }
        }

      }  // End of if (Flag_Blink < 3 )

      if (Flag_Blink == 3) {
        if ((millis() - OldMillis) < 10000 ) {  // If timestamp < 10 seconds
          // Do nothing
        }
        else {

          OldMillis = millis();
          Flag_Blink = 0;
          Flag_InProgress = false;
        }
      }  // End of if (Flag_Blink == 3)
    } // End of while (Flag_InProgress == true)

  }  // End of  if (hr_average > 70)
}

You are a genius. Thank you so much!

I understood the logic partly. I bet another read would make me comprehend. The flag technique is ingenious.

This sort of problem is best approached with a state machine. The logic is simplified and easy to extend. You have four basic states:

Normal: waiting for trigger (hr > 70)

Alert_led_on : LED on for 1 sec

Alert_led_off : LED off for 1 sec

Wait : 10 seconds with LED off

Each state can do it’s thing without worrying about anything else. When that state hits a trigger point, it moves to the next state.

Here is a working example sketch:

/*
   Demonstration of state machine
*/

typedef enum {normal, led_on, led_off, wait} state_t;

state_t state;
int heart_rate;
int count;
int32_t start_time;


void setup() {
  pinMode(13, OUTPUT);
  state = normal;
}

void loop() {

  heart_rate = analogRead(A0);

  switch (state)
  {
    case normal:
      if (heart_rate > 70)
      {
        state = led_on;
        count = 0;
        start_time = millis();
      }
      break;

    case led_on:
      if (count >= 3)
      {
        start_time = millis();
        state = wait;
      }
      else
      {
        if (millis() - start_time < 1000)
          digitalWrite(13, HIGH);
        else
        {
          state = led_off;
          start_time = millis();
        }
      }
      break;

    case led_off:
      if (millis() - start_time < 1000)
        digitalWrite(13, LOW);
      else
      {
        state = led_on;
        count++;
        start_time = millis();
      }
      break;

    case wait:
      if (millis() - start_time >= 10000)
        state = normal;
      break;
  }
}

I would use a less convoluted code (like I alread posted in your second thread)

const char ledPin = 9;

bool blinking = true;
byte blinks = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  static unsigned long lastEvent;
  unsigned long topLoop = millis();
  if (blinking) {
    if (topLoop - lastEvent >= 500) {
      lastEvent = topLoop;
      digitalWrite(ledPin, !digitalRead(ledPin));
      if (++blinks >= 6) {
        blinking = false;
        blinks = 0;
      }
    }
  } else if (topLoop - lastEvent >= 10000) {
    blinking = true;
  }
}

I would try another approach. What you call "blink" and what you call "off" and what you call "on" for the LED are ALL the same thing. Only the time is different.

I would attempt to only change the on time and off times based on conditions.

Paul

Paul_KD7HB:
I would try another approach. What you call "blink" and what you call "off" and what you call "on" for the LED are ALL the same thing. Only the time is different.

I'm quite sure "on" and "off" are different things!

I would attempt to only change the on time and off times based on conditions.

That's pretty much how all the above code works.

I would really recommend using something like the SimpleTimer library, which will make your code much more readable an de easier to maintain. Triggering the blinking for example I see simply written as

timer.setTimer(2000, ledOn, 3); // light up 3 times at 2s interval timer.setTimeout(16000, takeHeartBeat); // could also keep a static count in ledOn and wait 10s after the last blink...

void ledOn() {
digitalWrite(LED, HIGH);
Timer.setTimeout(1000, ledOff); // turn off in 1s
}

void ledOff() { digitalWrite(LED, LOW); }

ard_newbie:
Your algorithm seems rather straightforward :

/*

if hr>70,
  Blink three times(ontime=offtime=1000millisecs)
  turn off for 10 seconds
  if the hr is still > 70, the above repeats again.
  If hr<70,
  the led stays off
*/

uint32_t hr_average;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(A0, INPUT);
}

void loop() {

// Todo : update here the last value of hr_average
  // e.g. hr_average = analogRead(A0); ??

if (hr_average > 70) {
    Blink();
 
  }
 
}

void Blink() {
  // blink once
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(1000);

// blink twice
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(1000);

// blink a third time then turn OFF for 10 seconds
  digitalWrite(LED_BUILTIN, true);
  delay(1000);
  digitalWrite(LED_BUILTIN, false);
  delay(11000);

}

Hey there, Your code is great, It works by itself. The problem is that when I run it in my program with the heart rate, It works just like the delay code, the heart rate acquisition is halted when your code runs. My code includes data logging which involves using millis for other things as well.

fame3096:
The problem is that when I run it in my program with the heart rate, It works just like the delay code, the heart rate acquisition is halted when your code runs. My code includes data logging which involves using millis for other things as well.

See Reply #5 ?

...R