If you read the previous lesson, we covered the fundamentals of the millis function in general.
Let's make our first millis event!
Let's look ahead in time and create an event. When the value of millis reaches our predetermined time, we want a specific action to occur.
In code, it might look something like this:
const unsigned long event = 1000;
void setup() {
}
void loop() {
if (millis() > event) {
// Perform an action...
}
}
Let's walk through this sketch from the moment power is first applied. Power is applied, we enter the loop, and the first thing our sketch does is check millis.
Since it just started, the value of millis is low (less than 1000 ms). Since event is set to 1000, the if statement condition is false, and the code inside the curly braces doesn't run.
This loop will keep executing, and the if statement will continue to be skipped over since the condition is still false.
However, this won't last long, as the value of millis is rapidly increasing. Once millis exceeds the value of event, the if statement condition becomes true, and the code within the if statement starts executing.
Congratulations, you've created a timed event using millis!
But this isn't exactly what we're after. You could achieve the same thing with a delay function. What's nice about using millis is that we can perform other tasks in a loop, unlike with delay. We can read sensors, update displays, or do whatever we want.
In other words, the millis function won't block other code from running, as the delay function would. Additionally, we can add more events that trigger at later times. Next, let's see how we can use millis to create recurring timed events.
Recurring Events Using Millis
For example, we might want to read the water temperature every 30 seconds or have a servo motor move left and then right every minute. This simple use of millis won't cut it.
Let's return to our timeline with event. When millis exceeds this value, the event is triggered. However, in addition to triggering an action, the event time needs to be reset further down the timeline.
Essentially, 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. Let's examine some code to see what this might look like.
First, we'll set the interval of the event by creating a constant called eventInterval. We use a constant because the interval won't change, and we'll set it to 1 second or 1000 milliseconds.
Next, we'll create a variable called previousTime, which we'll use to track the time. It's an unsigned long because the value of millis can get extremely large, and we want to store that value in our variable.
In the setup, we'll 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:
const unsigned long eventInterval = 1000;
unsigned long previousTime = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
}
In the loop, we'll create a variable that gets updated with the current time during each iteration. To get the current time, we simply call the millis function.
Remember, the millis function reports to us where we are on the millis timeline. 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 will hold the current value of the millis function.
Now, here's the key step. We want to execute a function only when we reach our eventInterval (which is 1000ms).
So, every 1000 milliseconds, we want something to happen. The code might look complex, but we'll break it down step by step:
const unsigned long eventInterval = 1000;
unsigned long previousTime = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
/* Updates frequently */
unsigned long currentTime = millis();
/* This is the event */
if (currentTime - previousTime >= eventInterval) {
/* Event code */
Serial.println("Ice Ice Baby");
/* Update the timing for the next time around */
previousTime = currentTime;
}
}
So, what does this if statement do? It subtracts the current time (which is continually updated at the start of each loop iteration) from the previous time. Then, it checks if the result is greater than or equal to eventInterval.
This will make more sense with some numbers and examples.
EventInterval is a constant set to 1000, which won't change. What about currentTime? It's constantly increasing since it's assigned the value of the millis function. Think of currentTime as an arrow pointing upwards, always getting larger.
What about previousTime? Right now, it's set to zero. Let's see what happens when we substitute these values into the code:
Iteration 1:
Let's assume that only 100 milliseconds have passed so far. In this case, currentTime is equal to 100. The difference between currentTime (100) and previousTime (0) is 100, which is NOT greater than or equal to eventInterval (1000). Therefore, the if statement is false, and none of the code inside the curly braces is executed. We go back to the beginning of the loop.
Iteration 2:
Next, let's say 200 milliseconds have passed. Therefore, currentTime (200) - previousTime (0) = 200, which is still NOT >= eventInterval (1000). We keep going through the loop until the if statement becomes true 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 inside the if statement is executed, and "Ice Ice Baby" is printed to the serial monitor.
Here comes the clever part: we update the event's time for the next occurrence. We take the previousTime, which was zero, and update it with the current time. Since currentTime is 1000, previousTime is also set to 1000. We've printed to the serial monitor, updated the time, and now we exit the if statement and go 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 than or equal to 1000, so we skip over the if statement code. We keep skipping this code until another second has passed.
Iteration 5:
After 2000 milliseconds have passed, the difference between currentTime and previousTime is 1000, making our if statement true. We print to the serial monitor, update previousTime again, and the cycle continues.
This is the coding paradigm that allows you to create recurring timed events using your Arduino.
Admittedly, this may appear a bit tricky at first, with multiple variables involved. The best way to get a handle on this is to write the program yourself and experiment with it.
Comments