Blink Two LEDs, independent, no delay

Some of the frequent contributors thought this might be a good example - for when the tutorial "Blink without Delay" example is not enough

/* Multiple independent delay - Two blinking LEDs

Working code example that blinks two LEDs, each with its own independent period.
This extends the BlinkWithoutDelay example of a single LED, showing how to
implement multiple independent timing paths in the main loop.

Written by several forum members. In public domain.  Oct 2011.

Note: works even when millis () wraps around to zero after approximately 50 days.
*/

// Which pins are connected to which LED
const byte greenLED = 8 ;
const byte redLED = 10 ;

// Time periods of blinks in milliseconds (1000 milliseconds to a second).
// Time variable and constants are always unsigned long
const unsigned long greenLEDinterval = 555UL ;
const unsigned long redLEDinterval = 1234UL ;

// Variable holding the timer value so far. One for each "Timer"
unsigned long greenLEDtimer = 0 ;
unsigned long redLEDtimer = 0 ;

// Variable to know what the current LED state is
int greenLEDState = LOW ;
int redLEDState = LOW ;

void setup() {
  pinMode (greenLED,OUTPUT) ;
  pinMode (redLED,OUTPUT) ;
  greenLEDtimer = millis () ;
  redLEDtimer = millis () ;
}

void loop() {

// Handling the blink of one LED.
// First, check if it is time to change state
  if ( (millis () - greenLEDtimer) >= greenLEDinterval ) {
    // It is time to change state. Calculate next state.
    if (greenLEDState == LOW)
      greenLEDState = HIGH ;
    else
      greenLEDState = LOW ;
    // Write new state
    digitalWrite (greenLED, greenLEDState ) ;
    // Reset timer
    greenLEDtimer = millis () ;
  }

// The other LED is controlled the same way. Repeat for more LEDs
  if ( (millis () - redLEDtimer) >= redLEDinterval ) {
    if (redLEDState == LOW)
      redLEDState = HIGH ;
    else
      redLEDState = LOW ;
    digitalWrite (redLED, redLEDState ) ;
    redLEDtimer = millis ()  ;
  }

/* Other code that needs to execute goes here.
   It will be called many thousands of times per second because the above code
   does not wait for the LED blink interval to finish. */

}

Someone asked elswewhere if this could be udes with motors. SURE! just replace the digitalWrite with anything else you want to do after a while : servo.write() for example, or avoid reading a switch input for 5ms for the debounce.

And to save remembering that number:

Good example but I would use interrupts instead like so Persistence of Vision | Blinkenlight.

Generalizing (and avoiding fiddling with interrupts):

  1. How to do several things at the same time
  2. More on doing several things at the same time

Technically millis() is also utilizing interrupts. Why do you object against interrupts?

I don't object interrupts, I object them being used directly for blinking an LED, and by someone who's a beginner. Much simpler to take a non-preemptive approach. millis() hides interrupts, you don't have to deal with them. Keep it simple.

  1. More on doing several things at the same time

Isn't this using essentially the same technique as the solution in the original post?

Don

Njay:
I don't object interrupts, I object them being used directly for blinking an LED, and by someone who's a beginner. Much simpler to take a non-preemptive approach. millis() hides interrupts, you don't have to deal with them. Keep it simple.

For a beginner to learn about interrupts isn't a trivial task better than a complicated one?

Yes, if the purpose of the beginner is to learn about interrupts. But usually it isn't, it is just to blink the LED.

Well, mstimer2 also hides interrupts. It even hides the scheduling mechanism. Whereas the millis approach makes the scheduling transparent. Which one is easier to grasp depends on your point of view. I found pointers /memory allocation slightly harder to grasp than interrupts. Hence I do not understand why beginners should not learn this.
Debugging interrupts is a different issue though. But Arduino offers no debugger anyway.

This reminded me of a macro I wrote once, specifically for the case of blinking LEDs independently with different periods. I'm not sure that I'd recommend using macros in this way though, certainly not to beginners!

//usage: every(id,time) doSomething(); 
//   id = some unique identifier
// time = period in microseconds
// Be careful, this macro has a trailing if and can bite you. You have been warned!
// If you use it, don't use delay, dont use blocking code, don't do anything more
// complicated than flash an LED.

#define every(id,time)  static unsigned long _ec ## id = 0;                   \
                        unsigned long _et ## id = micros();                   \
                        boolean _eb ## id = (_et ## id - _ec ##  id) >= time; \
                        if(_eb ## id) _ec ## id += time;                      \
                        if(_eb ## id)              

boolean p13,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11;

void setup() {
  for(int i=2;i<=13;i++)pinMode(i,OUTPUT);
}

void loop() {
  every(tled,1000000) digitalWrite(13,p13=!p13); // eg. toggle LED every 1000000 microseconds
  
  every(t2,30000000/51) digitalWrite(2,p2=!p2); // pendulum waves
  every(t3,30000000/52) digitalWrite(3,p3=!p3);
  every(t4,30000000/53) digitalWrite(4,p4=!p4);
  every(t5,30000000/54) digitalWrite(5,p5=!p5);
  every(t6,30000000/55) digitalWrite(6,p6=!p6);
  every(t7,30000000/56) digitalWrite(7,p7=!p7);
  every(t8,30000000/57) digitalWrite(8,p8=!p8);
  every(t9,30000000/58) digitalWrite(9,p9=!p9);
  every(t10,30000000/59)digitalWrite(10,p10=!p10);
  every(t11,30000000/60)digitalWrite(11,p11=!p11);
}

(I ran out of LEDs - this would probably look really good on the Blinkenlight shield)

Because you only get 2.

WizenedEE:

[quote author=Udo Klein link=topic=76140.msg595426#msg595426 date=1321198485]
Technically millis() is also utilizing interrupts. Why do you object against interrupts?

Because you only get 2.
[/quote]

Timer interrupts don't use up either of the two user interrupts (five if mega board).

Lefty

Because you only get 2.

Every input pin on the Mega328 can generate an interrupt.

Don

@Stimmer: here is my macro approach for pros: Multiple Modes Without Flicker | Blinkenlight. I did this to see how far I can push the macro processor. This story is not yet finished :wink:

you can use my timer library, very simple to use. no delays, small footprint.

after you import the library, check the sample and test it.