Blinking two LEDs in and out of phase

I would like to create the following:

Two led that can blink within in sync at a given interval but also to be out of small sync (around 50ms) once in few blinks/few seconds.

here is a behaviour I try to achive:

Both led are blinknig for 50ms ON state every 2000 ms and after a some time - lets say 10 blinks led1 will blink out of phase of 40 ms from led2 and both led will now be in an interval of 3000 ms between blinks, than, after another x number of seconds (or after a x number of blinks) both LED will be in sync again and will blink at the same time for the same interval duration..

I am looking to have the control both on the on Time duration and on the interval duration as well on the 'out of phase' length between the two leds.

here is the code I got:


const uint8_t led1 = 2;
const uint8_t led2 = 3;

uint32_t  previousMillis1 = 0;
uint32_t  previousMillis2 = 0;

const uint16_t  interval_led1 = 1000;
const uint16_t  interval_led2 = 1000;
const uint16_t onTime_led1 = 50;
const uint16_t onTime_led2 = 50;

bool ledState1 = LOW;
bool ledState2 = LOW;

void setup()
{
  pinMode(led1,OUTPUT);
  pinMode(led2,OUTPUT);
}

void loop()

{ 
  if (ledState1 == HIGH && millis() - previousMillis1 >= onTime_led1) // interval time has passed
  {
    previousMillis1 = millis(); //store the time now to be previous time
    ledState1 = LOW;
    digitalWrite(led1, ledState1);
  }


  if (ledState1 == LOW && millis() - previousMillis1 >= interval_led1) // interval time has passed
  {
    previousMillis1 = millis(); //store the time now to be previous time
    ledState1 = HIGH; // make LED HIGH
    digitalWrite(led1, ledState1);
  }

   if (ledState2 == HIGH && millis() - previousMillis2 >= onTime_led2) // interval time has passed
  {
    previousMillis1 = millis(); //store the time now to be previous time
    ledState2 = LOW;
    digitalWrite(led2, ledState2);
  }


  if (ledState2 == LOW && millis() - previousMillis2 >= interval_led2) // interval time has passed
  {
    previousMillis2 = millis(); //store the time now to be previous time
    ledState2 = HIGH; // make LED HIGH
    digitalWrite(led2, ledState2);
  }
}

while that code was working just fine for 1 LED I got the following problems with two LEDs:

  1. why I am looking for is not the code I have.
  2. although both led have the same onTime and interval duration they are not blinking in sync all.
  3. I have no control over a change in time - for example - to change the interval from 2000ms to 5000ms after 10 blinks and two get out of synch in 50ms between LEDs
  4. I repeat to many times the same code which I understand it is not good programming.

Any help will be greatful!
Thanks

I just answered a request for almost the same thing.
https://forum.arduino.cc/t/led-display-changes/908868/6

Which MCU are you using /are you using a 32 bit MCU?

I ask because if the MCU you are using is an ESP32, I'd take one route by using freeRTOS and it's sate machine capabilities to solve the problem. Which ever MCU you have your problem suits well for a state machine. Use search. Search on the words "state Machine".

not sure i understand

consider

byte ledPins [] = { 12, 13 };
#define N_LED   sizeof(ledPins)

enum { Off = HIGH, On = LOW };

unsigned long msecLst [N_LED];
unsigned long msecPh  [N_LED] = { 0, 100 };

#define Interval    1000
#define Width       50

void loop () {
    unsigned long msec = millis ();

    for (unsigned n = 0; n < N_LED; n++)  {
        if (msec > msecLst [n])  {
            byte st = digitalRead (ledPins [n]);
            digitalWrite (ledPins [n], ! st);

            if (Off == st)
                msecLst [n] = msec + Width;
            else
                msecLst [n] = msec + Interval - Width - msecPh [n];
        }
    }
}

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

    for (unsigned n = 0; n < N_LED; n++)  {
        digitalWrite (ledPins [n], Off);
        pinMode      (ledPins [n], OUTPUT);
    }
}
const byte led1 = 2;
const byte led2 = 3;

void blink(unsigned long onTime, unsigned long phaseDifference, unsigned long rate)
{
  if (phaseDifference < onTime)
  {
    digitalWrite(led1, HIGH);
    delay(phaseDifference);
    digitalWrite(led2, HIGH);
    delay(onTime - phaseDifference);
    digitalWrite(led1, LOW);
    delay(phaseDifference);
    digitalWrite(led2, LOW);
    delay(rate - (onTime + phaseDifference));
  }
  else
  {
    digitalWrite(led1, HIGH);
    delay(onTime);
    digitalWrite(led1, LOW);

    delay(phaseDifference - onTime);

    digitalWrite(led2, HIGH);
    delay(onTime);
    digitalWrite(led2, LOW);

    delay(rate - (onTime + phaseDifference));
  }
}

void setup()
{
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);

  // Both led are blinknig for 
  // 50ms ON state every 2000 ms
  // and after a some time - 
  // lets say 10 blinks
  for (int i = 0; i < 10; i++)
  {
    blink(50, 0, 2000);
  }

  // led1 will blink out of phase of 
  // 40 ms from led2 and both led will 
  // now be in an interval of 3000 ms
  // between blinks, than, after another 
  // x number of seconds (or after a x 
  // number of blinks)

  for (int i = 0; i < 10; i++)
  {
    blink(50, 40, 3000);
  }

  // both LED will be in sync again and 
  // will blink at the same time for the 
  // same interval duration..
  for (int i = 0; i < 10; i++)
  {
    blink(50, 0, 3000);
  }
}

void loop() {}

your code is working and I have two things I'm wonder about:

the code uses delay which might be a problem if I would like to add non blocking function late on.
Is it possible to convert it using millis() instead of delay?

Is it possible to also add the option that each LED will have is own interval time?

For example: both led are flashing in sync 50 ms on time over an interval of 2000 ms for 10 times, then both led are flashing 50ms on time out of phase of 50ms in interval of 3000ms, then each led is flashing 60 ms ,but led1 in interval of 4000ms 10 times and led10 flashing in intervals of 5000ms also 10 times,
then again both LED are flashing in sync at an interval of 2500ms etc etc

Is it possible to change the function blink to contain another variable input that will specify the number of repetition?

I'm using Arduino Uno

it seems that in the code you share you can define only one time the interval, the phase and the onTime? is that right?

so doing something like I wrote on post #6 is not possible?

Hello
You may post a timing diagram to see what shall happens.

No.
It can define the onTime and the offTime, but the phase is only controllable as zero or 180 degrees.
You can see the phase just sets the initial LED state. If you wanted to have the phase to take on more angles, you should change the value to a float and have it change the initial delay to the first transition rather that just set the first state change to the full off duration.

It might be if only I could actually understand what it actually meant.

The explanation just seems to ramble on a bit. Has this a practical use or is it a random exercise / assignment?

hi, what do you mean timing diagram?

A diagram that shows the led states versus time.

Something like this, which is just a random one I found and not meant to represent what you need:

image

And obviously you can have as many lines as you need, one for each output, showing how they relate to each other.

Perhaps you can use the code that @t_tuku and I collaborated on in this topic?

It allows you to write a list like below to control a pair of LEDs by specifying the on/off timing in detail:

  {HIGH, LOW,   30},
  {LOW,  LOW,   30},
  {HIGH, LOW,   30},
  {LOW,  LOW,   30+1000},
  {LOW, HIGH,   30},
  {LOW,  LOW,   30},
  {LOW, HIGH,   30},
  {LOW,  LOW,   30+1000},

Thanks for the suggestion! I will look into that
What does the +1000 means?

I might not explain myself as good.
by phase I meant how much time between led blinks will be the interval
so if both led are blinking in an intervals of 2000ms (50ms on state and the rest of 1950ms off)
after repetition of lets say 10 times led2 will blink the same as led1 but 50ms after led1. that will repeat several times then again both led will blink in sync

That's a good reason to use a timing diagram.

Here is time diagram: time diagram.pdf (51.5 KB)

pic:

1st section show that both led are blinking in sync at the Same interval of 1000ms

2nd section show both led are blinking at the same interval but 50ms apart.

3rd section show both led are again blinking in sync at 2000ms interval.

4rd section show each led is blinking at his own interval: led1 at 2000ms interval while led two at 3000ms interval

By phase we mean Phase
You can't just make up words and expect to be understood.
That would appear to be what everyone else calls the LED off Time

So 1 second on and 50ms off? If so you will never see it.
I ask again has this any practical use?

Hi, PaulB

so I took the code you shared and I modified it for my needs as much as I could:

const int led1 = 12;
const int led2 = 11;



byte counter;
byte OldCounter = 0;
unsigned long previousMillis = 0;





struct {
  byte led2;
  byte led1;
  int period;
} sequence[] = {

  {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
 

  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},



  {HIGH,HIGH,50},
  {LOW,  LOW,  2000},
  {HIGH,LOW,50},
  {LOW,  LOW,  1000},
  {LOW,HIGH,50},
  {LOW,  LOW,  1000},
  {HIGH,LOW,50},
  {LOW,  LOW,  2000},
  {HIGH,HIGH,50},
  {LOW,  LOW,  1000},
  


}; // END STRUCTURE

int step;
unsigned long lastChange;

void Flasher(int first, int last) {
  if (step < first || step > last || millis() - lastChange >= sequence[step].period) {
    /* move to next step */
    step++;
    if (step < first || step > last) step = first;
    /* Update Leds */
    digitalWrite(led2, sequence[step].led2);
    digitalWrite(led1, sequence[step].led1);
    lastChange = millis();
  }
}

void setup()
{
  pinMode(led2, OUTPUT);
  pinMode(led1, OUTPUT);

  Serial.begin(9600);
}

void loop()
{
  OldCounter = counter;
  switch (OldCounter)
  {
    default: Flasher(0, 50); Serial.println("Default"); break;
  }
  

 

}

it seems to work fine, but I wonder:

In order to repeat a sequence of the same interval like this:


  {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},
   {HIGH, HIGH, 50},
  {LOW,  LOW,  2000},

I needed to type the same line over and over again.
that's true also for the following section:

{HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},
  {HIGH, LOW, 50},
  {LOW, HIGH, 50},
  {LOW,  LOW,  2000},

the last section I wrote is in order to have each led blink independently at is own time interval:

  {HIGH,HIGH,50},
  {LOW,  LOW,  2000},
  {HIGH,LOW,50},
  {LOW,  LOW,  1000},
  {LOW,HIGH,50},
  {LOW,  LOW,  1000},
  {HIGH,LOW,50},
  {LOW,  LOW,  2000},
  {HIGH,HIGH,50},
  {LOW,  LOW,  1000},
  

this method seems more complicated for that task. is there any other way of doing so?
Also, - how can I make the sequence in that struct to repeat itself? right now, after it finished is struct both LED are stuck on HIGH position.

another thing I noticed: the sequence start only from the 2nd row and not from the 0 index row.