element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • 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 & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • 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
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • 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 10919 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 12 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…
  • mcb1
    mcb1 over 12 years ago in reply to Robert Peter Oakes

    Peter

    Depending on the quality of the switch, bouncing is the changing of the state while the switch settles after an action by the user.

    I understood that the mechanical pushbutton switches only had issues when you pressed them, and hence the debounce was only on a closure.

    But you could have trouble with toggle switches where you wanted clean changes on both states.

     

    For this application I didn't actually care if he holds it for 1 sec, 10 secs or forever, as it was only the change from not pushed to pushed I wanted to detect.

     

    The 100mS is a cut and paste error ...which I have gone back and edited.   thanks

     

    Mark

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

    Should  there not be an unclick de-bounce too, 100mS being pressed is great or more specifically 5 consecutive checks but the bouncing in itself will reset the count so there could be longer while the button settles down (Depends on the quality of button), but when you let go, there should also be a secondary check to ensure it is not a bounce in the other direction. Im thinking here the operation with a normally closed connection rather than normally open.

     

    I have some routines I will be publishing soon that will have this as part of the logic.

     

    Software de-bouncing like Mark is describing above is a great thing to include in any project where you can not guarantee clean transitions, even if it is not a mechanical button.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • mcb1
    mcb1 over 12 years ago

    What about simply using the Millis() timer.

    The example BlinkWithoutDelay (stupid name IMO) shows how to do it.

     

    Use an unsigned long variable declaration and always subtract the lower number from the larger and the rollover works fine.

    An example of its use as a debounce on a button

     

      // Button handling variables
      boolean ButtonState = HIGH;           // records the Button State
      unsigned long LastButtonCheck = 0;    // Time the Buttons were last checked.
      unsigned long ButtonPressTime = 0;    // Time the last button was pressed.
      int ButtonCount = 0;                  // Button counter

    if (millis() - LastButtonCheck > 5)                    // Reads button state every 5mS and then updates button counts
          {       
            ButtonState = digitalRead(Pushbutton);
            LastButtonCheck = millis(); 
    
            if (ButtonState == LOW)
            {
              ButtonCount ++;                                     // Increment the Count by 1
              if (ButtonCount > 5)                               // the button should be LOW for 5x5mS = 25mS
              {
                // Button has been pressed for longer than 25mS so its valid
                ButtonPressTime = millis();                       // set the Button press timer
                ButtonCount = 0;
                ProcessButton();                                  // Do something with the valid button press
              }
            }
            else                                                  // Button is HIGH
            {
              ButtonCount =0;                                     // Reset the counter as the button has been released
            }
          }

     

     

    mark

     

    edit ... change the 100mS to 25mS in the comment on line 11

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Workshopshed
    Workshopshed over 12 years ago in reply to e14 Contributor

    Yes, the values will continue to ramp up regardless of the timeout so you need increment inside the if statement. Your test will likely produce a pseudo random result.

    I don't have an arduino to hand to test but something like the following should work

     

    NonBlockDelay ramp;
    int i;
    
    void loop() {
        // The goal is to delay writing new i values to myPin
            if (ramp.Timeout()) {
                analogWrite(myPin, i);
                //Serial.println(i);
                ramp.Delay(1000);
                if (i++ > 256) i = 0;
            }
    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • e14 Contributor
    e14 Contributor over 12 years ago

    Hi,

     

    This is a great class, thanks!  I've got it working with a few examples, but am having trouble getting it working while iterating through a loop.  Do you see any trouble with the syntax of my for-loop here?

     

    NonBlockDelay ramp;
    
    void loop() {
        // The goal is to delay writing new i values to myPin
        for (i=0; i<256; i++) {
            if (ramp.Timeout()) {
                analogWrite(myPin, i);
                //Serial.println(i);
                ramp.Delay(1000);
            }
        }
    }

     

    Thanks for any insights -- this is really puzzling because, oddly enough, if I uncomment line 8, the delay somehow works.  I'm at a loss.

    • 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 © 2026 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.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube