Arduino – Compute Duration of an Action

In this tutorial I’ll show you how to compute the duration of a part of code in Arduino.

The notion of time/duration is super important when you program, especially on embedded systems like Arduino. Writing a code that takes too much time, and not being able to know it, can lead to severe problems in your overall application.

For this post the goal will be to measure the duration of the famous digitalWrite() function. You’ll also get a template that you can use for measuring any piece of code you want in your Arduino programs.

Quick note before we get started: the duration you’ll measure will depend on your hardware. If you use an Arduino Uno or an Arduino Due (more computation power), you’ll get different results. For this tutorial I’ll be using an Arduino Uno.

Code to measure digitalWrite() duration

Here’s the code that you can run directly on your Arduino. We’ll make the experiment on pin number 10 – you don’t need to plug anything on this pin to test the code.

#define TEST_PIN 10

void setup() {
  Serial.begin(9600);
  pinMode(TEST_PIN, OUTPUT);

  unsigned long timeBegin = micros();
  
  for (int i = 0; i < 500; i++)
  {
    digitalWrite(TEST_PIN, HIGH);
    digitalWrite(TEST_PIN, LOW);
  }
  
  unsigned long timeEnd = micros();
  unsigned long duration = timeEnd - timeBegin;
  double averageDuration = (double)duration / 1000.0;

  Serial.println(averageDuration);
}

void loop() {}

Compute a duration in Arduino – breaking down the code

Let’s see what this code does, line by line.

Setup

#define TEST_PIN 10

void setup() {
  Serial.begin(9600);
  pinMode(TEST_PIN, OUTPUT);

First we setup the Serial communication, and we set the test pin to output mode. Calling pinMode() is required before you can use digitalWrite().

Store start time

  unsigned long timeBegin = micros();

To get the duration of an action, you first need to store the time before you start the action!

You can use either millis() or micros() here. Both will return an unsigned long number. For this purpose it’s better to use micros() as it will be more precise. millis() has a 1 millisecond resolution (1000 microseconds) while micros has a 4 microseconds resolution – 250 times more.

Execute your action

  for (int i = 0; i < 500; i++)
  {
    digitalWrite(TEST_PIN, HIGH);
    digitalWrite(TEST_PIN, LOW);
  }

Simply run your action. It could be whatever you want. Here we want to measure the duration of digitalWrite().

Seeing this code you might wonder: why did I wrote a for loop with 500 iterations, and not just execute one digitalWrite()?

Well, I did this so we can compute an average duration. For quick actions it’s usually very common to measure over multiple iterations of the same action, and then divide the total duration by the number of iterations. Thus you have a more precise value.

This applies to many fields, not only to Arduino programs. For example, to get the acidity of a liquid, a scientist will measure the acidity over many different samples, and then compute the average.

Also, as the resolution of micros() is 4 microseconds, well, if the result for one action is 4.59 microseconds (which is – spoiler alert – the real result), you will simply get a result of 4 microseconds. When an action is too quick it’s better to measure the duration for a lot of them and then compute the average.

Finally, to make sure we get a correct value, we set the pin to HIGH, then LOW, then HIGH, etc, in a loop. Setting only HIGH or only LOW with 1000 iterations might take less time, because the state of the pin doesn’t change (you can try to measure it).

Compute the duration

  unsigned long timeEnd = micros();
  unsigned long duration = timeEnd - timeBegin;
  double averageDuration = (double)duration / 1000.0;

After the action is done, we immediately store the time. We now have the time at when the action started, and the time at when the action finished.

By making a subtraction between the end time and the start time, we get the total duration. This duration is still represented as an unsigned long number.

Finally, we can get the average value by dividing the total duration by the number of iterations. Here we want to measure the duration of digitalWrite(), and we did 500 iterations of digitalWrite(HIGH) + digitalWrite(LOW). So we have to divide by 1000.

Note: If you simply write double averageDuration = duration / 1000;, the compiler will first make the computation in unsigned long (and round the result), and then cast it as a double. Hence, you’ll loose some precision. That’s why you have to make sure the computation is made with double numbers, by using (double)duration, or 1000.0, or both.

Print the result

  Serial.println(averageDuration);
}

void loop() {}

Finally we print the value on the terminal.

With my hardware setup – an Arduino Uno board – the result is 4.59 microseconds.

So, from that experiment you know that a digitalWrite() operation takes 4.59 microseconds on average, on an Arduino Uno. Great!

Code template to compute Arduino duration

The code structure to reproduce this experiment – for any action – is always the same.

  1. Store the start time.
  2. Run your action (once or with multiple iterations).
  3. Store the end time.
  4. Compute the total duration.
  5. Compute the average duration (if multiple iterations).
void setup() {
  // 0. Setup
  ...

  // 1. Store the start time
  unsigned long timeBegin = micros();

  // 2. Execute your action
  ...

  // 3. Store the end time
  unsigned long timeEnd = micros();

  // 4. Compute duration
  unsigned long duration = timeEnd - timeBegin;
  // 5. Compute average if multiple iterations
  ...
}

When you just wrote a piece of code and you’re not sure how long it will take, use this.

Arduino Duration – Conclusion

Computing the duration of an action in Arduino is very practical if you need to respect some time constraints.

For example you have a loop that you must run every 100 microseconds. If the code inside this loop takes more than 120 microseconds, well that’ll be a problem, and you’ll have to fix it with faster (or less) code. If, however, the code takes 70 microseconds, everything is OK and you don’t need to do anything.

If you want to multitask your Arduino, it’s important to know how long each action will take (and make them as simple as they can be),. This way you will be able to run multiple actions without having to worry about an action blocking other actions.

Also, always remember: premature optimization is the root of all evil. If you feel like optimizing a part of your code for speed, first measure how long it takes. Then, compare that with your application performance criteria. More often than not, you won’t have to modify anything, and you’ll save a lot of development time. Not saving time in order to save time, that’s the real deal here!

Did you find this tutorial useful?

Do you want to learn how to program with Arduino?

If yes, this course is for you:

Arduino Programming For Beginners Course

>> Arduino Programming For Beginners <<

LEARN HOW TO PROGRAM ROBOTS

Did you find this tutorial useful?

Do you want to become better at programming robots, with Arduino, Raspberry Pi, or ROS2?

If yes, subscribe to receive exclusive content and special offers!