element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino Tutorials
  • Products
  • Arduino
  • Arduino Tutorials
  • More
  • Cancel
Arduino Tutorials
Blog A non blocking delay
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino Tutorials to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Workshopshed
  • Date Created: 5 Jun 2014 8:45 PM Date Created
  • Views 8763 views
  • Likes 4 likes
  • Comments 15 comments
  • delay
  • code
  • c++
  • arduino
Related
Recommended

A non blocking delay

Workshopshed
Workshopshed
5 Jun 2014

The "hello world" of the Arduino is the blink sketch. This demonstrates that your board is working by blinking an LED, typically the on-board LED attached to pin13 but it has a problem.

The code uses the "delay" function which waits the desired number of milliseconds before continuing with the next line of the code.

 

int led = 13;

void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
  //Code here runs once every 2 seconds
}

 

The problem with the delay function is that nothing else happens whilst the delay is running. This is not only wasteful of the limited processing power of the microcontroller but it also makes any other routines you are using potentially unresponsive. There are several approaches to this problem such as using interrupts. The approach I selected to use a class which implement the non blocking delay.

This delay is implemented with a variable and two function, the first sets the delay and the second checks if the delay has finished.

 

Here's how it is used:

#include "Delay.h"

int led = 13;
int ledstate = HIGH;
NonBlockDelay d;

void setup() {                
  pinMode(led, OUTPUT);  
}

// the loop routine runs over and over again forever:
void loop() {
  if (d.Timeout()) {
    digitalWrite(led, ledstate);
    ledstate = ledstate == LOW ? HIGH : LOW; //toggle state
    d.Delay(1000);
  } 
  //Code here runs frequently
}

 

Delay.h

#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
class NonBlockDelay {
    unsigned long iTimeout;
  public:
    void Delay (unsigned long);
    bool Timeout (void);
    unsigned long Time(void);
};

 

Delay.cpp

#include "Delay.h"
void NonBlockDelay::Delay (unsigned long t)
{
  iTimeout = millis() + t;
  return;
};
bool NonBlockDelay::Timeout (void)
{
  return (iTimeout < millis());
}
unsigned long NonBlockDelay::Time(void)
 {
   return iTimeout;
 }

 

My reason for wrapping the delay in a class is so that I can use it for twice for each of the steppers in my clock project and so my loop will end up as a series of non blocking calls.

 

void loop() {
     CheckInput();
     ReadClock();
     CalcHandPositions();
     SetStepperPositions();
     StepMotors();
}

  • Sign in to reply

Top Comments

  • jadew
    jadew over 11 years ago in reply to Workshopshed +1
    Hey Andy, Yes, you can put those 3 lines inside a header file and include it wherever you need it. I know why you went for the class, it's the natural way to go when you're coming from higher level environments…
  • Workshopshed
    Workshopshed over 9 years ago in reply to celem

    Hi Edward, nice idea, thanks for the comment.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • celem
    celem over 9 years ago

    I altered Andy Clark's solution to better suit my needs. While I kept the Timeout member, I am not using it. I modified Delay() so that it stands alone and only executes the code after the timer expires. Here is what I am using. Note, all three files are concatenated together for this comment.

     

    /**
     * nonblockdelay2.ino
     * 
     * example "blink" program
     *
     */
    
    
    #include "Delay.h"
    
    
    int led = 13;
    int ledstate = HIGH;
    static NonBlockDelay d;
    
    
    void setup()
    {                
      pinMode(led, OUTPUT);
    }
    
    
    // the loop routine runs over and over again forever:
    void loop()
    {
      if(d.Delay(1000))
      {
        ledstate = (ledstate == LOW ? HIGH : LOW); //toggle state
        digitalWrite(led, ledstate);
      }
      //Code here runs frequently
    }
    
    
    //---------------------
    /**
     * Delay.cpp
     *
     */
    
    #include "Delay.h"
    
    
    // Set iTimeout to current millis plus milliseconds to wait for
    /**
     * Called with milliseconds to delay.
     * Return true if timer expired
     * 
     */
    bool NonBlockDelay::Delay (unsigned long t)
    {
      if(TimingActive)
      {
        if((millis() >iTimeout)){
          TimingActive = 0;
          return(1);
        }
        return(0);
      }
      iTimeout = millis() + t;
      TimingActive = 1;
      return(0);
    };
    
    
    
    
    // returns true if timer expired
    bool NonBlockDelay::Timeout (void)
    {
      if(TimingActive){
        if((millis() >iTimeout)){
          TimingActive = 0;
          iTimeout = 0;
          return(1);
        }
      }
      return(false);
    }
    
    
    // Returns the current timeout value in milliseconds
    unsigned long NonBlockDelay::Time(void)
     {
       return iTimeout;
     }
    
    
    //------------------------------
    /**
     * Delay.h
     *
     */
    
    #if defined(ARDUINO) && ARDUINO >= 100
    #include <Arduino.h>
    #else
    #include <WProgram.h>
    #endif
    class NonBlockDelay {
        unsigned long iTimeout;
        bool TimingActive = 0;
      public:
        bool Delay (unsigned long);
        bool Timeout (void);
        unsigned long Time(void);
    };
    //-------------------------

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Robert Peter Oakes
    Robert Peter Oakes over 9 years ago in reply to celem

    A simple solution for non blocking delays is as follows

     

    #define timeDelay   2000 // 2Seconds
    long nextOperation = millis() + timeDelay;
    
    setup()
    {
         .....
    }
    
    loop()
    {
    // stuff done in the main loop()
    .......
    // now the thing we want to only do every timeDelay Period
    if (nextOperation <= millis()
    {
         // Do you thing here 
         nextOperation = millis() + timeDelay; // reset the timer for next time
    }
    
    }

    The thing about this is it will only enter if the time period has elapsed. There are also libraries that can abstract all this for you if you want, but knowing how to do it yourself is always good.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • celem
    celem over 9 years ago

    Andy Clark's solution is concise and makes for readable source - but behaves as a do {..code..}while loop where the 'code' will execute one and the delay only applies to subsequent executions of Timeout(). Using the example code:

    void loop() {
      if (d.Timeout()) {    // always true on first call
        digitalWrite(led, ledstate);
        ledstate = ledstate == LOW ? HIGH : LOW; //toggle state
        d.Delay(1000);
      }

     

    d.Timeout returns (iTimeout < millis()). On the first invocation iTimeout is indeterminate but, unless millis() has turned over, probably less than millis() returns, so 'true' will be returned. Once d.Delay is called iTimeout will be set to millis() + 1000 so subsequent calls to d.Timeout will return 'false' until millis() increments above iTimeout.

     

    This is useful where a do {..code..}while loop is called for, such as blinking the LED but not useful in a delay before executing situation, which is more like a blocking delay() would do. I haven't figured out how to do that yet - meanwhile Andy Clark's solution works for some situations.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • jadew
    jadew over 11 years ago in reply to Workshopshed

    I had a mistake in the DELAY_DONE macro, it's now fixed.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube