SALES INQUIRIES: 1 (888) 767-9864

Arduino Sketch with millis() instead of delay()

Are you trying to build a project using Arduino and you need to program repetitive timed events?

Are you looking for alternatives to the delay() function to achieve this?

Have you heard of the millis() function?

The wait is over. This lesson is for you.

How we got here

If you’ve watched the previous lessons, we’ve described the basics of millis function in general (part 1), we’ve talked about tight loops and blocking code (part 2), and we’ve discussed some issues that arise when using the delay function (part 3 and part 4).

In this lesson

  • Quick review of the millis function
  • The millis timeline
  • Create once-off timed events
  • Create repetitive timed events
  • How black holes can alter space-time

Millis Review

The easiest way to review this function is to look at it in a simple sketch. Let’s write a sketch that prints the value of millis to the serial monitor window.

In the Arduino IDE we’re going to begin in the setup section and use this Serial.begin function to enable serial communication.

Then in the loop we’re going to use the Serial.println (println = print line) function to print the value of millis.

Each time through the loop, this program will print the current value of the millis function. If we load this sketch onto our Arduino and open up the serial monitor window, you’ll see the value of millis is increasing rapidly.

Arduino Millis function value printed to serial monitor

So what is this value that the millis function returns?

The millis function returns the number of milliseconds that your Arduino board has been powered up.

In other words, when you upload your sketch to your Arduino, as soon as the upload is complete, the clock starts. Millis returns the number of milliseconds that have passed since this upload was completed.

Essentially, it’s a timer for how long the current program has been running. This is independent of the number of times the “void loop ()” has iterated.

So how high can it count up? It can count to 4,294,967,296… it would take 49 days to reach this number. Once it hits this number it “overflows”, which is just a fancy way of saying it then starts back over at zero and resumes counting up.

The way millis is able to track the number of milliseconds that have passed is by using the timer counter module that is built into the integrated circuit on the Arduino.

We don’t have to start the clock or start millis in our code, it starts all by itself in the background.

If you want to learn more about how the millis function works, definitely check out the first lesson in the series.

Millis timeline concept

To conceptualize millis so that we can use it to create timed repetitive events, let’s start by thinking of millis as moving along a timeline.

The timeline starts at zero and it goes all the way up to four billion and some change, and these numbers represent milliseconds.

So at any point during our program, we can call the millis function, and find out exactly where on the timeline we are.

Arduino millis timeline

Let’s take a look at the first five seconds of a program. The little dot (in the picture below) represents where millis is on the timeline.

As soon as we power up Arduino, the millis function starts counting. You can see the value is increasing and moving to the right along the time axis. If we want to create timed repetitive events, how could we use this timeline to our advantage?

Once-Off Millis Event

Let’s look ahead (in time) and create an event. When the value of millis gets to our predetermined time, we want a specific action to occur.

Arduino timeline gif

 

In code it might look something like this:

Let’s talk through this sketch from the point when power is first applied. Power is applied, we get into the loop, and the first thing our sketch does is check millis.

Since it just began, the value of millis is low (less than 1000 ms). Since event_1 is equal to 1000, the if statement condition is false, and the code in the curly brackets doesn’t run.

This loop will continue to execute over and over, and the if statement will continue to get passed over since the condition is still false.

 

This won’t last long, however, as the value of millis is increasing rapidly. Once millis exceeds the value of event_1, the if statement condition becomes true, and the code within the if statement begins to execute.

Congratulations, we’ve officially created a timed event using millis!

Arduino millis chef

But this really isn’t exactly what we’re after. You could achieve the same thing with a delay function. What’s nice with using millis, however, is we can do other stuff in a loop (unlike delay). We can read a sensor, update a display, or whatever we want.

Said another way, the millis function won’t block other code from running like the delay function would. Furthermore, we could add additional events that trigger at later times.  Next let’s see how we can use millis to create repetitive timed events.

Repetitive events using Millis

For example, every 30 seconds could read the water temperature, or every minute we could have a servo motor move left and then right again. For these types of programs, this simple use of millis won’t do it.

Let’s go back to our timeline. We still have our event_1, and when millis exceeds this value, the event is triggered. But in addition to triggering an action, the event_1 time will also need to be reset to further down timeline.

Arduino repetitive event using millis

Essentially what we’re doing is every time our event is triggered, we create a new updated time for our event, allowing us to repeat this timed event over and over again. Let’s try some code and see what this might look like.

The first thing we’re going to do is set the interval of the event. So let’s create a constant named eventInterval. We have it as a constant because the interval isn’t going to change. We’ll set it to 1 second, or 1000 milliseconds.

Next we’re going to create a variable that we’re going to use to update the time, called previousTime. It’s an unsigned long because the value of millis gets extremely large, and we want to be able to hold that value in our variable.

We’ve talked about this in one of the previous lessons (part 1), so make sure to check it out to learn more about storing millis values.

In setup we’re going to start serial communication using the Serial.begin function. We do this to enable data to be sent to the serial monitor in the loop. Here’s what the code looks like so far:

Down in the loop we’re going to create a variable that gets updated every time through the loop with the current time.

How do we get the current time? We just call the millis function.

Remember, the millis function is going to report back to us where we are on that millis timeline. So let’s create a variable called currentTime and set it equal to the output of the millis function.

So every time through the loop, currentTime is going to be holding the current value of the millis function.

Now comes the key step. We want to create some type of function that is only going to happen when we’re at our eventInterval (which is 1000ms).

So every 1000 milliseconds, we want something to happen.  The code is below, and it may look like a doozy, but we’ll go through it step by step:

So what does this if statement do? It takes the current time (… remember the current time is constantly being updated at the beginning of each iteration of the loop), and it subtracts from the previous time. It then checks to see if the resultant value is greater than or equal to the eventInterval.

This will make more sense if we assign some numbers and do a few iterations as examples.

We know eventInterval is never going to change, it’s a constant, and we set it to 1000.

What about currentTime? Since it’s assigned to the value of the millis function, we know it’s constantly going to be increasing. Think of current time as just a big arrow up. It’s always getting bigger, and bigger, and bigger.

What about previousTime? Right now it’s set to zero. Let’s take a look at the code with these substitutions:

Arduino if statement values

Let’s talk about a few iterations through the loop. At first, currentTime will be very small number since the program has just begun (i.e. not much time has passed since millis started counting up from zero).

If you’d like to see the following explanation in tabular format, just scroll to the bottom of the lesson and find the table that summaries the iterations. Some people’s brains work best like this!

Iteration 1

Looking at an early in time example (let’s say 100 milliseconds have passed so far), currentTime is equal to 100. The difference between currentTime (100) and previous time (0) is 100, which is NOT greater than or equal to eventInterval (1000).

Therefore the if statement is false, none of the code inside the { } brackets is executed, and we go back the the beginning of the loop.

Iteration 2

Next, let’s say 200 milliseconds have passed so far. Therefore, currentTime (200) – previousTime (0) = 200, which is still NOT >= eventInterval (1000).

We will continue through the loop over and over again until the if statement is true, which will happen after 1 second, or 1000 milliseconds.

Iteration 3

In the next example, 1000 milliseconds have passed. Therefore, currentTime (1000) – previousTime (0) = 1000, which IS equal to eventInterval (1000). Now the code in the if statement is executed.

Serial.println will print “Ice Ice Baby” to the serial monitor.

But here comes the clever part, where we scooch down the event so that the next time around, we can have this event happen again in another thousand milliseconds.

Let’s take the previousTime, which was zero, and update it with the current time. The currentTime is 1000, so now previousTime is also equal to 1000. So we’ve printed to the serial monitor, we’ve updated the time, and now we exit the if statement and go right back into the loop.

Iteration 4

Now let’s say 1010 milliseconds have passed. If we subtract currentTime (1010) from the new previousTime (1000), we get 10. This is not greater or equal to 1000, so we skip over the if statement code.

You can see what’s going on here: we’re going to keep skipping over this code until another second has passed.

Iteration 5

After 2000 milliseconds have passed, the difference between currentTime and previousTime is 1000, therefore our if statement is true, and we print to the serial monitor.  We also update the previousTime again.

This right here is the coding paradigm that allows you to create repetitive timed events using your Arduino.

Admittedly, this can look a little tricky at first, and there seems to be a lot of variables. The best way to really get a handle on this, however, is to just write the program yourself and mess around with it.

Arduino millis iteration table

Tabular summary of the iterations

Review

First, we did a quick review of the millis function. You don’t have to “start” the millis function, it’s always counting. It starts at zero and represents how long, in milliseconds, the Arduino has been powered up (or since the last sketch upload). Remember it can count up to 4 billion and some change, and then it starts over again once it gets to the top.

Next, we discussed how it’s best to think about millis as a value moving down a timeline in our program. This helps us conceptualize how we can use millis to create timed events.

Then, we talked about creating “once-off” timed events using the millis function, and how that’s not much different that using the delay function.

Finally, we talked about creating repetitive timed events using the millis function.

We hope you found this lesson helpful. We’re going to have a couple more lessons about the millis function and how to use it in some interesting cases, so stick around and stay tuned for the next lesson! Have a great day.

Arduino black hole

1 Comment

  1. Avatar Stephen Mann on April 22, 2019 at 12:14 am

    What happens if you set currenttime just a bit before millis() overflows?

    void loop() {
    /* Updates frequently */
    unsigned long currentTime = millis();
    /* This is the event */
    if (currentTime – previousTime >= eventInterval) {
    /* Event code */
    Serial.println(“Ice Ice Baby”);
    }
    }

    So, if previoustime= 4,294,967,296 will it take 49 days for currenttime to catch up?

Leave a Comment