Go Down

Topic: Blink Two LEDs, independent, no delay (Read 5809 times) previous topic - next topic

Msquare

Oct 20, 2011, 06:11 pm Last Edit: Nov 12, 2011, 09:24 pm by Msquare Reason: 1
Some of the frequent contributors thought this might be a good example - for when the tutorial "Blink without Delay" example is not enough
Code: [Select]
/* 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. */

}



Msquare

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.

GoForSmoke

http://www.gammon.com.au/forum/?id=11411

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Nick Gammon

And to save remembering that number:

http://gammon.com.au/blink
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Udo Klein

Check out my experiments http://blog.blinkenlight.net


Udo Klein

Technically millis() is also utilizing interrupts.  Why do you object against interrupts?
Check out my experiments http://blog.blinkenlight.net

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.

floresta

Quote
2) 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

GoForSmoke


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?

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Njay

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

Udo Klein

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.
Check out my experiments http://blog.blinkenlight.net

stimmer

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!

Code: [Select]

//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)
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

WizenedEE


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


Because you only get 2.

retrolefty



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


Because you only get 2.


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

Lefty

Go Up