Contents[Hide]

Introduction

The standard delay() function blocks the Arduino which is not allowed sometimes. We can find several examples on Internet to overcome this, but there was no method to use non-blocking delays on an easy way. Therefore, I have built the VirtualDelay library. It has been kept as simple as possible to save memory space and optimize the speed.

Advantages of the VirtualDelay library

  • It doesn't block anymore.
  • It can used for a chain of delays too, this was previously not possible.
  • The interface is straightforward.
  • The delay time can set in micro-seconds or milli-seconds.

VirtualDelay library

You can download the library from GitHub.

Note that it is more complex than might appear at first sight.

Questions

Please post any questions at the Arduino forum.

Using the VirtualDelay class

Interface

There are 2 member functions, see the examples how to use.
done() Use this if we need just one delay.
proceed() Use this if we need more delays with one VirtualDelay object. End with done().

Notes

  • The VirtualDelay must always run inside a loop, but this is usually the case with embedded software such as the Arduino platform.
  • We need an "if" statement, in contrast with the standard delay() function.
  • The timing of VirtualDelay starts at the beginning of the sketch in contrast to delay() which starts at the function itself.

The simplest VirtualDelay example

Here a simple blinking LED sketch with the VirtualDelay: 

#include <Arduino.h>
#include <VirtualDelay.h>

const byte ledPin = 13;

bool b;
VirtualDelay virtualDelay(millis);

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

void loop() 
{ if(virtualDelay.done(500)) digitalWrite(ledPin, b=!b); // the LED blinks on and off
}

Common blocking delay example program

 

Here a simple blinking LED sketch. Open the serial port and you can see that printing goes very slowly.

// Blocking delay 
#include <Arduino.h>
#include <Streaming.h>
const byte ledPin = 13;
void setup() 
{ pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}
  
void loop() 
{ delay(500); // 500ms 
  digitalWrite(ledPin, 1);
  delay(500); // 500ms 
  digitalWrite(ledPin, 0);  
  static int i; Serial << "\n" << i++; // printing goes very slow
}

Non-blocking delay example program

Open the serial port and you can see that printing goes fast now. The code is substitutable and we can easily recognize the differences between the two sketches.

// Non-blocking delay 
#include <Arduino.h>
#include <Streaming.h>
#include <VirtualDelay.h>
const byte ledPin = 13;
void setup() 
{ pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}
void loop() 
{ static VirtualDelay virtualDelay(millis);
  if(virtualDelay.proceed(500)) 
    digitalWrite(ledPin, 1); // 500ms    
  if(virtualDelay.done(500)) 
    digitalWrite(ledPin, 0); // 500ms 
  static int i; Serial << "\n" << i++; // printing goes fast
}

Comprehensive example program

In this example, all the features of the VirtualDelay library are used.

#include "Arduino.h"
#include <Streaming.h>
#include <Albert.h>
#include "VirtualDelay.h"
const byte Led1pin = 13;
const byte Led2pin = 11;
const byte Led3pin = 9;
VirtualDelay virtualDelay1(micros);
VirtualDelay virtualDelay2(millis);
VirtualDelay virtualDelay3(millis);
void startupBlinkLed(int blinkCount); // declaration
void setup() 
{ Serial.begin(9600);
  pinMode(Led1pin, OUTPUT);
  pinMode(Led2pin, OUTPUT);
  pinMode(Led3pin, OUTPUT);
}
void loop() 
{ Serial << endl, millis(), digitalRead(Led1pin), 2+digitalRead(Led2pin); // comma operator , in Albert.h
  //Serial << "           I'm so happy with VirtualDelay, during delay times, I can play:  ";
/* Blink Led3 only at startup and meanwhile proceed with the sketch without blocking 
      _   _   _   _
     | |_| |_| |_| |___________________________________________    
*/  
  startupBlinkLed(4); 
  
/* Blink Led2 with single delay of 235000us  
      _   _   _   _   _   _   _   _   _   _   _   _   _   _   _   _   _       
     | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|    
*/                
  static bool led2on;
  if(virtualDelay1.done(235000)) digitalWrite(Led2pin, led2on=!led2on); // blink Led2
/* Create a pattern with a chain of delays  
     ____________    ____     _
                 |__|    |___|  etc.
        800ms    150 200  225        
*/  
  digitalWrite(Led1pin, 1); // *a)
  if(virtualDelay2.proceed(800)) digitalWrite(Led1pin, 0); // set time in ms  
  if(virtualDelay2.proceed(150)) digitalWrite(Led1pin, 1);
  if(virtualDelay2.proceed(200)) digitalWrite(Led1pin, 0);
  virtualDelay2.done(225); // return virtually to *a)
/* Heartbeat on Led3 6s after startup   
                         _   _   _
     ___________________/ \_/ \_/ \_ etc.
             6s
*/  
  static bool delayDone;
  static bool led3on;
  if(!delayDone) 
  { if(virtualDelay3.done(6000)) delayDone=1; // delay 6s 
  }  
  else heartbeat(Led3pin); // else belong to if(!delayDone)
}
//------------------------------------------------------------------------------------------------------
void startupBlinkLed(int blinkCount) 
{ static VirtualDelay virtualDelay(millis); // static object allows that all code is within the function
  static bool on;
  static byte i;
  if(i < 2 * blinkCount) // attention: don't use while here!
  { if(virtualDelay.done(500)) 
    { i++;
      digitalWrite(Led3pin, on=!on); // blink Led
    }
  } 
}

The output is printed to the serial port and shown in an Excel graph here:

VirtualDelay: non-blocking delay library for the Arduino
VirtualDelay: non-blocking delay library for the Arduino

Do you have any comments? Please let me know.
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.