timing 2 LED blink rates

Hey All,

I'm struggling to get this to work out correctly. I'm creating a program for a star trek model and trying to figure out led blinking to work properly.

Here is the layout and time table.

LED on pin 12 flashes in the following manner: ON for 150 ms, OFF for 150 ms, on for 150 ms... Repeat ever 2 seconds.

So doing the math, there is 1550 ms for the second strobe. I'm trying to get the LED to light up for 150 ms right at 700 ms after LED 12 turns off (1550/2 - 150/2 = 700 ms). But I'm just having a terrible time and have been trying for a while.

I'll fully accept the mantle of bad programmer if someone can help me out. :wink:

Here is the code.

/*     Variables     */
// Fast Strobes variables
const int pin_FastStrobes =  12;      // the number of the LED pin
int state_FastStrobes = LOW;             // state_FastStrobes used to set the LED
int counter_FastStrobes = 0;
unsigned long time_FastStrobes_1 = 0;
unsigned long timer_FastStrobes_1 = 0;        // will store last time LED was updated
unsigned long timer_FastStrobes_2 = 0;        // will store last time LED was updated
const long interval_FastStrobes_1 = 150;           // interval_FastStrobes_1 at which to blink (milliseconds)
const long interval_FastStrobes_2 = 2000;           // interval_FastStrobes_1 at which to blink (milliseconds)

// Slow Strobes variables
const int pin_SlowStrobes = 11; // Slow Strobe Pin
unsigned long time_SlowStrobes = 0;
int state_SlowStrobes = LOW;
unsigned long timer_SlowStrobes = 0;
unsigned long SlowStrobes_timeoff = 725;
unsigned long SlowStrobes_time_on = 150;

// Setup The Environment
void setup() {
  pinMode(pin_SlowStrobes, OUTPUT);
  digitalWrite(pin_SlowStrobes, LOW);
  pinMode(pin_FastStrobes, OUTPUT);  
  digitalWrite(pin_FastStrobes, LOW);
  Serial.begin(9600); // open the serial port at 9600 bps:
}

/*     Main Program     */
void loop() {
  // Slow Strobes
  // Fast Strobes
  unsigned long time_FastStrobes = millis();  //  Get the current system uptime for Fast Strobes
  time_FastStrobes_1 = millis();
  if (time_FastStrobes_1 - timer_FastStrobes_1 >= interval_FastStrobes_1) {
    if (counter_FastStrobes <= 3) subroutine_FastStrobes_1() ;
    else subroutine_FastStrobes_2() ;
  }
  // Phasers
  // Photon Torpedos
  
}

/*     Subroutines     */
// Fast Strobe Subroutines
void subroutine_FastStrobes_1() {
  timer_FastStrobes_1 = time_FastStrobes_1;
  if (state_FastStrobes == LOW) {
    state_FastStrobes = HIGH;
    counter_FastStrobes++;
  } else {
    state_FastStrobes = LOW;
    counter_FastStrobes++;
  }
  digitalWrite(pin_FastStrobes, state_FastStrobes);
}

void subroutine_FastStrobes_2(){
  unsigned long time_FastStrobes_2 = millis();
  state_FastStrobes = LOW;
  if (time_FastStrobes_2 - timer_FastStrobes_2 >= interval_FastStrobes_2) {
    timer_FastStrobes_2 = time_FastStrobes_2;
    time_SlowStrobes = time_FastStrobes_2;
    subroutine_SlowStrobes();
    counter_FastStrobes = 0;
  }
}

// Slow Strobe Subroutine
void subroutine_SlowStrobes(){
  if(time_SlowStrobes > timer_SlowStrobes + SlowStrobes_timeoff) {
    if(time_SlowStrobes > timer_SlowStrobes + SlowStrobes_time_on) {
      digitalWrite(pin_SlowStrobes, HIGH);
    }
    digitalWrite(pin_SlowStrobes, LOW);
    timer_SlowStrobes = time_SlowStrobes;
  }

}

Start by getting ONE copy of millis() at the start of loop:

now = millis();

Use that for all your timing everywhere. Do not read millis() again until next time through loop.
If you feel you need to you are doing something wrong.

That is too much code for just a sequence of two leds.

When two leds need to blink independent of each other, then you need two millis-timers.
When two leds run a certain sequence for both, then you need only one millis-timer.

Can you draw (in a picture or on paper) when a led is on and off ? Or a link to a video or website that shows it. I don't understand that part.
You don't have to do the blinking of the second led in the 1550 ms. You can turn on an off any led at any moment, either a sequence tied to each other or completely independent of each other.

For fun, I did a test and was able to make 27000 millis-timers running at the same time (and you need probably just one :wink: ).

Led "FastStrobes" on pin 12 : on - 150ms - off - 150ms - on - 150ms - off - 1550ms
Led "SlowStrobes" on pin 11 : off - 1150ms - on - 150ms - off - 700ms.

I watched a number of Youtube videos, but I can not find that blinking pattern in relation with Star Trek. Do you really want to keep the "FastStrobes" off for 1550 ms ?

chipnod2020:
LED on pin 12 flashes in the following manner: ON for 150 ms, OFF for 150 ms, on for 150 ms... Repeat ever 2 seconds.

So doing the math, there is 1550 ms for the second strobe. I'm trying to get the LED to light up for 150 ms right at 700 ms after LED 12 turns off (1550/2 - 150/2 = 700 ms). But I'm just having a terrible time and have been trying for a while.

I can't figure out the desired blink pattern from your description.
It looks like you want Pin 12 to:
On, then off at 150, on at 300, off at 450... Then what? You put "..." and then something about 2 seconds?!? Did you mean for the pattern to repeat? On at 600? Off at 750? On at 900? ... That would give you 6 and 2/3rds cycles in 2 seconds.
What do you mean by "right at 700 ms after LED 12 turns off"? With a 300 ms cycle (150 on, 150 off) the LED on Pin 12 would not be off at 700 ms. It would be turning on at 600 and off at 750.

You can refer to this code to blink multiple LED without caring about timestamp

[size=0.8em]Code: [url=https://arduinogetstarted.com/tools/arduino-code-highlighter]see how to post code[/url] [/size]

---



```
[size=0.8em]/*
* Created by ArduinoGetStarted.com
*
* This example code is in the public domain
*
[color=#95a5a6] * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-output-library[/color]
*
* This example blinks 3 LED:
* + with diffent frequencies
* + start blink at the same time
* + without using delay() function. This is a non-blocking example
*/

#include <ezOutput.h> // ezOutput library

ezOutput led1(7);  // create ezOutput object that attach to pin 7;
ezOutput led2(8 );  // create ezOutput object that attach to pin 8;
ezOutput led3(9);  // create ezOutput object that attach to pin 9;

void [color=#5E6D03]setup/color {
  led1.blink(500, 250); // 500 milliseconds ON, 250 milliseconds OFF
  led2.blink(250, 250); // 250 milliseconds ON, 250 milliseconds OFF
  led2.blink(100, 100); // 100 milliseconds ON, 100 milliseconds OFF
}

void [color=#5E6D03]loop/color {
  led1.[color=#5E6D03]loop/color; // MUST call the led1.loop() function in loop()
  led2.[color=#5E6D03]loop/color; // MUST call the led2.loop() function in loop()
  led3.[color=#5E6D03]loop/color; // MUST call the led3.loop() function in loop()
}[/size]
```

|

Thanks All! You are 100% right, I am over complicating it hence why I seek wisdom. :slight_smile:

Great Advise on taking the time once and using it. I will modify it.

Pictures make life easier. This is what I'm trying to accomplish. Yellow is on, grey is off.


LED Timetable

For context, refer to the movie Star Trek (2009). The saucer of the Enterprise has 2 strobes that blink in quick succession, then stay off. Some of the other strobes blink once.

The pattern is clear now. Thanks for the diagram.

unsigned long StartTime = 0


void setup()
{
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
}


void loop()
{
  unsigned long now = millis();
  
  if (now - StartTime >= 2000) // Restart every 2 seconds.
  {
    StartTime += 2000;
  }
  
  unsigned long timeInPattern = now - StartTime;
  digitalWrite(12, timeInPattern < 150 || (timeInPattern >= 300 && timeInPattern < 450));
  digitalWrite(11, timeInPattern >= 1150 && timeInPattern < 1300);
}

This takes advantage of the fact that 'true'==HIGH and 'false'==LOW on almost all Arduinos.

This code uses millis() to cycle through an array of time intervals. Just make two arrays, one for each LED, and populate the arrays with the cycle times you posted.

// yet another blink sketch by aarg, Arduino forum
//
// circular list of intervals, alternating off and on
unsigned long intervals[] = {500, 500};
const byte NUM_OF_INTERVALS = sizeof(intervals) / sizeof(unsigned long);
byte currentInterval = 0;

unsigned long previousMillis = 0;
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();          //get current value of millisecond counter
  if (currentMillis - previousMillis >= intervals[currentInterval])  //if the time interval has elapsed
  {
    currentInterval = currentInterval + 1;     // select the next interval in the list
    if (currentInterval >= NUM_OF_INTERVALS)
      currentInterval = 0;
    digitalWrite(LED_BUILTIN, not digitalRead(LED_BUILTIN));    //change state of the LED
    previousMillis = currentMillis;                //save the time of change
  }
}

As many blinks of as many LEDs with as many periods of as many lengths as you like controlled by entries in an array

const byte ledPins[] = {3,5,6,9};
const byte NUMBER_OF_LEDS = sizeof(ledPins);
unsigned long startTimes[NUMBER_OF_LEDS] = {};
byte indexes[NUMBER_OF_LEDS] = {0};
const byte MAX_NUMBER_OF_PERIODS = 10;
unsigned long periods[][MAX_NUMBER_OF_PERIODS] =    //periods for each LED.  zero indicates end of sequence
{
  {1000, 2000, 1500, 2500, 0},
  {500, 200, 1000, 2000, 3000, 4000, 0},
  {400, 1000, 1500, 2000, 0},
  {1100, 2200, 0}
};

void setup()
{
  Serial.begin(115200);
  for (int led = 0; led < NUMBER_OF_LEDS; led++)
  {
    pinMode(ledPins[led], OUTPUT);
  }
}

void loop()
{
  unsigned long currentTime = millis();
  for (int led = 0; led < NUMBER_OF_LEDS; led++)  //iterate through the LEDs
  {
    if (currentTime - startTimes[led] >= periods[led][indexes[led]])  //? time to change ?
    {
      digitalWrite(ledPins[led], !digitalRead(ledPins[led]));  //flip led state
      startTimes[led] = currentTime;  //save start time of state
      indexes[led]++;                    //increment index
    }
    if (periods[led][indexes[led]] == 0)  //if next period is zero (end of sequence)
    {
      indexes[led] = 0;        //reset period index for this LED
    }
  }  //end for loop
}

Thanks all for the great responses!!

I have gone with johnwassers's answer with a little modification using variables. This way I can change 2 variables and the entire sequence will act differently.

/*     Variables     */
const int pin_FastStrobes = 12; // Fast Strobes LEDs
const int pin_SlowStrobes = 8; // Slow Strobes LEDs
unsigned long timer_Strobeloop = 0;
int var1 = 150;  // How long should a strobe be on?
int var2 = 2000; // How long is the strobe loop?
int for1 = ((var2-var1*3)/2 - (var1/2))+var1*3; // Formula to make editing values much easier

void setup() {
  pinMode(pin_FastStrobes, OUTPUT); // Fast Strobes
  pinMode(pin_SlowStrobes, OUTPUT); // Slow Strobes
}

void loop() {
  unsigned long now = millis();
  // --- Strobe Lights
  if (now - timer_Strobeloop >= var2) { // Restart every 2 seconds.
    timer_Strobeloop += var2;
  }
  unsigned long timeInPattern = now - timer_Strobeloop;
  digitalWrite(pin_FastStrobes, timeInPattern < var1 || (timeInPattern >= var1*2 && timeInPattern < var1*3));
  digitalWrite(pin_SlowStrobes, timeInPattern >= for1 && timeInPattern < for1+var1);
}

I give you some credit if it works, but it's "too clever". It's much easier to understand and edit a simple table, than a set of logical expressions that have inputs that change fairly opaquely with time.

Thanks aarg...

So for example, how would you set the array up for 150 ms on, 150 ms off, 150 ms on, and 1550 off, then repeat?

I've tried this, but it acts weird and turns on for 1550ms a few times.

unsigned long intervals[] = {150, 150, 150, 1550};

Let me just add one more method for the issue at hand, one that doesn't really deal with elapsed time triggering a counter like

if (currentMillis - previousMillis >= intervals[currentInterval])  //if the time interval has elapsed
  {
    currentInterval = currentInterval + 1;     // select the next interval in the list

but rather uses the '%' modulo (this thread wouldn't be complete without it.)

#define CYCLE 2000

const uint8_t 
  fastPin = 12,
  slowPin = 11;

void setup() {
  pinMode(fastPin, OUTPUT);
  pinMode(slowPin, OUTPUT);
}

void loop() {
  uint32_t moment = millis();
  moment = moment % CYCLE;
  uint8_t fastS = moment / 150;
  if ((fastS < 3) && (!(fastS % 2))) {  // less that 450ms
    digitalWrite(fastPin, HIGH);     // and  0 == On
  }
  else {
    digitalWrite(fastPin, LOW);
  }
  if ((moment >= 1150) && (moment < 1300))  {  
    digitalWrite(slowPin, HIGH); 
  }
  else {
    digitalWrite(slowPin, LOW);
  }

or for the other led

moment = moment - 1150;
  if (! moment / 150)  {  
    digitalWrite(slowPin, HIGH); 
  }
  else {
    digitalWrite(slowPin, LOW);
  }

Which i think is even better.

This takes advantage of the fact that 'true'==HIGH and 'false'==LOW on almost all Arduinos.

I agree with that as a method, but some elaboration (eh 'almost' ? ) 'false and true are boolean operators, for (false) to be 'true' (hehe) all bits need to be 'off'. A boolean variable that is 'true' is stored as a '1'. HIGH & LOW are defined as literals '1' & '0' (and since they come without any specifier they will be generated as integers, which is also what digitalWrite() takes as an argument. This is what i understood from the last conversation i had about this.

chipnod2020:
Thanks aarg...

So for example, how would you set the array up for 150 ms on, 150 ms off, 150 ms on, and 1550 off, then repeat?

I've tried this, but it acts weird and turns on for 1550ms a few times.

unsigned long intervals[] = {150, 150, 150, 1550};

I forgot to set the initial state:

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);    //initial state of the LED
}

Set HIGH if the first interval array element is supposed to trigger a LOW state. Tested, works now. @UKHeliBob's code is more developed and flexible, it's based on the same idea. Mine is a basic demo, just to get started.

Hey Aarg,

One last one. I'm getting just a small flicker of the slow led for the first array element. Is there a way to have an array index as a null value versus entering 0?

i.e. Array array_SlowStrobes element 0 = null value?

// Definitions
// inter - Interval Value
// civ - Current Interval Value
// pin - Assigned Pin
// pmillis - Previous millis for a certain set of loop functions
// array - Array of values

// Fast Strobes Setup
const int pin_FastStrobes = 13; // Fast Strobes LEDs
unsigned long array_FastStrobes[] = {150 , 150 , 150 , 1550}; // adds up to 2000
const byte interval_FastStrobes = sizeof(array_FastStrobes) / sizeof(unsigned long);
byte civ_FastStrobes = 0;
unsigned long pmillis_FastStrobes = 0;

// Slow Strobes Setup
const int pin_SlowStrobes = 12; // Slow Strobes LEDs
unsigned long array_SlowStrobes[] = {0, 1150, 150 , 700}; // adds up to 2000
const byte interval_SlowStrobes = sizeof(array_SlowStrobes) / sizeof(unsigned long);
byte civ_SlowStrobes = 0;
unsigned long pmillis_SlowStrobes = 0;


void setup()
{
  pinMode(pin_FastStrobes, OUTPUT);
  pinMode(pin_SlowStrobes, OUTPUT);
  digitalWrite(pin_FastStrobes, HIGH);    //initial state of the LED
  digitalWrite(pin_SlowStrobes, HIGH);    //initial state of the LED
}

void loop()
{
  unsigned long now = millis(); // Get current value of millisecond counter
  // Fast Strobes
  if (now - pmillis_FastStrobes >= array_FastStrobes[civ_FastStrobes])  //if the time interval has elapsed
  {
    civ_FastStrobes = civ_FastStrobes + 1;     // select the next interval in the list
    if (civ_FastStrobes >= interval_FastStrobes)
      civ_FastStrobes = 0;
    digitalWrite(pin_FastStrobes, not digitalRead(pin_FastStrobes));    //change state of the LED
    pmillis_FastStrobes = now;                //save the time of change
  }
  // Slow Strobes
  if (now - pmillis_SlowStrobes >= array_SlowStrobes[civ_SlowStrobes])  //if the time interval has elapsed
  {
    civ_SlowStrobes = civ_SlowStrobes + 1;     // select the next interval in the list
    if (civ_SlowStrobes >= interval_SlowStrobes)
      civ_SlowStrobes = 0;
    digitalWrite(pin_SlowStrobes, not digitalRead(pin_SlowStrobes));    //change state of the LED
    pmillis_SlowStrobes = now;                //save the time of change
  }
}

You can't have a duration of zero. The slow strobe really has only two phases, so the array should only contain two entries. There is a time offset, so FastStrobes has to be initialized to 850ms in advance, I made both changes below. See if it works...

// Definitions
// inter - Interval Value
// civ - Current Interval Value
// pin - Assigned Pin
// pmillis - Previous millis for a certain set of loop functions
// array - Array of values

// Fast Strobes Setup
const int pin_FastStrobes = 13; // Fast Strobes LEDs
unsigned long array_FastStrobes[] = {150 , 150 , 150 , 1550}; // adds up to 2000
const byte interval_FastStrobes = sizeof(array_FastStrobes) / sizeof(unsigned long);
byte civ_FastStrobes = 0;
unsigned long pmillis_FastStrobes = 850;

// Slow Strobes Setup
const int pin_SlowStrobes = 12; // Slow Strobes LEDs
unsigned long array_SlowStrobes[] = {150 , 1850}; // adds up to 2000
const byte interval_SlowStrobes = sizeof(array_SlowStrobes) / sizeof(unsigned long);
byte civ_SlowStrobes = 0;
unsigned long pmillis_SlowStrobes = 0;


void setup()
{
  pinMode(pin_FastStrobes, OUTPUT);
  pinMode(pin_SlowStrobes, OUTPUT);
  digitalWrite(pin_FastStrobes, HIGH);    //initial state of the LED
  digitalWrite(pin_SlowStrobes, HIGH);    //initial state of the LED
}

void loop()
{
  unsigned long now = millis(); // Get current value of millisecond counter
  // Fast Strobes
  if (now - pmillis_FastStrobes >= array_FastStrobes[civ_FastStrobes])  //if the time interval has elapsed
  {
    civ_FastStrobes = civ_FastStrobes + 1;     // select the next interval in the list
    if (civ_FastStrobes >= interval_FastStrobes)
      civ_FastStrobes = 0;
    digitalWrite(pin_FastStrobes, not digitalRead(pin_FastStrobes));    //change state of the LED
    pmillis_FastStrobes = now;                //save the time of change
  }
  // Slow Strobes
  if (now - pmillis_SlowStrobes >= array_SlowStrobes[civ_SlowStrobes])  //if the time interval has elapsed
  {
    civ_SlowStrobes = civ_SlowStrobes + 1;     // select the next interval in the list
    if (civ_SlowStrobes >= interval_SlowStrobes)
      civ_SlowStrobes = 0;
    digitalWrite(pin_SlowStrobes, not digitalRead(pin_SlowStrobes));    //change state of the LED
    pmillis_SlowStrobes = now;                //save the time of change
  }
}

Notice that UKHelibob's sketch has start times for every counter. This is why.