I am not wholeheartedly in agreement with the alternate suggestion. Instead of just writing negative comments, or just saying "mine is better" (well, that may be my
opinion), I will explain my deliberations to achieve the goal:
- A short, simple and uncomplicated example, cut-n-paste ready to run. It is to aid people who look at the (in)famous BlinkWithoutDelay who can not make the mental leap to generalize this to two or more LEDs.
(Note to self: start another thread with a rewritten BlinkWithoutDelay that is correct and a clearer comment on what "NoDelay" means to the other code in loop)
In particular, I did not want to introduce a number of other "tricks of the trade" which would detract from getting the main point.
So here is a line-by-line argument for my choices, where I now have included the good points from above discussion.
/* "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 you
can implement multiple independent timing paths in the main loop.
Written by several forum members. In public domain. Oct 2011.
*/
Yeah ... I amended it to this, inspired by the official examples. (No mention of using a resistor, which is the anode and so on. This is a programming exercise.)
// Which pins are connected to which LED
const int GreenLED = 8 ;
const int RedLED = 10 ;
This is to indirectly teach that meanigfull variable names are usefull. If I added a comment "//Pin8 connect to greenLED"
it defeats half the reason for variable name. int
choosen beacuse that is what the documentation says the pinMode, digitalWrite expect.
// Time periods of blinks. Time variables and constants should be unsigned long, always
const unsigned long QuickBlink = 555UL ;
const unsigned long SlowBlink = 1234UL ;
Make it clear that millis/micros are unsigned long
and all variable and constants should be of that form. As such the constants should be suffixed UL. The lesser sophisticated reader may not understand why, but will follow the example, and thus avoid the classic "why isnt 100,000 working". (No indvidual line comment for each variable for the same reason as before)
// Variable holding the timer value so far. One for each "Timer"
unsigned long QuickTimer , SlowTimer ;
// Variables to store what to change the LED to.
int GreenLEDState = LOW ;
int RedLEDState = LOW ;
I am undecided whether to initialize the timer variables or not.
void setup() {
pinMode(GreenLED,OUTPUT) ;
pinMode(RedLED,OUTPUT) ;
}
Intentionally avoided adding comments that "here starts the setup. Setup is only called once. ..." "this is the closing brace that ends setup ..."
void loop() {
// Handling the blink of one LED.
// First, check if it is time to change state
if ( millis() - QuickTimer > QuickBlink ) {
Comments added, inspired by Nick's example and the official examples.
// It is time to change state. Calculate next state.
if (GreenLEDState==LOW) GreenLEDState = HIGH ; else GreenLEDState = LOW ;
This item is most carefully choosen. The "new" reader knows and understands the if-then-else construct. I sometimes write lines like this using the trenary "X?y:z" operator, but that is not part of the subset of C that Arduino uses. (And it generates the same binary stuff anyhow). I was considering whether to use multiple lines (makes the example long-ish) and if to relgiously use braces. I slightly favour braces, even though here they would be redundant, but then it is less ambigous, less likely to break code when modifying. In the end keeping the "toggle" line as short as possible won the day.
I really like the digitalWrite(p, !digitalRead(p) )
alternative. I will use it in my code. But it is NOT used here because it "misdirects" in this context. The unsophisticated user gets sidetracked, thinks it is part of the "simultaneous magic", and it will not let him/her generalize to do PWM (analogWrite(p, analogRead(p)+1) ??) or other intelligent items. Lastly on a pure note, it "violates" type, we are relying on that LOW is !HIGH by the quirks of C's boolean representation.
Thus a boring if-then-else
, and the comment shows it could be any calculation of the next state. (And I will "submit" an example with PWM, too, later, another day)
// Write new state
digitalWrite(GreenLED, GreenLEDState ) ;
// Note the current millis(), so we change state again "QuickTimer" milliseconds later
QuickTimer = millis() ;
}
Comments added, inspired by Nick's example and the official examples. Codewise there is not much choice here, as I intentionally wanted to show the similarity to the BlinkWithoutDelay. (I'll comment on the "creep" and the "save millis() in a variable" shown in Nick's versions later.)
The whole code example without interruptions in the next post, where I have included an expanded version of the trailing comment for "here goes more code". Good point that.