Arduino delay:
The delay() function takes an integer argument representing the number of milliseconds delay to wait. This is a blocking function that stops the processor doing anything else until it's finished.
There are two reasons for using the delay function:
You will want to use delay() to slow down the processor e.g. to see an LED flashing or to slow it down between sending commands to devices
Some chips require specific delays when you initialize them for
instance the Hitachi HD44780 needs milliseconds delay in a specific
startup process. The delay function is appropriate in that process since
usually the delays needed are small and the processor does not need to
do anything else during startup.
Microcontrollers operate at a very fast rate (16MHz for an Arduino Uno - the ESP8266 runs at 80 or 160MHz!) and this is a good
thing since you can do more processing. The problem is that to interact
with the real world, you need to slow the processor down since real
world actions do not go at MHz rates! This is where the Arduino delay
function comes in useful.
It is a function that sits in a loop for the number of milliseconds that you give it as an argument. A millisecond is 1/000th of a second so there are 1000 milliseconds in one second ( 1000ms = 1s ).
For a 1 second delay you would use the function delay() in your program as follows:
delay(1000);
For quick simple programs the Arduino delay() function provides a convenient slow-down mechanism. Here's an example program for flashing the on-board LED attached to pin 13 of the Arduino uno.
// Simple LED flash
#define LED 13
//////////////////////////////////////////////
void setup(void) {
pinMode(LED,OUTPUT);
}
//////////////////////////////////////////////
// Arduino Delay LED flash
void loop(){
delay(500);
digitalWrite(LED,HIGH);
delay(500);
digitalWrite(LED,LOW);
}
All it does is initialise the pin as an output in setup(). Then it repeatedly executes the code in loop(). That is, it waits for half a second, then sets the LED on, waits another half a second and sets the LED off. So over the course of 1 second the LED is turned on for half a second and off for half a second. Then that action is repeated endlessly.
So far, everything looks great; Delays work fine and LEDs flash on and off, but delay() has a skeleton in the cupboard.
delay() is a lazy function - it is a DO NOTHING function or a blocking function.
When you use delay(), even though it is sometimes useful, you are throwing away processing power straight out of the window never to be recovered!
When you start to write more substantial programs you will find that using delay interferes with operations.
For example if you wanted to read a input button and react to that button quickly e.g. within 100ms. If you had used a 200ms on/200ms off delay to flash an LED on and off, you could not meet that requirement; 400ms would be lost waiting in the delay routines. This is time that could be better spent in doing useful processing.
So the question now becomes how do you actually create a delay but at the same time use a delay that uses up minimal processor time.
There are actually two ways to do this:
The first option is easier and is explained more here.
The second is more advanced and involves using low level interrupt routines and more hardware (to allow several keys to operate into one interrupt pin).
This Arduino delay gotcha is fairly subtle and you may have already come across it. It is all to do with scoping ( C/C++ rules of when a variable is visible to other functions) and how the Arduino environment (although convenient) does hide what is going on behind the scenes - and this can catch you out.
The following code is trying to control the delay time by passing a variable to the delay function which is changed when a button is pressed.
//////////////////////////////////////////////
void loop(){
uint16_t dly=200;
delay(dly);
digitalWrite(LED,HIGH);
delay(dly);
digitalWrite(LED,LOW);
if (digitalRead(INPUT)) dly=100; else dly=10;
}
When you look at the code it looks perfectly reasonable; Use a variable to hold the delay value and change the value dependent of the state of an input button press, however it does not work! All that happens is that the Arduino delay value is only ever set to 200.
The reason is that the functions setup() and loop() are artificial constructs that make programming
easier (sort of).
The setup() and loop() functions are inherited from the "processing"
environment which is a graphics coding system based on openGL. These two
functions make it easier to explain how a program is written i.e. you
first initialise variables and ports in setup() and then execute code
repeatedly in loop().
In fact the underlying compiler only starts a program from main() and ends at the end of main() - there is no loop! You roll your own loops as required! The actual code that lies above the familiar Arduino words 'setup' and 'loop' is something like this:
// main construct
void main(void) {
setup(); // Call the user defined code for setup
while(1) loop(); // Continuously call the user defined code for loop.
}
As shown above when 'main()' is called, first of all the code within function setup() is executed and then the function loop() is called repeatedly (in a so-called endless loop). This is standard programming practice and all that the Arduino code has done is removed the outer layer so it sort-of simplifies the proceedings so that you only need to write those functions ( setup() and loop() ).
However you can't actually see that loop() is called (hidden in the Arduino code similar to the code above) since you are never aware of the main() function.
The key point is that scoping rules force all local variables to be initialised at the start of any function and lost at exit of that function. Therefore the value of dly is lost at the end of loop() and so the code that sets the new value has no effect. All that happens is that each time the function is started the dly variable is initialised to 200.
To make a function remember values between calls you need to preceded the variable with the word static - meaning that the value of that variable is going no where and is retained between calls to the function.
//////////////////////////////////////////////
// Arduino Delay LED flash that works
void loop(){
static uint16_t dly=200;
delay(dly);
digitalWrite(LED,HIGH);
delay(dly);
digitalWrite(LED,LOW);
if (digitalRead(INPUT)) dly=100; else dly=10;
}
Or how "normal" compilers work - not the Arduino compiler!
The real reason that there is a problem is that in a "standard compiler" program you could have written the whole thing as follows using the main() function.
// main construct Full program non-Arduino compiler code.
// Arduino pins
#define INPUT 5
#define LED 13
void main(void) {
uint16_t dly=200;
pinMode(LED,OUTPUT); // This was the code within setup()
while(1) {} // Endless loop code
delay(dly); // This was the code within loop()
digitalWrite(LED,HIGH);
delay(dly);
digitalWrite(LED,LOW);
if (digitalRead(INPUT)) dly=100; else dly=10;
}
}
In this case the definition of dly does not need to be static since the variable's scope is the whole of the main() function. In this case anything within main() can see and use the variable dly.
This is the sort of code that you will have to write for most microcontrollers since compiler makers do not mess about giving you the easy route that the Arduino IDE/compiler does!
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.