I noticed that the duration of the blink is always the same as the duration of the delay in the simple sketch below.
// Turn an LED on for one second, off for one second,
and repeat forever.
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(13, LOW); // Turn off the LED
delay(1000); // Wait for one second
}
Can I assume any activity paused by delay must take place in the same interval? I understand delay causes all program activity to stop for the duration. This sketch seems to have more to do with delay than blinking a LED.
What I am learning from this is the sequence of events in a sketch. So, I modified the sketch to include another LED:
// Turn an LED on for one second, off for one second,
// and repeat forever.
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(13, LOW); // Turn off the LED
delay(1000); // Wait for one second
digitalWrite(12, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(12, LOW); // Turn off the LED
delay(1000);
}
This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?
The demo Several Things at a Time is an extended example of standard "Blink Without Delay" example and illustrates the use of millis() to manage timing. It may help with understanding the technique.
brianeo:
This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?
You are correct, this is purely a pedalogical exercise that is easy to understand for newbies. Congratulations Padawan, you are very strong with the force.
After you fully understand the links Delta_G and Robin2 offered, check the attached sketch.
Place a LED on D13 and D12.
//BWD example
unsigned long FlashTime;
unsigned long RelayTime;
unsigned long WaitTime;
unsigned long currentmillis;
byte x;
void setup()
{
pinMode(13, OUTPUT); //connect to LED
pinMode(12, OUTPUT); //connect to relay driver
FlashTime = millis();
} // >>>>>>>>>>>>>> E N D O F s e t u p ( ) <<<<<<<<<<<<<<<<<
void loop()
{
//leave this line of code at the top
currentmillis = millis();
//***************************
//just some code to see if the sketch is blocking
if (CheckTime(FlashTime, 50UL))
{
digitalWrite(13,!digitalRead(13)); //toggle LED
}
//***************************
if (CheckTime(RelayTime, WaitTime))
{
if(x < 20)
{
WaitTime = 400; //Fast
}
else
{
WaitTime = 800; //Slow
}
digitalWrite(12,!digitalRead(12)); //toggle relay
x++;
if(x > 39)
{
x = 0;
}
}
//***************************
//Put your non-blocking regular stuff here
} // >>>>>>>>>>>>>> E N D O F l o o p ( ) <<<<<<<<<<<<<<<<<
//======================================================================
// F U N C T I O N S
//======================================================================
//***************************
//Delay time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait)
{
//is the time up for this task?
if (currentmillis - lastMillis >= wait)
{
lastMillis += wait; //get ready for the next iteration
return true;
}
return false;
} //END of CheckTime()
//***************************
//======================================================================
// E N D O F C O D E
//======================================================================
Thanks for all replies. I see the terminology for it is "blocking." What I want is "non-blocking." That's a good start, for me. I will print the entire thread for study.
I have been aware of the Example/02.Digital/BlinkWithoutDelay since I found it on my own, plus the repeated discussion of it on the forum. It's still clear as mud to me. That's not because it's not a good tutorial. It's me. I don't get it until I get it.
It looks to me like the link offered by Delta_G is another way of explaining it. Sometimes when I look at a thing from a different point of view is makes better sense, and, afterwards, the first explanation sinks in also...
Save the time from millis() when the start action happens, such as turning on an LED, then each time through loop() check whether the current time minus the start time is equal to or greater than the required interval. If so, then act on it, such as turning the LED off, save the time from millis() and off you go again. If the period has not passed then keep going round loop() until it has. Now the important bit. Because loop() is running freely (not blocked) you can do other things until the interval passes.
The code in reply #4 uses this principle but holds the variables in arrays so that several different periods can be used on different LEDs without duplication of code.
brianeo:
Can I assume any activity paused by delay must take place in the same interval? I understand delay causes all program activity to stop for the duration. This sketch seems to have more to do with delay than blinking a LED.
Delay does not pause any one specific activity, it pauses EVERYTHING*.
Except for interrupt driven activities, like the millis/micros timer and Serial TX/RX.
This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?
It is very crude and ugly. The sooner you cultivate a healthy disgust for the delay function, the sooner you will be able to fully unleash the power of your microcontroller.
delay() is an evil function. delay() entices little children to the back of a windowless van with promises of candy. delay() sacrifices kittens, puppies, and baby seals in Satan's glory. delay() caused the 9/11 terrorist attacks. delay() hacked the 2016 US election. delay() steals your socks from the dryer and hides your keys in the morning when you're late for work.
As much as delay is maligned here, I feel like the transition from delay to millis usage is a step that can be easily taken farther down the line in the learning process. Spend more time now or less time later, latter being more efficient.
In other words, use delay, learn to do many different things, one at a time. Then, when your toolbox actually has multiple things, and you want to run simultaneously and non-blockingly, then implementing millis for delay behavior will be a snap.
Although the advice of avoiding the use of delay means well, I think it gets mindlessly dispensed too eagerly too often.
Then, when your toolbox actually has multiple things, and you want to run simultaneously and non-blockingly, then implementing millis for delay behavior will be a snap.
delay() has its place, but it is easier to learn to use millis() in simple cases such as BWOD before you need to use it in a complicated one.
BwoD is a good example but it was confusing for me at first.
It took me awhile to understand it well enough to be able to rearrange it as a one off timer instead of the constant blinking.
unsigned long startTime = 0;
const long interval = 1000; // 1 second = 1000 millis
void setup()
{
}
void loop()
{
if (condition to activate timer)
{
startTime = millis(); // Begin timing sequence
// do stuff here when timing sequence starts
}
unsigned long currentTime = millis();
if (currentTime - startTime >= interval) // End timing sequence
{
// do stuff here when time is up
}
}
Delta_G:
No, actually it doesn't. As soon as you add any more code the timing would change and you have to go calibrate the timing again.
Yeah it does, I did mention it was to blink just one led, I am perfectly aware that adding any more code would change the timing i do not know why you are insinuating that and i know its not time specific.
in that case you might as well get an atomic clock for your timing, you obviously have a chip on your shoulder its was just a post for what i assume is a beginner programmer, that is not accurate and does not use delay, there is no need to partake in one-upmanship.
brianeo:
Thanks for all replies. I see the terminology for it is "blocking." What I want is "non-blocking." That's a good start, for me. I will print the entire thread for study.
Let me see if I can make it easier to see. First, the "bad" delay (the blocking one) in pseudo-code:
forever loop {
LED = on;
delay (1000); // wait 1 second - during this time *NOTHING else can run
LED = off;
delay (1000); // wait another second while LED is off
}
(* when I say "nothing" I mean none of your program can run. background interrupts still do run)
Now, a "non-blocking" way:
variable T = millis(); // get start time upon entering the loop
forever loop {
LED = on; // turn on the LED
if (millis() > (T + 1000)) { // if current time greater than start + 1000
LED = off; // led off
}
//////////////////////////////////////////////////
// in the mean time, other stuff can run here
//////////////////////////////////////////////////
// the current millisecond is checked thousands of times per second
// (each time through the loop) but the LED doesn't get turned off
// until the CURRENT time is greater than (START + 1000).
}
The example above only turns the LED on once, then turns it off after 1 second. I left out the rest of the code that would blink it repeated for clarity. Of course, to blink the LED, you just add another "get start time, check for end time" piece and switch the LED the other way (and again other code can run while waiting for the time to expire).
I wanted you to see how you get the start time, then continuously check for the end time and in between your program can still do other things because the "check if time expired" is so quick the rest of your code (i.e. not related to the LED) runs at essentially full speed.
Hope this helped see how the "delay without delay()" works.