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
  • 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 9376 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…
Parents
  • mcb1
    mcb1 over 11 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
  • jadew
    jadew over 11 years ago in reply to mcb1

    Personally, I prefer hardware debouncing, as for the delay being made simpler / more resource friendly, I agree, a simple variable would have sufficed.

     

    I would have implemented this class as a set of 3 define statements, which would eliminate the overhead the object is bringing in:

     

    #define DELAY_DECLARE(name) volatile unsigned long delay_variable_##name
    #define DELAY_SET(name, time) delay_variable_##name = millis() + time
    #define DELAY_DONE(name) (delay_variable_##name <= millis())
    
    DELAY_DECLARE(test);
    DELAY_SET(test, 1000);
    
    while (!DELAY_DONE(name))
    {
        // do whatever
    }

     

    Edit: I never used an arduino, but if you don't need that millis() thing anywhere else, you could repurpose the timer that is generating that count and use CTC mode instead. Then you just have to check if the compare match flag is set and reset the counter and the flag when that happens. Doing this will make it even more efficient as it will save the CPU time that is wasted incrementing that millis() counter.

     

    Edit 2: I had a mistake in there, it should have been less or equal, not greater or equal for the DELAY_DONE macro. It's fixed now.

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

    >why not simply use Millis() - It is there in the code, it's just abstracted by a class.

     

    I do like the simplicity of the define approach and you raise an interesting point about the use of the volatile keywork which is something I missed, also CTC Mode is something new to me.

     

    For this example can I put the 3 lines into a .h file to include in every project that needs it or does the compiler not work like that? Is re-use a "simple" case of copy and paste?

     

    The reason for using classes was for re-use and abstraction

         as mentioned the idea is to use this for two different motors (which I also plan to control using classes)

         also if I needed longer timing I might switch from using millis() to using the RTC I've attached to my clock.

     

    I did use C/C++ many years ago but I've come back to it recently after a lot of PHP and C# development so my development approach is the build, test, refactor with clarity of code and maintenance being key. I've not applied this to microcontrollors before so don't know how that will work as a strategy.  I've also not got into unit testing on this platform but that's something I'd like to look at.

     

    So far the code I've compiled has come nowhere near the limits of the Arduino Micro I'm using so agressive resource or performance tuning has not been an issue (yet).

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

    >why not simply use Millis() - It is there in the code, it's just abstracted by a class.

     

    I do like the simplicity of the define approach and you raise an interesting point about the use of the volatile keywork which is something I missed, also CTC Mode is something new to me.

     

    For this example can I put the 3 lines into a .h file to include in every project that needs it or does the compiler not work like that? Is re-use a "simple" case of copy and paste?

     

    The reason for using classes was for re-use and abstraction

         as mentioned the idea is to use this for two different motors (which I also plan to control using classes)

         also if I needed longer timing I might switch from using millis() to using the RTC I've attached to my clock.

     

    I did use C/C++ many years ago but I've come back to it recently after a lot of PHP and C# development so my development approach is the build, test, refactor with clarity of code and maintenance being key. I've not applied this to microcontrollors before so don't know how that will work as a strategy.  I've also not got into unit testing on this platform but that's something I'd like to look at.

     

    So far the code I've compiled has come nowhere near the limits of the Arduino Micro I'm using so agressive resource or performance tuning has not been an issue (yet).

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

    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, however in the MCU world, particularly on these small AVRs, it's always a good idea to think about resources as they have a tendency to run out.

     

    Don't worry about not hitting the upper limits of the device yet, you will, every one does image and I think that's when the fun starts.

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

    I'll let you know how I get on

    • 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