Blinking 3 leds concurrently and independently?

Is it possible to blink 3 leds at the same time but all 3 leds blinks at different rates?

Yes.

Do a site search on things like "blink without delay" or "using millis".

millis() timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

1 Like

The initial examples delivered with the arduino-IDE IMO are leading newcomers to a wrong way how coding on a microcontroller works.
Because these inital examples use the command delay()

Jump over delay(). delay is delaying your progress in learning how real programming works.
Of course there are different ways how different people learn.
Some with reading, some with videos. Just to extend the ways how to learn it

non-blocking timing enables to have hundreds of things each "blinking" independently from all others. Non-blocking timing is based on the function millis().

These two videos explain non-blocking timing based on function millis()

best regards Stefan

Of course you could do with millis() directly.
But I maybe more easy to use a library :wink:
Here is an example of my MobaTools library, that does what you want with 2 leds. It should be easy to extend to 3 leds.
( the original example in the lib is commented in german)

#include <MobaTools.h>
/* Demo: Time delays without delay command.
In principle, the 'MoToTimer' works like a kitchen timer.
kitchen: you wind it up to a certain time, and then it runs 
back to 0. Unlike the kitchen alarm clock, however, it does not ring.
You have to check cyclically to see if the time has elapsed. But that fits
perfectly with the principle of the 'loop', i.e. an endless loop in which one
cyclically queries for events.
Method calls:
MoToTimer.setTime( long Runtime ); sets the time in ms
bool = MoToTimer.running(); == true as long as the time is still running, 
                            == false when expired
                                 
In contrast to the procedure with delay(), this allows for several
independent and asynchronous cycle times.
In this demo 2 leds are flashing with different clock rates


*/

const int led1P =  5; 
const int led2P =  6; 

MoToTimer flashTime1;
MoToTimer flashTime2;

void setup() {
    pinMode(led1P, OUTPUT); 
    pinMode(led2P, OUTPUT);
}

void loop() {
    // -------- Blinking of the 1st Led ------------------
    // This led flashes with a non-symmetrical clock ratio
	if ( flashTime1.running()== false ) {
        // Flashing time expired, toggle output and rewind time
        if ( digitalRead( led1P ) == HIGH ) {
            digitalWrite( led1P, LOW );
            flashTime1.setTime( 600 );
       } else {
            digitalWrite( led1P, HIGH );
            flashTime1.setTime( 300 );
        }
	}
   
    // -------- Blinking of the 2nd Led ------------------
    // This led flashes symetrically
    if ( flashTime2.running() == false ) {
        // Flashing time expired, toggle output and rewind time
        if ( digitalRead( led2P ) == HIGH ) {
            digitalWrite( led2P, LOW);
        } else {
            digitalWrite( led2P, HIGH);
        }
        flashTime2.setTime( 633 );
    }
}

However, the advices how to write non blocking code are important in any case.

Yes it is possible. Make per LED an object containing the information about the pin port address and the timing information. The BWOD example from the IDE is used to process the timing information from the object.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  https://forum.arduino.cc/t/blinking-3-leds-concurrently-and-independently/919646
*/
#define ProjectName "Blinking 3 leds concurrently and independently?"
// hardware and timer settings
constexpr byte LedOnePin {2};        // portPin o---|220|---|LED|---GND
constexpr byte LedTwoPin {3};        // portPin o---|220|---|LED|---GND
constexpr byte LedThreePin {4};      // portPin o---|220|---|LED|---GND
struct GROUP {
  byte pin;
  unsigned long stamp;
  unsigned long duration;
} groups[] {
  {LedOnePin, 0, 1000},
  {LedTwoPin, 0, 1333},
  {LedThreePin, 0, 2222},
};
unsigned long currentTime;

// ------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
   for (auto group : groups) pinMode(group.pin, OUTPUT);
  // check outputs
  for (auto group : groups) digitalWrite(group.pin, HIGH), delay(1000);
  for (auto group : groups) digitalWrite(group.pin, LOW), delay(1000);
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  for (auto &group : groups) {
    if (currentTime-group.stamp>=group.duration) {
      group.stamp=currentTime;
      digitalWrite(group.pin,!digitalRead(group.pin));
    }
  }
}

Have a nice day and enjoy coding in C++.

My "2-cents"...

I'm not going to write the code but this isn't too hard if you understand how Blink Without Delay works. You can start with Blink Without Delay and make some modifications to add one LED, then another.

You're going to need 3 if-statements/structures, one for each LED.

You'll also need a few separate variables for each LED to keep track of the 3 on/off states and the 3 times... These are variables that you define.

Of course, there is only one currentMillis.

But instead of ledState we can have ledState1, ledState2, and ledState3. (Or if you have different color LEDs you can have RedState, BlueState, GreenState, or whatever is the most descriptive.)

Instead of Interval we can have Interval1, Interval2, Interval3.

Finally we need previousMillis1, previousMillis2, previousMillis3.

1 Like

My take (unless I misunderstand the requirement). Super simple use of BWOD and Several things at a time..

const byte redPin = 4;
const byte bluePin = 5;
const byte greenPin = 6;

unsigned long redInterval = 500;
unsigned long blueInterval = 100;
unsigned long greenInterval = 2000;

unsigned long currentMillis = 0;

void setup()
{
   Serial.begin(115200);
   pinMode(redPin, OUTPUT);
   pinMode(bluePin, OUTPUT);
   pinMode(greenPin, OUTPUT);
}

void loop()
{
   currentMillis = millis();
   flashRed();
   flashBlue();
   flashGreen();
}

void flashRed()
{
   static unsigned long timer = 0;   
   if (currentMillis - timer >= redInterval)
   {
      timer = currentMillis;
      digitalWrite(redPin, !digitalRead(redPin));
   }
}

void flashBlue()
{
   static unsigned long timer = 0;   
   if (currentMillis - timer >= blueInterval)
   {
      timer = currentMillis;
      digitalWrite(bluePin, !digitalRead(bluePin));
   }
}

void flashGreen()
{
   static unsigned long timer = 0;   
   if (currentMillis - timer >= greenInterval)
   {
      timer = currentMillis;
      digitalWrite(greenPin, !digitalRead(greenPin));
   }
}

Wow! Thank you so much for the replies. I will read everyone’s comment slowly and test it out and upload the result when I am free! :slight_smile:

consider a more generic approach

struct Led  {
    const byte          Pin;
    const unsigned long Period;
    unsigned long       msecLst;
} leds [] = {
    { 10, 150 },
    { 11, 300 },
    { 12, 400 },
    { 13, 550 },
};

const int N_LEDS = sizeof(leds) / sizeof(Led);

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

    Led  *p = leds;
    for (unsigned n = 0; N_LEDS > n; n++, p++)  {
        if ( (msec - p->msecLst) > p->Period)  {
            p->msecLst = msec;
            digitalWrite (p->Pin, ! digitalRead (p->Pin));
        }
    }
}

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

    for (unsigned n = 0; N_LEDS > n; n++)
        pinMode (leds [n].Pin, OUTPUT);
}

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