3. System Delay
The delay function is very common in computer programming. It can pause the execution of a program for a period of time to meet various application requirements.
3.1 Purpose of Delay
In programming for the ESP32-S3 or other microcontrollers, delays are widely used, mainly for the following reasons:
- Interacting with hardware: Many hardware devices need some time to respond to a command. For example, if you start a motor in a program and immediately check its status, you may get an incorrect reading because the motor may not have had enough time to start spinning. In this case, you need to use the
delay()function to let the system wait for a period of time so that the motor has enough time to respond. - User interaction: We often need to implement delay effects in user interactions. For example, when a buzzer plays music, there needs to be a period of silence between notes. Or, in the case of a blinking LED, a delay is needed between the "on" and "off" states to control the blinking speed.
- Saving energy: In some applications, such as battery-powered systems, if the system is kept running at high speed for a long time when not needed, the battery life will be greatly shortened. In this case, we can let the system enter standby or low-power mode after a period of time until the next processing cycle arrives.
- Timed operations: In many projects, we often need to implement operations at specific points in time. For example, in an automatic irrigation system, we may need to irrigate at specific times of the day. In interval measurements, we may collect data once at regular intervals. Although the delay function is very useful in many cases, you should also be aware of its blocking nature. Over-reliance on blocking delays may cause the program to respond slowly to other events. To better perform multitasking programming on ESP-IDF, we can also learn some non-blocking delay programming techniques.
What is a blocking delay?
📌 A blocking delay means that during program execution, when an operation or function needs a certain amount of time to complete, the program pauses execution until the operation completes. During this time, the program is blocked. Blocking delays may cause the program to run slower or appear to freeze. For example, suppose you want to boil water to make tea. Normally, you would place the kettle on the stove, heat it, and wait for the water to boil before you can use it. In this process, there is a blocking delay. When you place the kettle on the fire, the program can be thought of as "waiting" for the water to boil. During this waiting period, you cannot immediately get hot water to make tea; you need to wait patiently for the water to boil. During this time, you may not be able to do other things unrelated to boiling water, because you need to keep an eye on the kettle and wait for the right moment. Even if the house is on fire, you are still waiting for the water to boil.
3.2 Implementation of Delay
In ESP-IDF, you can use the following options to implement delays:
vTaskDelay()function This function suspends the current task for a specified time. For example,vTaskDelay(1000 / portTICK_PERIOD_MS)will suspend the current task for 1 second, waiting for one system clock cycle.usleep()function This function can perform precise delays in microseconds. For example,usleep(1000000)will put the task to sleep for 1 second.esp_rom_delay_us()function Can perform microsecond-level delays.
The following is example code that uses the vTaskDelay() function to implement a delay: Note that the vTaskDelay() function requires the freertos/task.h and freertos/FreeRTOS.h header files to be included.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void delay_ms(int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
void app_main(void)
{
// A one-second delay
delay_ms(1000);
}2
3
4
5
6
7
8
9
10
11
Here we use a FreeRTOS concept: the void vTaskDelay( const TickType_t xTicksToDelay ) function delays a task for a given number of xTicksToDelay ticks. The actual time that the task is blocked depends on the tick rate. The constant portTICK_PERIOD_MS can be used to calculate real time from the tick rate, with a resolution of one tick period. Whether one clock tick is 1 ms, 2 ms, or 10 ms depends on configTICK_RATE_Hz, which is CONFIG_FREERTOS_HZ. CONFIG_FREERTOS_HZ is defined in sdkconfig, and the default is 100 Hz. So one clock tick is 10 ms. You can change it to 1000 Hz, which makes one clock tick 1 ms and the timing more precise. However, this also increases system overhead and causes unnecessary waste.
If you need higher-precision delays, you can use the usleep() function. The following is example code that uses the usleep() function to implement a delay:
#include "unistd.h"
void delay_us(int us)
{
usleep(us);
}
void app_main(void)
{
// A one-second delay
delay_us(1000000);
}2
3
4
5
6
7
8
9
10
Note that the usleep() function requires the unistd.h header file.
Use the esp_rom_delay_us() function for microsecond-level delays:
- First, include the header file
esp_rom_sys.h:
#include "esp_rom_sys.h"- Call the
ets_delay_us()function to perform a microsecond-level delay. This function accepts a parameter in microseconds.
esp_rom_delay_us(delay_us);The above are the basic steps for using delay functions in the ESP-IDF environment. Note that ESP-IDF is a multitasking real-time operating system (RTOS), so using the vTaskDelay() function for delays is the recommended method, as it avoids blocking other tasks from executing. Functions such as usleep() are used for scenarios that require more precise microsecond-level delays.
3.3 Blinking LED Verification
Set the GPIO48 pin connected to the LED on the development board to output mode. Through the delay function vTaskDelay(), control the LED to turn on and off for a while, achieving a blinking effect. (For the LED code, please refer to the LED chapter.)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "bsp_led.h"
void app_main(void)
{
// LED initialization
LedGpioConfig();
while(1)
{
// Turn on the LED
LedOn();
// Delay 100 ms, that is, keep it on for 100 ms
vTaskDelay(100 / portTICK_PERIOD_MS);
// Turn off the LED
LedOff();
// Delay 100 ms, that is, keep it off for 100 ms
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
3.4 Blinking LED Effect
After downloading the code, the LED marked G48 on the development board will blink on and off in a continuous loop.