LED blink using millis() but with differing ON and OFF cycles

A LED blink program by David Mellis ( https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay shows the LED's blinking ON and OFF in equal time spacings (duty cycle).

However I need to use this idea in a situation where the ON/OFF cycles are not equal.

More exactly: I have a program where a message 1 has to be displayed during interval1, then message 2 has to be displayed during interval2.

Moreover, the usage of this display cycle is dependent of a number of conditions being met.

If the conditions are no longer met, the display of message1 and message2 has to stop and the program has to carry on.

However, as soon as the conditions are valid again, then the display cycle of message1 and message2 has to resume flawlessly.

My idea was to use the fact that the millis() setup by David Mellis goes through the statements in the loop twice: once at the start and once at the end of the timing. So I had to figure a way to get these statements ran through twice, and only then go to the statements relevant for timing interval2.

For that I use an intermediate variable: flag1 for interval1 and flag2 for interval2. Something like a bistable multivibrator for those knowledgeable in electronics, with the exception that it takes two triggers instead of one to change state.

Please have a critical look at my code; any comments will be greatly appreciated:

// Draft program to run millis()( instead of delay()
// Purpose is to alternate two texts on a LCD line but with different cycles: message1 display a time interval1,
// messag2 displays a time interval2
// The execution of this program is dependent on a set of conditions: temp1Value>T1 && temp2Value <= T2 || temp2Value>T1 && temp2Value<=T2 && OC=false
// 
// The idea is that the execution of the millis()-delayfunction happens the first time the function is called and only when the time-interval has lapsed
// will the millis()-delayfunction be run again.
// Therefor variables must be set to allow interval1 section to be ran a first time and then a second time and only then it is allowed to go to the
// interval2 section. Both interval sections may only run exclusively.
// The purpose must also be that whenever the inital condition is not valid anymore and so the statements are not run anymore, 
// that whenever the condition is met again at a later time, the millis()(-dealyfunction can be ran again without error.


    const long interval1 = 250; // display time 1 in milliseconds
    const long interval2 = 350; // display time 2 in milliseconds
    unsigned long previousMillis1 = 0; // display timer 1
    unsigned long previousMillis2 = 0; // display timer 2
    boolean message1 = true;
    boolean message2 = false;
    boolean flag1 = false;
    boolean flag2 = false;



void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

  unsigned long currentMillis1 = millis();
  unsigned long currentMillis2 = millis();

    //..lots of previous programming lines not relevant to this post..


    if (temp1Value > T1 && temp1Value <= T2 || temp2Value > T1 && temp2Value <= T2 && OC == false)  // warning high temp darlington or heatsink
        {
            warning  = true;
            digitalWrite(LED_BUILTIN, HIGH);

          
          if ((currentMillis1 - previousMillis1 >= interval1) && (message1 = true) || (flag1 = true))
          {
            previousMillis1 = currentMillis1;
            lcd.setCursor (0, 1);
            lcd.print("HIGH TEMP WARN!!");

            // do whatever else needs to be done during interval1
            
            if (message1 = true) {message1 = false;}
            else {message2 = true;
            flag1 = false; flag2 = true;}
            }
          if ((currentMillis2 - previousMillis2 >= interval2) && (message2 = true) || (flag2 = true))
          {
            previousMillis2 = currentMillis2;
            lcd.setCursor (0, 1); // go to start of 2nd line  
            lcd.print("I=");
            lcd.print(outcurr);
            lcd.print("A");
            lcd.print(" T2=");
            lcd.print(outtemp1);
            lcd.print("C");

            // do whatever else needs to be done during interval2
            
            if (message2 = true) {message2 = false;}
            else {message1 = true;
            flag2 = false; flag1 = true;}
            }
          
            
        }

        // ...lots of subsequent programming lines not relevant to this post..

}

You don't need two currentMillis.

I did not look properly at your code as I'm currently using a phone. But regarding the blink-without-delay, you can use a variable to hold the required delay and set the corrwxt delay depending on the state of the led (e.g 500ms when the led is on and 1000ms when the les is off and compare the difference between the current time and the previous time with the value stored in this variable.

You are making things much too complicated.

Start with the BWOD sketch. If the conditions that need the LED to flash are true then run that portion of code. When it comes time to change state of the LED then change the message to be printed too.

sterretje:
You don't need two currentMillis.

I did not look properly at your code as I'm currently using a phone. But regarding the blink-without-delay, you can use a variable to hold the required delay and set the corrwxt delay depending on the state of the led (e.g 500ms when the led is on and 1000ms when the les is off and compare the difference between the current time and the previous time with the value stored in this variable.

You are right, currentMillis is used independently in both cycles: I will use only one currentMillis

UKHeliBob:
You are making things much too complicated.

Start with the BWOD sketch. If the conditions that need the LED to flash are true then run that portion of code. When it comes time to change state of the LED then change the message to be printed too.

This is true if the duty cycles are identical. However, I need the ON interval different from the OFF interval which is not possible with the BWOD code of David straight away.

brice3010:
This is true if the duty cycles are identical. However, I need the ON interval different from the OFF interval which is not possible with the BWOD code of David straight away.

So change the period each time you change the state of the LED

brice3010:
This is true if the duty cycles are identical. However, I need the ON interval different from the OFF interval which is not possible with the BWOD code of David straight away.

As I indicated, keep a variable that can store the different delays for on and off :wink:

UKHeliBob:
So change the period each time you change the state of the LED

Like this?:

  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 == LOW) {
      ledState = HIGH;interval=interval1;
    } else {
      ledState = LOW;interval=interval2;
    }

Like this?:

it took you longer to post that than it would have taken to test it.

Groove:
it took you longer to post that than it would have taken to test it.

This can be said of half the forum, you must be a busy man.

I posted this 1. to have it scrutinized 2. for the benefit of others too

ledState = (HIGH + LOW) - ledState;
interval=(interval1 + interval2) - interval;

brice3010:
This can be said of half the forum

Sadly, yes.

Groove:

ledState = (HIGH + LOW) - ledState;

interval=(interval1 + interval2) - interval;

Great, I will test this; thks

Personally I would have put the two intervals in an array and used the LED state as an index to the active interval

UKHeliBob:
Personally I would have put the two intervals in an array and used the LED state as an index to the active interval

UKHeliBob, now I am puzzled, I need to look up on arrays (I have not yet used them), but I need a bit of clarification too on the second part of your sentence: can you give me a url or so where I can look this up please?

unsigned long intervals []  = {offTime, onTime};

This usage depends on LOW having the value zero, and HIGH having the value one.
You can pretty much bet that this will be true.

Groove:

unsigned long intervals []  = {offTime, onTime};

This usage depends on LOW having the value zero, and HIGH having the value one.
You can pretty much bet that this will be true.

Great, thks a lot! ..and meanwhile I did test your previous code but I do not understand the "HIGH + LOW" statement. I know them individually but not in this combination?

HIGH + LOW. == 1, in my arithmetic.

Groove:
HIGH + LOW. == 1, in my arithmetic.

AHHHH (big bright light shining) :wink:

Edit1: however, why would you add to logical constants?

They're not logical constants, they're simple integer literals