
After learning how to flash a single LED on your Arduino, you are probably looking for a way to make cool patterns, but feel limited by the use of delay(). If you ask in the forums, you get told to look at the “Blink Without Delay” example. This example introduces the idea of replacing delay() with a state machine. If you’re confused how to use it, this tutorial is setup to take you from blinking two LEDs with delay, to using an alternate method, right down to how you can use millis().
The millis() function is one of the most powerful functions of the Arduino library. This function returns the number of milliseconds the current sketch has been running since the last reset. At first, you might be thinking, well that’s not every useful! But consider how you tell time during the day. Effectively, you look at how many minutes have elapsed since midnight. That’s the idea behind millis()!
Instead of “waiting a certain amount of time” like you do with delay(), you can use millis() to ask “how much time has passed”? Let’s start by looking at a couple of ways you can use delay() to flash LEDs.
Example #1: Basic Delay
You are probably already familiar with this first code example The Arduino IDE includes this example as “Blink.”
void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); // set the LED on delay(1000); // wait for a second digitalWrite(13, LOW); // set the LED off delay(1000); // wait for a second }
Reading each line of loop() in sequence the sketch:
- Turns on Pin 13’s LED,
- Waits 1 second (or 1000milliseconds),
- Turns off Pin 13’s LED and,
- Waits 1 second.
- Then the entire sequence repeats.
The potential issue is that while you are sitting at the delay(), your code can’t be doing anything else. So let’s look at an example where you aren’t “blocking” for that entire 1000 milliseconds.
Example #2: Basic Delay with for() loops
For our 2nd example, we are only going to delay for 1ms, but do so inside of a for() loop.
void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); // set the LED on for (int x=0; x < 1000; x++) { // Wait for 1 second delay(1); } digitalWrite(13, LOW); // set the LED on for (int x=0; x < 1000; x++) { // Wait for 1 second delay(1); } }
This new sketch will accomplish the same sequence as Example #1. The difference is that the Arduino is only “delayed” for one millisecond at a time. A clever trick would be to call other functions inside of that for() loop. However, your timing will be off because those instructions will add additional delay.
Example #3: for() loops with 2 LEDs
In this example, we’ve added a second LED on Pin 12 (with a current limiting resistor!). Now let’s see how we could write the code from Example #2 to flash the 2nd LED.
void setup() { pinMode(13, OUTPUT); pinMode(12, OUTPUT); } void loop() { digitalWrite(13, HIGH); // set the LED on for (int x=0; x < 1000; x++) { // wait for a secoond delay(1); if (x==500) { digitalWrite(12, HIGH); } } digitalWrite(13, LOW); // set the LED off for (int x=0; x < 1000; x++) { // wait for a secoond delay(1); if (x==500) { digitalWrite(12, LOW); } } }
Starting with the first for() loop, while Pin 13 is high, Pin 12 will turn on after 500 times through the for() loop. It would appear that Pin 13 and Pin 12 were flashing in Sequence. Pin 12 would turn on 1/2 second after Pin 13 turns on. 1/2 second later Pin 13 turns off, followed by Pin 12 another 1/2 second.
This code is pretty complicated, isn’t it?
If you wanted to add other LEDs or change the sequence, you have to start getting ingenious with all of the if-statements. Just like example #2, the timing of these LEDs is going to be off. The if() statement and digitalWrite() function all take time, adding to the “delay()”.
Now let’s look at how millis() gets around this problem.
The millis() Function
Going back to the definition of the millis() function: it counts the number of milliseconds the sketch has been running.
Step back and think about that for a second. In Example #3, we are trying to flash LEDs based on a certain amount of time. Every 500ms we want one of the LEDs to do something different. So what if we write the code to see how much time as passed, instead of, waiting for time to pass?
Example #4: Blink with millis()
This code is the same “Blink” example from #1 re-written to make use of millis(). A slightly more complicated design, because you have to include a couple of more variables. One to know how long to wait, and one to know the state of LED on Pin 13 needs to be.
unsigned long interval=1000; // the time we need to wait unsigned long previousMillis=0; // millis() returns an unsigned long. bool ledState = false; // state variable for the LED void setup() { pinMode(13, OUTPUT); digitalWrite(13, ledState); } void loop() { unsigned long currentMillis = millis(); // grab current time // check if "interval" time has passed (1000 milliseconds) if ((unsigned long)(currentMillis - previousMillis) >= interval) { ledState = !ledState; // "toggles" the state digitalWrite(13, ledState); // sets the LED based on ledState // save the "current" time previousMillis = millis(); } }
Let’s look at the code from the very beginning.
unsigned long interval=1000; // the time we need to wait unsigned long previousMillis=0; // millis() returns an unsigned long.
millis() returns an unsigned long.
The variable interval is the amount of time we are going to wait. The variable previousMillis is used so we can see how long it has been since something happened.
bool ledState = false; // state variable for the LED
This code uses a variable for the state of the LED. Instead of directly writing a “HIGH” or “LOW” with digitalWrite(), we will write the value of this variable.
The setup() function is pretty standard, so let’s skip directly to the loop():
void loop() { unsigned long currentMillis = millis(); // grab current time
Each time loop() repeats, the first thing we do is grab the current value of millis(). Instead of repeated calls to millis(), we will use this time like a timestamp.
void loop() { if ((unsigned long)(currentMillis - previousMillis) >= interval) {
Holy cow does that look complicated! It really isn’t, so don’t be afraid to just “copy and paste” this one. First, it is an if()-statement. Second the (unsigned long) isn’t necessary (but I’m not going to sit around for 49 days to make sure). Third “(currentMillis – previousMillis) >= interval)” is the magic.
What it boils down to, this code will only become TRUE after millis() is at least “interval” larger than the previously stored value of millis, in previousMillis. In other words, nothing in the if()-statement will execute until millis() gets 1000 milliseconds larger than previousMillis.
The reason we use this subtraction is that it will handle the roll-over of millis. You don’t need to do anything else.
ledState = !ledState;
This line of code will set the value of ledState to the corresponding value. If it is true, it becomes false. If it is false, it becomes true.
digitalWrite(13, ledState); // sets the LED based on ledState
Instead of writing a HIGH or LOW directly, we are using a state variable for the LED. You’ll understand why in the next example.
previousMillis = millis();
The last thing you do inside of the if-statement is to set previousMillis to the current time stamp. This value allows the if-statement to track when at least interval (or 1000ms) has passed.
Example #5: Adding a 2nd LED with millis()
Adding a second flashing LED is straightforward with the millis() code. Duplicate the if-statement with a second waitUntil and LEDstate variable.
// each "event" (LED) gets their own tracking variable unsigned long previousMillisLED12=0; unsigned long previousMillisLED13=0; // different intervals for each LED int intervalLED12 = 500; int intervalLED13 = 1000; // each LED gets a state varaible boolean LED13state = false; // the LED will turn ON in the first iteration of loop() boolean LED12state = false; // need to seed the light to be OFF void setup() { pinMode(13, OUTPUT); pinMode(12, OUTPUT); } void loop() { // get current time stamp // only need one for both if-statements unsigned long currentMillis = millis(); // time to toggle LED on Pin 12? if ((unsigned long)(currentMillis - previousMillisLED12) >= intervalLED12) { LED12state = !LED12state; digitalWrite(12, LED12state); // save current time to pin 12's previousMillis previousMillisLED12 = currentMillis; } // time to toggle LED on Pin 13? if ((unsigned long)(currentMillis - previousMillisLED13) >= intervalLED13) { LED13state = !LED13state; digitalWrite(13, LED13state); // save current time to pin 13's previousMillis previousMillisLED13 = currentMillis; } }
This code has some small changes from the previous example. There are separate previousMillis and state variables for both pins 12 and 13.
To get an idea of what’s going on with this code change the interval values for each. Both LEDs will blink independently of each other.
Other Examples
Check out this list of millis() examples: https://www.baldengineer.com/millis-cookbook.html
There are examples to create a Police Light Strobe Effect, Time your Code, Change the ON-time and OFF-time for an LED, and others.
Conclusion
At first it seems that using the millis() function will make a sketch more complicated than using delay(). In some ways, this is true. However, the trade-off is that the sketch becomes significantly more flexible. Animations become much simpler. Talking to LCDs while reading buttons becomes no problem. Virtually, you can make your Arduino multitask.
Please help with the code according to the logic you’ve shown in ???
Microcontrollers atmega 328p
Are 3 switch( No) and 1 close (Nc)
Are 3 outputs for Rele and 1 Led alarm
1- switch 1- A0. On …… D5 for 5 minute …..D5 off……D6 on…..for 5minute …….D6 off…….D7 on……5minute .Resetting
2- switch 1- A0 and 2A1 .is on. …..D5 and D6 on for 5minute..
D5 off. D6 and D7 on for 5minute .. D6 off. D7 and D5 n for 5minute.Resetting
3- switch. 1,2,3__ A0,A1,A2. On D5,D6,D7.On No limit.
4_ switch 4 open_ A3 OFF . Off D5,D6,D7. And on D8 led alarm
5_ Switch 4 closed A3 on returning home
I’m sorry but I am not sure I understand your question. You should post on the Official Arduino Forums, in your native language.
Hi James,
Let me start by saying your tutorial was excellent!! I have been studying many methods of timing led’s and reading the arduino examples and have to say your insight, attention to detail and explanation was perfect!!
So may hat goes off to you for taking valuable time out of your life to help us understand.
Thank you!!!
Respectably
Dave Pina
I know this is an old post, but thank you! Been stuck killing a PID program from running in the background using delay(). This solved that issue so simply! No additional library necessary. Thank you again, Brian
Hello James,
Something odd is happening with example #4 and my arduino. When it executes, there is a short interval, then the LED lights (but dimly). Then it brightens. Then it goes back to dim. And that’s it. It doesn’t brighten again, nor does it turn off.
I cut and pasted #4, verified it, and uploaded it correctly, as far as I can see. I’m mystified.
Any help would be much appreciated.
It going to be a couple of days because I’m traveling without my Arduino this week. Are you certain you included the pinMode call?
I believe so. I copied and pasted Example #4 in its entirety. (By the way, Example #2 is missing a “;” at the end of Line 2)
Also, I forgot to mention earlier – thank you for replying to me!
I fixed #2, oops!
Like I said, I’ll get back to you on #4. I’m not sure I see a problem with the code, but sometimes little things happen when I paste into the blog.
James,
Any luck with this?
Mark
Mark, I’ve updated #4 with correct code… Thank you for pointing out the issue! Sorry about that.
Hi, I need help please. I am trying to remove the delays from the codes below:
int northRed = 0; //first of all associate a pin number with the Northern red light, in this case 13
int northAmber = 1; // associate pin 12 with the amber light
int northGreen = 2; //and finally the green light with pin 11
int eastRed = 3; //a pin for the east red light, 8
int eastAmber = 4; //a pin for the east amber light , 9
int eastGreen = 5; //a pin for the east green light, 10
int maindelay = 1500; //The timings of the lights are based around this number.
void setup() {
pinMode(northRed,OUTPUT); //set the north red pin as an output
pinMode(northAmber,OUTPUT); //set the north amber pin as an output
pinMode(northGreen,OUTPUT); //set the north green pin as an output
pinMode(eastRed,OUTPUT); //set the east red pin as an output
pinMode(eastAmber,OUTPUT); //set the east amber pin as an output
pinMode(eastGreen,OUTPUT); //set the east green pin as an output
digitalWrite(northRed,HIGH); //Switch the red light on so we have something to start with
digitalWrite(eastRed,HIGH); //switch the east red light on as well
}
void loop(){
northtogreen(); //change the north signal to green
delay(maindelay*4); //wait for the traffic to pass
northtored(); //change the north signal back to red
delay(maindelay/2); //small delay to allow traffic to clear junction
easttogreen(); //change the east signal to green
delay(maindelay*4);//wait for the traffic to pass
easttored(); //change the east signal back to red
delay(maindelay/2); //small delay to allow the traffic to clear junction
}
void northtogreen(){ //sequence of north lights going to green
digitalWrite(northAmber,HIGH); //Amber on, prepare to go
delay(maindelay); //Time for traffic to see amber
digitalWrite(northRed,LOW); //red off, finished with
digitalWrite(northAmber,LOW); //amber off, finished with
digitalWrite(northGreen,HIGH); //green on, go
}
void northtored(){ //sequence of north lights going to red
digitalWrite(northAmber,HIGH); //Amber on, prepare to stop
digitalWrite(northGreen,LOW); //Green off, finished with
delay(maindelay); //Time for traffic to stop
digitalWrite(northAmber,LOW); //Amber off
digitalWrite(northRed,HIGH); //Red on, stop
}
void easttogreen(){ //sequence of east lights going to green
digitalWrite(eastAmber,HIGH); //Amber on, prepare to go
delay(maindelay); //Time for traffic to see amber
digitalWrite(eastRed,LOW); //red off, finished with
digitalWrite(eastAmber,LOW); //amber off, finished with
digitalWrite(eastGreen,HIGH); //green on, go
}
void easttored(){//sequence of east lights going to red
digitalWrite(eastAmber,HIGH); //Amber on, prepare to stop
digitalWrite(eastGreen,LOW); //Green off, finished with
delay(maindelay); //Time for traffic to stop
digitalWrite(eastAmber,LOW); //Amber off, finished with
digitalWrite(eastRed,HIGH); //Red on, stop
}
can someone help please?
Marcus
please leave your circuit diagram.
Can you please explain more?
Thanks a bunch James.
Its working now!
This is the coolest thing ever. Don’t ask me why but it is! Hah.
Now I can get rid of my obviously infantile delay script and possibly add another LED to the chain. I am creating a sign that has a (IR) remote control and I got that to work. I am using case/switch statements so I can chose between a couple blinking patters, but they stop after one pass through the case scenario. In other words, It will blink the leds in sequence I programmed then stop. I suppose I make them continue with some sort of “while” statement or something like that. Eh?
Thanks again,,
Mark
PS. Happy Holidays.
It sounds like you need a state machine for each pattern. If the patterns have the same number of “states” (or you can fit them into the name of states, e.g. repeat states) you can use one state variable. Use your switch() statement to select the correct pattern and then use another switch statement to execute the correct pattern state.
Nice explanations. I’m a NOOB.
I tried to upload some of the sketches above and kept getting warnings such as “gt was not declared in this scope. (example 5) and “< ” in example 4.
Could this be because I have a newer model Arduino and those were written in 2011?
Thanks
No, it is a problem with WordPress. Occasionally it converts the greater-than and less-than symbols in the code into their HTML-escaped code. I’ve updated the examples to show the correct symbol.