Ardunio Looping Without Delay()

In the Arduino forum I’ve noticed a lot of people wanting to run their programs faster, but using delay() in their code.

Briefly, delay() waits a specific time before continuing. It makes for simple code, for example:

void loop()
{
// do event 1
  delay(...)
// do event 2
  delay(...)
// do event 3
  delay(...)
}

However, coming from a Windows background, it’s hard to look at code that does nothing (at one time, a delay in a Windows program meant every other program waited as well, a big no-no).

An easy(ish) solution is to manage your own timing by keeping track of a timer count for each event. The Arduino has a timestamp, millis(), which returns the number of milliseconds since the program started. If we store the time for an event in a variable, we can compare to millis() and see if it’s time to do something.

And to shorten the code, we’ll do two other things:

  • If the variable is zero, it’s a signal to us that we aren’t concerned with this event right now (ie, ignore).
  • Instead of storing the start time for an event, we store the end time (or current time plus the delay until the event changes). By combining them, our tests becomes shorter and faster.

So using this, let’s look at an example: say you want a light on for 5 seconds, then turn off. Use a variable ‘timerLight’ to hold the milliseconds to stop in the future:

unsigned long timerLight=0;
void loop()
{
  unsigned long msec=millis(); // get the time once and save (faster on long loops)
  if ( ourHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight && timerLight<msec ) // time to turn off?
  {
    timerLight=0;// turn off timer so we don't check again
        
// turn off light (somehow)
    
  }
}

Used this way, the code loop will stay active without delays, yet still catch events. As well, since it quickly tests for all events, you don’t have to worry about one item’s delay() interfering with another.

And while events can be independent, you can also gang up the events – for example, after you turn off one light, you could turn on another:

unsigned long timerLight1=0, timerLight2=0;
void loop()
{
  unsigned long msec=millis();
  if ( ourNotYetWrittenHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight1=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight1 && timerLight1<msec ) // time to turn off 1st light?
  {
    timerLight1=0;// turn off timer so we don't check again

// turn off light1 (somehow)

    // now next light - turn it off in 10 seconds
    timerLight2=msec+10000; // when to stop #2 in the future

// turn ON light2 (somehow)

  }
  if ( timerLight2 && timerLight2<msec ) // time to turn off 2nd light?
  {
    timerLight2=0;// turn off timer so we don't check again

// turn off light2 (somehow)

  }
}

The result is a you can a number of events in whichever order you want – just remember to add on and off code in the appropriate sections.

Using variables like this can make events much easier to manage and trigger (or turn off). Plus, avoiding delay() means you put those Arduino cycles where they count – doing useful work for you!

Comments are closed.