8. Timer
8.1 Timer Introduction
A timer is integrated inside a microcontroller and can be controlled through programming. The microcontroller's timing function is implemented by counting. When one pulse is generated in each machine cycle, the counter increments by one. The main function of a timer is to measure time. When the specified time is reached, it can generate an interrupt to notify that the timing period has elapsed, and the interrupt function can then execute a task. For example, if we want an LED to toggle every 1 second, we can configure a timer to trigger an interrupt every 1 second and execute the LED toggle code inside the interrupt function.
8.2 Hardware Timers and Software Timers
Timers can be implemented using hardware or software. They have different characteristics and application scenarios:
- A hardware timer is a timing function provided by microcontroller hardware and implemented by a dedicated timer/counter circuit. The biggest advantages of hardware timers are high precision and strong reliability because they are not affected by software tasks or operating system scheduling. When very accurate timing is required, such as generating PWM signals or obtaining precise time measurements, a hardware timer is preferred. Since timing is handled directly by hardware, the timer can execute callback operations accurately at the scheduled time even if the main CPU is busy with other tasks.
- A software timer is implemented by an operating system or software library. It uses mechanisms provided by the operating system to simulate timer functions. Software timers are affected by current system load and task scheduling strategies, so they are generally less accurate than hardware timers. However, software timers are usually more flexible, can be created in large numbers, and are suitable for applications that do not require precise time control.
- In some cases, software timers may cause timing accuracy issues, for example under high load or when many other high-priority tasks exist in the system. For simple delays that do not require high precision, software timers are usually sufficient.
8.3 Basic Timer Parameters
The ESP32S3 chip has multiple hardware timers, such as Timer0, Timer1, and Timer2. Each timer contains multiple channels. You can select a specific timer and channel by specifying the timer number and channel number. Basic timer parameters include timer number, channel number, prescaler, auto-reload value, timer interrupt enable, and so on.
The following are some basic concepts and common timer attributes:
- Counter: the core component of the timer, responsible for continuous counting.
- Timer overflow: occurs when the counter reaches its maximum value and then returns to zero.
- Preset value: generates an interrupt or another event when the counter reaches this value.
- Prescaler: reduces the frequency of the clock signal received by the counter to extend the maximum timing range of the timer.
- Interrupt: when the timer reaches the preset value, it can be configured to generate an interrupt, and the interrupt handler executes certain tasks.
8.4 Timer Usage Flow
8.4.1 Create a Timer Object
Declare a global variable of type hw_timer_t at the top of the program to represent the timer object. Example:
hw_timer_t *timer = NULL;8.4.2 Initialize the Timer
Initialize the timer in the setup() function. During initialization, set the timer period and bind the interrupt function. Example:
void setup()
{
// Initialize the timer
timer = timerBegin(1000000);
// Enable the timer interrupt
timerAttachInterrupt(timer, onTimerISR);
// Set the target counter value for the timer alarm and enable infinite repeat counting
timerAlarm(timer,1000000,true, 0);
}2
3
4
5
6
7
8
9
10
11
In the example above, the timerBegin() function initializes the timer and sets the timer frequency to 1000000 Hz. Converted to time, this means the timer counts 1000000 times per second, or once every 1 microsecond. Next, timerAttachInterrupt() binds the timer interrupt service function onTimerISR and enables the timer interrupt.
The following describes the timer configuration functions:
hw_timer_t * timerBegin(uint32_t frequency);: initializes a hardware timer. Parameter description:
frequency: sets the timer frequency. The timer clock source has already been configured for you inside this function, so you only need to set the timer frequency. The timer frequency affects the timer counting period. The counting period is determined by the timer frequency. Since the timer frequency in the code example above is set to 1000000 Hz, or 1 MHz, the time for each timer count is1 / 1000000 = 0.000001 seconds = 1 microsecond.
void timerAttachInterrupt(hw_timer_t * timer, voidFuncPtr userFunc): associates an interrupt handler with a specific timer. Parameters:
timer: timer pointer.userFunc: interrupt handler.
void timerAlarm(hw_timer_t * timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count): configures the timer alarm or interrupt value.
timer: timer pointer.alarm_value: alarm value. When the timer counts from 0 to this value, an interrupt is triggered.autoreload: whether to enable automatic reload of the counter value. When the alarm value is reached, the counter changes toreload_countand starts counting again.trueenables it, andfalsedisables it.reload_count: counter value to reload.
8.4.3 Timer Interrupt Service Function
Using the example above, write the timer interrupt processing logic in onTimerISR(), such as reading sensor data or controlling peripherals. Write the corresponding code according to actual needs. The interrupt service function name is not fixed; it only needs to follow C naming rules.
8.5 Hardware Connection and Preparation
This example uses an LED to test the timer effect. The LED state change is placed in the timer interrupt handler. The timer duration is set to 1 second. When the timer period expires, an interrupt is triggered and the LED state changes.
8.6 Timer Verification
The following code is based on Arduino V2.3.3 and esp32 3.1.0-RC1.
#define LED 48
// Define a timer object
hw_timer_t *timer = NULL;
// Timer interrupt handler
void timer_interrupt()
{
// Change the LED state. If it is on, turn it off; if it is off, turn it on.
digitalWrite(LED, !digitalRead(LED));
}
void setup()
{
// Set the LED pin (48) to output mode
pinMode(LED, OUTPUT);
// Initialize the timer frequency to 1 MHz
timer = timerBegin(1000000);
// Configure the timer interrupt service function
// The interrupt callback function of timer 0 is timer_interrupt()
timerAttachInterrupt(timer,timer_interrupt);
// Set the timer counter value
// The timer counter value is 1,000,000. true enables auto-reload.
// The counter unit is us. 1,000,000 us = 1000 ms = 1 s
timerAlarm(timer,1000000,true, 0);
}
void loop()
{
}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
29
30
31
32
33
34
8.7 Timer Effect
The LED turns on and off once every second.