When programming microcontrollers like the AVR, timing control plays a crucial role in almost every embedded application. From blinking an LED to generating signals, reading sensors, or controlling motors — timing defines the behavior of the system. In real-world applications, it’s often necessary to create precise delays between operations. For example, we might want an LED to remain ON for one second and OFF for another, or we may need a few microseconds of delay between data transmissions. To achieve this, AVR C programming offers several methods to generate software and hardware-based delays. This post will explain how delay functions work, how to use the built-in delay libraries, and what considerations are important when writing reliable delay-based code.
What are Delay Functions?
A delay function is a small section of code that holds or pauses program execution for a specific time duration.
In AVR, delay functions can be implemented manually using loops or by using predefined library functions provided in the <util/delay.h> header file.
These functions use the CPU clock cycles to generate accurate timing based on the system frequency.
F_CPU.
Always set the correct frequency before using any delay function.
Using the <util/delay.h> Library
AVR-GCC provides a very handy header file called util/delay.h that includes two major delay functions:
_delay_ms()– Generates a delay in milliseconds._delay_us()– Generates a delay in microseconds.
These functions are implemented using calibrated software loops that depend on the CPU frequency. Before using them, you must define the CPU frequency at the beginning of your program using:
#define F_CPU 8000000UL // 8 MHz crystal frequency
#include <avr/io.h>
#include <util/delay.h>
Once defined, the compiler uses this value to generate accurate timing delays.
Example: LED Blinking Using Delay Function
The following example demonstrates a simple LED blinking program using the built-in delay functions:
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRB |= (1 << PB0); // Set PB0 as output
while(1)
{
PORTB |= (1 << PB0); // Turn LED ON
_delay_ms(1000); // Delay for 1 second
PORTB &= ~(1 << PB0); // Turn LED OFF
_delay_ms(1000); // Delay for 1 second
}
}
In the above example, the LED connected to pin PB0 will turn ON and OFF alternately every second,
creating a blinking effect. The _delay_ms() function holds program execution for 1000 milliseconds (1 second) before proceeding.
Custom Delay Function Using Loops
If you prefer not to use the <util/delay.h> library or need variable delays calculated at runtime,
you can implement your own delay function using nested loops.
Though this method is less accurate, it is simple and sometimes useful in time-insensitive applications.
void delay_ms(unsigned int ms)
{
for(unsigned int i=0; i<ms; i++)
{
for(unsigned int j=0; j<255; j++);
}
}
Here, the inner loop creates a short delay, and the outer loop repeats it multiple times. The total delay time depends on the clock frequency and the number of loop iterations. You can adjust the inner loop limit to change the approximate duration.
Hardware Timer-Based Delays
For high accuracy and longer durations, AVR timers are often used instead of software delays. Timers can generate delays independently of the CPU, allowing multitasking or interrupt-based operations. These are extremely useful in applications like motor control, signal generation, and sensor timing.
The above diagram shows how the CPU clock drives the timer registers to generate precise delay outputs or interrupts. This method is more efficient than software delays and is widely used in real-time embedded systems.
Conclusion
Delay functions are essential for managing timing in embedded systems.
Whether you use software-based delays through util/delay.h or hardware timers,
choosing the right approach depends on the required precision and system design.
For beginners, the built-in delay functions are simple and effective.
As you advance, understanding timer registers and interrupt-based delays becomes critical for creating reliable, real-time AVR applications.
Comments
Post a Comment
Subscribe to Post Comments [Atom]