Arduino Delay Function – Tutorial on Software Interrupts, Timer Library & Alternatives to Delay

///Arduino Delay Function – Tutorial on Software Interrupts, Timer Library & Alternatives to Delay

Arduino Delay Function – Tutorial on Software Interrupts, Timer Library & Alternatives to Delay

An Arduino delay can ruin your code. Knowing how to leverage software interrupts as well as Arduino timers as alternatives to Arduino delay calls critical. We will be looking at the Arduino Timer Library as well as examples of Software Interrupts and how you can eliminate the pesky Arduino delay function.

The demo in the tutorial is an LCD screen which receives data sent by the microcontroller with regards to a potentiometer. We will be discussing how we can eliminate the delay() call and which drawbacks each of the methods will have on our code.

Arduino Delays – Hardware Used

Why are delay() function calls bad?

The simplest and arguably most intuitive way to “pause” an Arduino function is to introduce a call to the delay() function. This function stops the code from executing for the duration specified as the parameter to the function in milliseconds (EX: delay(1000); would pause for 1000msec. or 1sec.). However, using a delay in your program is extremely dangerous due to the fact that nothing else may run during that time.

A microcontroller has a sequential architecture which only allows it to execute a single piece of code at a time. Although the execution is extremely fast, when you request a delay(), the Arduino is forced to count the timer without being able to do anything else.

Luckily, there are certain methods which allow you to counter this deficiency. We will be exploring these ways in this tutorial.

Printing to an LCD Display without a Delay

Arduino Delay Function - Tutorial on Software Interrupts, Timer Library & Alternatives to DelayIn certain situations, you may seek to avoid a delay altogether. However, this isn’t always possible due to a wide range of reasons. We will explore such a scenario in this section.

The circuit I’ve built for this tutorial is straightforward but will expose a very important flaw which we will discuss and address here.

If you’re interested in following along or simply need to wire an LCD; you should follow the circuit I’ve outlined in a previous tutorial in which I designed the entire LCD screen menu (Find it here: LCD Screen Menu Tutorial).

Once we’ve breadboarded the circuit and applied a simple LCD.write routine, we can clearly see the problem with having no delays in the main loop. It’s the fact that the LCD screen is clearing way too fast for our eyes to be able to see what’s written. The update rate of the screen is extremely fast.

The Simplest Solution – Delay(1000);

Based on the above result, we can easily introduce a delay(1000); call into our main. This will quickly fix the flickering and update the LCD once every second only. By doing so, we’re definitely giving it enough time to display the message for our eyes to see.

That being said, we still have a problem with our call: we’re locking up the microcontroller for the duration of the call. If the only device connected to your Arduino is the LCD screen; you should be perfectly fine with this implementation. However, I’m looking to have many more peripherals; therefore, we need to think of something else.

Leveraging the millis() function as an alternative to delays

The millis() call will “Returns the number of milliseconds since the Arduino board began running the current program.” (Arduino Reference)

This helpful function can be used to create calls after a certain number of milliseconds has elapsed. Here’s a simple implementation of this call:

#include LiquidCrystal lcd(6, 7, 5, 4, 3, 2);
unsigned long prevTime = 0;
volatile int sensorValue = 0;
void setup() {
lcd.begin(16, 2);
}
void loop() {
unsigned long currTime = millis();
if (currTime – prevTime >= 100) {
prevTime = currTime;
lcd.clear();
lcd.print(sensorValue);
}
}
void softInterrupt() {
sensorValue = analogRead(A0);
}

The advantage of using the millis() call is that the program is free to execute other operations while it waits for the timer to be equal to your preset. In other words, the scan of your main continues to happen until the specified time is reached.

The Problem with millis() & Software Timers

Using the millis() call is an excellent approach for most applications. However, there are still drawbacks which we should explore.

The biggest drawback of this way of programming is that the timing is not precise. Even if you introduce a 100msec interval where you should read a certain value and update the LCD, the call will be dependent on the execution time. In other words, if it takes 50msec to scan through your main(), the call to the millis() update you’ve implemented may take anywhere between 100 and 150msec.

The other drawback and potential flaw of this call are that it may still be interrupted by other functions, events, etc. In other words, if you have a separate delay() call or a routine which takes too long to execute, your millis() call may wait for a while!

Introducing Software Interrupts

software interrupt exampleThe ATMega328P-PU, the processor at the core of the Arduino Uno platform, is equipped with three timers. These timers are T0, T1 and T2. You may choose to investigate some of their definitions and registers within the datasheet of the microcontroller:

ATMega328P-PU Datasheet

The bottom line is that you can use any of the three timers to create a software interrupt which will trigger at a precise time and execute the specified function within your program.

Working with the TimerOne.h Arduino Library

The goal of the Arduino platform is to simplify the use of the functions provided by the microcontroller in order to make them accessible to everyone. The TimerOne.h library accomplishes exactly that for the software interrupt functions described above.

This library makes it extremely easy for the user to create a routine which will call a specified function outside of the main() routine at a specified interval. This function will execute regardless of what the microcontroller is doing at the time and will always execute right on time.

You may choose to read more about the library and all of the settings you’d need here:

Arduino TimerOne.h Library Documentation

Here’s a piece of code which makes use of this library.

#include #include “TimerOne.h”
LiquidCrystal lcd(6, 7, 5, 4, 3, 2);
unsigned long prevTime = 0;
volatile int sensorValue = 0;
void setup() {
lcd.begin(16, 2);
Timer1.initialize(100000);
Timer1.attachInterrupt(softInterr);
}
void loop() {
delay(10000000);
}
void softInterr() {
sensorValue = analogRead(A0);
lcd.clear();
lcd.print(sensorValue);
}

You need only a few lines of code in order to work with software interrupts within the TimerOne.h library. The first call is to initialize the interrupt which takes the time as a parameter. This time is in microseconds. In other words, 100000 = 100000 microseconds = 100 milliseconds. The second call we need to make is the attachInterrupt one. As we had seen in a previous tutorial on interrupts (See Tutorial Here), this function will take the name of the interrupt call as the parameter. In my case, this will be linked to the function called “softInterr”.

Defining the function called by the interrupt timer is also straightforward. Just like with hardware interrupts, this function may not return anything and can’t take a parameter. Therefore, we declare it as void and make sure that every single parameter we use within the function has the “volatile” modifier. In this case, that would be “sensorValue” which is declared within the global scope.

Conclusion on Arduino Delay, Millis() & Software Interrupts

It’s extremely important to know how to work with these functions, calls, and libraries. It’s very easy to call the delay() function within your code and call it a day. However, it may negatively impact your code in many applications. Familiarize yourself with the different methods and approaches which you can use to eliminate such calls and create a much more robust way of polling your timers.

All that being said, everything has a trade-off. Make sure that you are familiar with them before introducing code into your software.

Cheers,
– EEEnthusiast

By | 2018-06-30T08:39:38+00:00 June 30th, 2018|Arduino, Tutorials|0 Comments

About the Author:

Welcome to EEEnthusiast.com My name is Vlad, I'm an Electrical Engineer and I love to build and teach. I graduated in 2013 and have tried my best to share my electrical knowledge and experience with viewers and readers from all over the world. You can find me on my personal site or LinkedIn!

Leave A Comment

CommentLuv badge

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

Show Buttons
Hide Buttons