Help to synchronize two blinking LEDs using millis with pattern

Hello, I want to make navigation lights to my drone. I make it work using delay, but the delay function stop all other code running. So I need to make this happen without using delay.

Wanted function:

  1. LED 1: blink twice (100ms on, 200ms of, while LED 2 is off.
  2. Delay time 1000ms between LED 1 and LED2.
  3. LED 2: blink once while LED 1 have blinked two times.

I`m new to programming and have tried to make it happen using counter, if/and operators and handling the sequence with +- millis time. But I do not get it to work.

Can someone give me some pointers? or share some code? :slight_smile:

This is the code that I have modified without success:

Can someone give me some pointers?

Take a look at Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

Blinkwithout delay code is all fine.

My problem is, I need somehow to stop LED 1 stop blinking while LED 2 start to blink. What is the best strategy? Maybe this is done before in a example?

If you think about it each of the 2 LEDs simply have their own flash pattern implemented as separate BWoD "timers"

I am not clear exactly what the blink pattern should be for LED1 in relation to LED1 but here is my best guess

//1. LED 1: blink twice (100ms on, 200ms of, while LED 2 is off.
//2. Delay time 1000ms between LED 1 and LED2.
//3. LED 2: blink once while LED 1 have blinked two times.

unsigned long currentTime;
unsigned long blink1StartTime;
unsigned long blink2StartTime;

const unsigned long blink1Periods[] = {100, 200, 100, 200, 1000};
const byte blink1States[] = {LOW, HIGH, LOW, HIGH, HIGH};
const unsigned long blink2Periods[] = {300, 300, 1000};
const byte blink2States[] = {HIGH, LOW, HIGH};

byte blink1Index = 0;
byte blink2Index = 0;
const byte led1Pin = 3;
const byte led2Pin = 5;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  digitalWrite(led1Pin, HIGH);
  digitalWrite(led2Pin, HIGH);
}

void loop()
{
  currentTime = millis();
  blink1();
  blink2();
}

void blink1()
{
  if (currentTime - blink1StartTime > blink1Periods[blink1Index])
  {
    digitalWrite(led1Pin, blink1States[blink1Index]);
    blink1StartTime = currentTime;
    blink1Index++;
    if (blink1Index == sizeof(blink1States))
    {
      blink1Index = 0;
    }
  }
}

void blink2()
{
  if (currentTime - blink2StartTime > blink2Periods[blink2Index])
  {
    digitalWrite(led2Pin, blink1States[blink2Index]);
    blink2StartTime = currentTime;
    blink2Index++;
    if (blink2Index == sizeof(blink2States))
    {
      blink2Index = 0;
    }
  }
}

The code uses arrays to hold the required periods and associated states which may look complicated but it makes it easier to change because the program is driven by that data so to change the blink patters and timing the program does not have to be changed

Note that I have assumed that outputting LOW turns on an LED, which is what I normally do, but if your system needs HIGH to turn on an LED then invert the states in the arrays to suit

Yes!!! after some modification for my project, I got it to work. Thank you! Karma!+++ :slight_smile:

Good news that you got it to work. If you have any questions about how my example works then I will talk you through it

Hello, after some hours of testing, it seems like the intervalls drift. I think this may a result of the controller processing time, i.e. the time between blinkstate1 and blinkstate2. (I use 72MHz STM32 bluepill).

In the start, the intervall between LED1 and LED2 is fine. After 30 minutes, I can clearly see that they aproach each other and drift away again, as a sine function.

Q: Is there a way to mitigate this? :slight_smile:

Is there a way to mitigate this?

With independent timing of the two LEDs there is always a danger of them drifting, not least because the processor is doing other things behind then scenes that might cause a problem

One small improvement would be to write the update to the next blink differently, like this

void blink1()
{
  if (currentTime - blink1StartTime > blink1Periods[blink1Index])
  {
    digitalWrite(led1Pin, blink1States[blink1Index]);
    blink1StartTime = blink1StartTime + blink1Periods[blink1Index];
    blink1Index++;
    if (blink1Index == sizeof(blink1States))
    {
      blink1Index = 0;
    }
  }
}

Doing it this way avoids using currentTime to calculate the time that the period starts by calculating it based on the previous start time plus the previous interval

Another approach would be to build a table holding the state of both LEDs showing when either of them change state and the time at which they entered the new state

I never really made sense of your original description

//1. LED 1: blink twice (100ms on, 200ms of, while LED 2 is off.
//2. Delay time 1000ms between LED 1 and LED2.
//3. LED 2: blink once while LED 1 have blinked two times.

Number 1 I understand, but is there then a 1000 mS delay before LED 2 blinks once and the pattern repeats or some other requirement ? How long is LED 2 turned on when it blinks. I assume that LED 1 is never on when LED 2 is on. Is that right ?

Please post your code as it is now as it will give some clues as to what you want to do

An alternative approach that is guaranteed to keep the LEDs in step as long as you set the data up correctly

const byte ON = LOW;  //change to suit target system
const byte OFF = HIGH;

struct dataFormat
{
  unsigned long period; //period for this stage
  byte led1State; //led 1 stage for this stage
  byte led2State; //led 2 state for this stage
};

dataFormat ledData[] =
{
  {500, ON, OFF},   //led 1 on/led 2 off for 500
  {500, OFF, OFF},  //led 1 off for 500, led 2 off for 500
  {500, ON, ON},    //led 1 on for 500, led 2 on for 500
  {500, OFF, ON},    //led 1 off 500, led 2 on for 500
  {1000, OFF, OFF},  //both off for 1000
  {100, ON, ON},   //both on for 100
  {1000, OFF, OFF}  //both off for 1000

};

const byte NUMBER_OF_STAGES = sizeof(ledData) / sizeof(ledData[0]);

byte stage = 0;
const byte led1Pin = 3;
const byte led2Pin = 5;
unsigned long stageStart;
unsigned long currentTime;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  digitalWrite(led1Pin, ledData[stage].led1State);
  digitalWrite(led2Pin, ledData[stage].led2State);
  stageStart = millis();
}

void loop()
{
  currentTime = millis();
  if (currentTime - stageStart >= ledData[stage].period)
  {
    stageStart = stageStart + ledData[stage].period;
    stage++;
    stage = stage % NUMBER_OF_STAGES; //wrap around after all stages
    digitalWrite(led1Pin, ledData[stage].led1State);
    digitalWrite(led2Pin, ledData[stage].led2State);
  }
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.