一、概述
盡管FreeRTOS提供了軟件計時器,但是這些計時器有一些限制:
最大分辨率等于RTOS滴答周期
計時器回調從低優先級任務分派
硬件計時器不受這兩個限制,但是通常它們使用起來不太方便。例如,應用組件可能需要計時器事件在將來的特定時間觸發,但是硬件計時器僅包含一個用于生成中斷的“比較”值。這意味著需要在硬件計時器之上構建一些設施,以管理掛起事件列表,以便在發生相應的硬件中斷時可以調度這些事件的回調。
esp_timer一組API提供了這種功能。在內部,esp_timer使用64位硬件計時器(CONFIG_ESP_TIMER_IMPL)。esp_timer提供一次性計時器和周期計時器,微秒時間分辨率和64位范圍。
計時器回調是從高優先級esp_timer任務分派的。因為所有回調都是從同一任務分派的,因此,回調不應該做太多工作;相反,它們應該使用RTOS通知機制(隊列、信號量、事件組等)來將信息傳遞給其他任務。
如果其他優先級高于esp_timer運行的任務正在運行,則回調調度將被延遲,直到esp_timer任務有機會運行為止。例如,如果正在進行SPI Flash操作,則會發生這種情況。
創建和啟動計時器以及調度回調需要一些時間。因此,單發超時值有一個下限esp_timer。如果esp_timer_start_once()調用的超時值小于20us,則僅在大約20us之后才調度回調。
周期性esp_timer還會對最小計時器周期施加50us的限制。周期小于50us的定期軟件計時器不切實際,因為它們會占用大部分CPU時間。如果發現需要一個短周期的計時器,請考慮使用專用的硬件外設或DMA功能。
ESP-IDF 編程指南——高分辨率定時器
二、API說明
以下軟件定時器接口位于 esp_timer/include/esp_timer.h。
2.1 esp_timer_init
2.2 esp_timer_deinit
2.3 esp_timer_create
2.4 esp_timer_start_once
2.5 esp_timer_start_periodic
2.6 esp_timer_stop
2.7 esp_timer_delete
2.8 esp_timer_get_time
三、一次性定時器
3.1 定義相關變量
// 定義定時器句柄esp_timer_handle_t test_o_handle = 0;// 定義一個單次運行的定時器結構體esp_timer_create_args_t test_once_arg = {
.callback = &test_timer_once_cb, // 設置回調函數
.arg = NULL, // 不攜帶參數
.name = 'TestOnceTimer' // 定時器名字};
3.2 定義定時器回調函數
void test_timer_once_cb(void *arg) {
int64_t tick = esp_timer_get_time();
printf('方法回調名字: %s , 距離定時器開啟時間間隔 = %lld rn', __func__, tick);
esp_err_t err = esp_timer_delete(test_o_handle);
printf('要刪除的定時器名字:%s , 是否停止成功:%s', test_once_arg.name,
err == ESP_OK ? 'ok!rn' : 'failed!rn');}
要在不再需要計時器時刪除它,請調用esp_timer_delete()。
3.3 創建定時器
#include 'esp_timer.h'void app_main(void){
esp_timer_init(); // 使用定時器API函數,先調用接口初始化
// 開始創建一個單次周期的定時器并且執行
esp_timer_create(&test_once_arg, &test_o_handle);
esp_timer_start_once(test_o_handle, 10 * 1000 * 1000);
while(1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
}}
3.4 查看打印
四、周期定時器
4.1 定義相關變量
// 定義定時器句柄esp_timer_handle_t test_p_handle = 0;// 定義一個周期重復運行的定時器結構體esp_timer_create_args_t test_periodic_arg = {
.callback = &test_timer_periodic_cb, // 設置回調函數
.arg = NULL, // 不攜帶參數
.name = 'TestPeriodicTimer' // 定時器名字};
4.2 定義定時器回調函數
void test_timer_periodic_cb(void *arg) {
int64_t tick = esp_timer_get_time();
printf('方法回調名字: %s , 距離定時器開啟時間間隔 = %lld rn', __func__, tick);
if(tick > 100000000)
{
// 停止定時器工作,并獲取是否停止成功
esp_err_t err = esp_timer_stop(test_p_handle);
printf('要停止的定時器名字:%s , 是否停止成功:%s', test_periodic_arg.name,
err == ESP_OK ? 'ok!rn' : 'failed!rn');
err = esp_timer_delete(test_p_handle);
printf('要刪除的定時器名字:%s , 是否停止成功:%s', test_periodic_arg.name,
err == ESP_OK ? 'ok!rn' : 'failed!rn');
}}
要在不再需要計時器時刪除它,請調用esp_timer_delete()。
請注意,當esp_timer_start_once()或esp_timer_start_periodic()調用計時器時,計時器一定不能運行。要重新啟動正在運行的計時器,esp_timer_stop()請先調用,然后調用啟動功能之一。
4.3 創建定時器
#include 'esp_timer.h'void app_main(void){
esp_timer_init(); // 使用定時器API函數,先調用接口初始化
// 開始創建一個重復周期的定時器并且執行
esp_err_t err = esp_timer_create(&test_periodic_arg, &test_p_handle);
err = esp_timer_start_periodic(test_p_handle, 1000 * 1000);
printf('重復周期運行的定時器創建狀態碼: %s', err == ESP_OK ? 'ok!rn' : 'failed!rn');
while(1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
}}
4.4 查看打印
上一篇:ESP32學習筆記(4)——UART串口使用
下一篇:ESP32學習筆記(2)——GPIO接口使用
推薦閱讀最新更新時間:2025-05-04 11:28



