TIMING

This page is part of my Model Remodel series of articles and a subset of my Arduino section.

DISCLAIMER: If you choose to attempt any of these modifications, you assume all risks thereof. I just wanted to share my experiences here. Neither Eaglemoss, nor myself, are responsible for any damages that may occur.


In my previous Arduino articles, we wrote Our First Arduino Sketch, built Our First Circuit to light up a LED, and learned about Variables and if/else Statements. Hopefully, those pages provided enough basic knowledge to let us step into more interesting capabilities of our Arduino.

Immediately after learning how to light up an LED, I then tried to see if I could make it blink on and off. This is because I wanted to make the Beacon Lights on my Enterprise D model flash at a specific rate.

On this page, we are going to take our basic LED circuit and program the Arduino to turn the LED on and off every one (1) second, effectively making it blink. I will share two ways of accomplishing this effect: with and without using the delay command.

Using the delay Command

The delay command is commonly used to tell an Arduino to wait a certain period of time before performing the next command. The delay command only expects one value: the number of milliseconds (thousandths of a second) to wait.

By inserting delay commands after telling the Arduino to set Pin 3 HIGH (ON), and again after telling it to set Pin 3 LOW (OFF), this will change the state of our LED every 1000ms (one second). And, because these commands are inside the loop() function, it will repeat forever. I have modified our previous sketch to create this  one:

/*
  A sketch that will flash a LED every second using:
    A Variable
    An if/else Statement
    The delay command
*/
// Create the LEDPin variable and set its value to 3
const byte LEDPin = 3;
void setup() {
  // Set LEDPin (Pin 3) as an output pin
  pinMode(LEDPin, OUTPUT);
}
void loop() {
  // Turn LED on
  digitalWrite(LEDPin, HIGH);
  // Wait one second
  delay(1000);
  // Turn LED off
  digitalWrite(LEDPin, LOW);
  // Wait one second
  delay(1000);
}

After verifying and uploading this sketch to our Arduino, the same circuit from before now has a blinking LED!

Animated GIF of our blinking LED

Using our knowledge of if/else statements, we could even get rid of one of the delay commands. Here, I used the digitalRead command to check the current state of Pin 3 (the LEDPin). This command returns a value of HIGH or LOW, which the condition sees as true or false.

If the LEDPin is currently HIGH (ON), the condition evaluates to true, so we can turn it off by setting it to LOW. If the LEDPin is currently LOW (OFF), the condition evaluates to false and the else part of the statement is executed where we turn it on by setting it to HIGH.

Since the changing of the LED state is now self-contained inside this new if/else statement, we can remove one delay command and move the other delay command to the bottom. Our loop() function will now change the state of the LED, wait one second, then start over.

...
void loop() {
  // Read the LEDPin (Pin 3) State and change it to the opposite state
  if (digitalRead(LEDPin)) {      // LEDPin is HIGH (on)
    // Turn LED off
    digitalWrite(LEDPin,LOW);
  } else {                        // LEDPin is LOW (off) 
    // Turn LED on
    digitalWrite(LEDPin,HIGH);
  }

  // Wait one second
  delay(1000);
}

Download my Sketch

To help others, I have shared this sketch via the Arduino Editor. Simply click the Open Code or Download buttons!

Avoiding the delay Command

While the delay command can be very helpful for simple sketches, it also has a significant downside. This is because the delay command instructs the Arduino to stop doing anything for the duration of the delay. And, while the Arduino is ‘delayed’ it cannot perform any other tasks. Luckily, we can avoid using delay and still trigger events using three bits of information:

  • The last time the event occurred
  • The current time
  • The intended interval of time before the event occurs again

To store the last time an event occurred, we need to declare a new global variable and update its value every time the event happens. Time values are stored internally as a numerical ‘timestamp’ with a long variable type. Therefore, we can declare our new variable as such and give it a default value of zero. I used the name ledLastChangedTime for my newly declared variable, but you can name it whatever you like.

Since timestamps are always a positive number, our ledLastChangedTime variable does not need a -/+ modifier. That means we can use the  unsigned modifier. Also, because this value will not be constant (it needs to be able to change), we would not use const modifier here.

/*
  A sketch that will flash a LED every second using:
    Variables
    if/else Statements
    Internal clock timing
*/
// Create the LEDPin variable and set its value to 3
const byte LEDPin = 3;
// Create the ledLastChangedTime to hold the timestamp of the last LED state change
unsigned long ledLastChangedTime = 0;
void setup() {
...

Next, we want to update the value of this ledLastChangedTime variable every time the LED state changes by setting it to the current time value. For this, we will use the millis() command. Calling the millis() command immediately returns a timestamp value (in unsigned long format) containing the number of milliseconds that have passed since the Arduino began running the current sketch.

NOTE: This is a good time to remove any of the previous delay commands from our sketch.

...
void loop() {
  // Read the LEDPin (Pin 3) State and change it to the opposite state
  if (digitalRead(LEDPin)) {       // LEDPin is HIGH (on)
    // Turn LED off
    digitalWrite(LEDPin,LOW);
    // Reset Last Changed Time
    ledLastChangedTime = millis();
  } else {                         // LEDPin is LOW (off)
    // Turn LED on
    digitalWrite(LEDPin,HIGH);
    // Reset Last Changed Time
    ledLastChangedTime = millis();
  }
}

Then, we need to choose an interval time value. Since our previous sketches used a one second (1000ms) between flashes, I will just use this value as our interval. For this, we need to declare our interval as a new variable with a preset value. I used the name ledChangeInterval here, but again, you can use any name you like.

There is a gotcha here. Unlike the LEDPin variable, we cannot use a byte variable type for this new variable as its value will be more than the maximum a byte can hold (255). The next suitable variable type is an int (integer), so we will use that instead. Because this variable will not need to be changed by the sketch (read-only), we can set it to be a constant variable.

/*
  A sketch that will flash a LED every second using:
    Variables
    if/else Statements
    Internal clock timing
*/
// Create the LEDPin variable and set its value to 3
const byte LEDPin = 3;
// Create the ledLastChangedTime to hold the timestamp of the last LED state change
unsigned long ledLastChangedTime = 0;
// Create the ledChangeInterval and set its value to number of milliseconds between LED state changes
const int ledChangeInterval = 1000;
void setup() {
...

Finally, here is where it all comes together. We are going to wrap our previous chunk of ‘LED State Changing’ code inside a new if statement that first takes the current time using millis() and subtracts the ledLastChangedTime. This result of this equation is a value of how much time has passed since the LED last change state:

millis() – ledLastChangedTime

Then, we check to see if that value is more than our preset ledChangeInterval. The paratheses around the first equation makes sure that math is processed first:

(millis() – ledLastChangedTime) > ledChangeInterval

In our sketch, this if condition will only evaluate to true when 1000ms (the ledChangeInterval) has passed since the last time the LED changed state (the ledLastChangedTime). If true, then it will execute the code inside this new if statement which contains our ‘LED State Changing’ code and a single ledLastChangedTime line.

The second ledLastChangedTime is no longer needed since after the LED state is changed, we can just overwrite (set) the ledLastChangedTime once to hold the current time value inside our new if statement.

...
void loop() {
  // Check to see if the ledChangeInterval has passed since the ledLastChangedTime
  if ((millis() - ledLastChangedTime) > ledChangeInterval) {

    // Read the LEDPin (Pin 3) State and change it to the opposite state
    if (digitalRead(LEDPin)) {       // LEDPin is HIGH (on)
      // Turn LED off
      digitalWrite(LEDPin, LOW);
    } else {                         // LEDPin is LOW (off)
      // Turn LED on
      digitalWrite(LEDPin, HIGH);
    }
    // Reset Last Changed Time
    ledLastChangedTime = millis();
  }
}

That’s it! Plug your Arduino back into the USB cable and our LED should blink on and off every one second without any delay commands in the sketch. Not using delay will allow us to trigger multiple events at the same time and this will become more important as we ask the our Arduino to do more and more things.

Download my Sketch

To help others, I have shared this sketch via the Arduino Editor. Simply click the Open Code or Download buttons!

Timing Multiple Events

Timing multiple events is where avoiding the use of the delay command really shines. We are going to add a second LED circuit to our breadboard and time it to blink at a completely different interval! To add this capability to our sketch is quite simple – we can basically copy/paste bits of the code we have already written and make only minor changes.

First, we will declare a new global variable for a second DIGITAL pin and set it as an OUTPUT. In this case, I used the variable name LED2Pin and picked Pin 4.

/*
A sketch that will flash two LEDs at different intervals using:
  Variables
  if/else Statements
  Internal clock timing
*/
// Create a LEDPin variable and set its value to 3
const byte LEDPin = 3;
// Create a LED2Pin variable and set its value to 4
const byte LED2Pin = 4;
...
void setup() {
  // Set LEDPin (Pin 3) as an output pin
  pinMode(LEDPin, OUTPUT);
  // Set LED2Pin (Pin 4) as an output pin
  pinMode(LED2Pin, OUTPUT);
}
...

Next, we create another set of variables to hold separate ‘last changed time’ and ‘change intervals’ for this second LED. Let’s say we want the second LED to blink twice as fast. We just need to cut the interval in half, or 500ms. I named these variables led2LastChangedTime and led2ChangeInterval:

...
// Create a ledLastChangedTime to hold the timestamp of the last state change of the first LED
long ledLastChangedTime = 0;
// Create a ledChangeInterval and set its value to number of ms between the first LED state changes
const int ledChangeInterval = 1000;
// Create a led2LastChangedTime to hold the timestamp of the last state change of the second LED
long led2LastChangedTime = 0;
// Create a led2ChangeInterval and set its value to number of ms between the second LED state changes
const int led2ChangeInterval = 500;
void setup() {
...

Finally, we add another if statement (similar to the previous one) to the loop() function using these newly created variables:

...
void loop() {
  // Check to see if the ledChangeInterval has passed since the ledLastChangedTime
  if ((millis() - ledLastChangedTime) > ledChangeInterval) {
    // Read the LEDPin (Pin 3) State and change it to the opposite state
    if (digitalRead(LEDPin)) { // LEDPin is HIGH (on)
      // Turn LED off
      digitalWrite(LEDPin, LOW);
    } else { // LEDPin is LOW (off)
      // Turn LED on
      digitalWrite(LEDPin, HIGH);
    }
  // Reset Last Changed Time
  ledLastChangedTime = millis();
  }
  // Check to see if the led2ChangeInterval has passed since the led2LastChangedTime
  if ((millis() - led2LastChangedTime) > led2ChangeInterval) {
    // Read the LED2Pin (Pin 4) State and change it to the opposite state
    if (digitalRead(LED2Pin)) { // LED2Pin is HIGH (on)
      // Turn LED2 off
      digitalWrite(LED2Pin, LOW);
    } else { // LED2Pin is LOW (off)
      // Turn LED2 on
      digitalWrite(LED2Pin, HIGH);
    }
    // Reset Last Changed Time
    led2LastChangedTime = millis();
  }
}

Download my Sketch

To help others, I have shared this sketch via the Arduino Editor. Simply click the Open Code or Download buttons!That’s it! Verify and upload the sketch to your Arduino, and then we can turn to wiring this new circuit to test it out.

Wiring Up the Second LED

To connect our second LED, we will need another red LED, another 150Ω resistor, and two more jumper wires. This LED will be hooked up in the same way as the first, but this time using Pin 4 on the Arduino to provide the positive connection to the anode side of the new LED. The ground side (and the inline resistor) of this second circuit can be connected to the same ground ‘power rail’ we used before:

When you plug your Arduino in, we should now see both LEDs flashing at different rates:

GIF Animation of two LEDs flashing at different rates

As you can see, we can have multiple different events timed at different intervals and never use the delay command. This bit of code can easily be duplicated and modified as many times as needed for your project. I use timing like this as the core of the various sequences and lighting effects throughout my final sketch.

Next Arduino Page


REMOTE CONTROL – Controlling our Arduino circuits remotely

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.