ESP32高分辨率定时器(esp_timer)应用指南
一、为什么需要esp_timer?
FreeRTOS软件定时器存在两大限制:
- 最大分辨率受限于RTOS节拍周期(通常1ms)
- 回调函数在低优先级任务中调度
ESP32的硬件定时器虽然不受此限制,但直接操作复杂。esp_timer
API通过以下方式解决了这些问题:
- ✅ 使用64位硬件定时器(CONFIG_ESP_TIMER_IMPL)
- ✅ 提供微秒级分辨率(1μs)
- ✅ 支持单次和周期定时
- ✅ 自动管理待处理事件队列
二、核心特性与限制
关键优势
- 高优先级回调:从专用
esp_timer
任务分派(优先级高于普通应用任务) - 64位时间戳:
esp_timer_get_time()
返回微秒级单调时间
使用限制
类型 | 最小周期 | 原因 |
---|---|---|
单次定时 | ≥20μs | 调度开销 |
周期定时 | ≥50μs | 避免CPU过载 |
重要提示:回调函数应保持简短,避免阻塞。耗时操作需通过队列/信号量移交其他任务。
三、API 工作流程
四、实战代码示例
单次定时器实现
// 定义定时器句柄及参数
esp_timer_handle_t once_timer;
esp_timer_create_args_t once_args = {
.callback = timer_once_callback,
.arg = NULL,
.name = "SingleShotTimer"
};
// 回调函数
void timer_once_callback(void* arg) {
int64_t elapsed = esp_timer_get_time();
printf("[%.6fs] 单次定时器触发\n", elapsed / 1e6f);
// 删除定时器(必需!)
esp_timer_delete(once_timer);
}
void app_main() {
esp_timer_init();
// 创建并启动定时器(10秒后触发)
ESP_ERROR_CHECK(esp_timer_create(&once_args, &once_timer));
ESP_ERROR_CHECK(esp_timer_start_once(once_timer, 10 * 1000000));
}
周期定时器实现
esp_timer_handle_t periodic_timer;
esp_timer_create_args_t periodic_args = {
.callback = timer_periodic_callback,
.name = "PeriodicTimer"
};
void timer_periodic_callback(void* arg) {
static int count = 0;
int64_t time = esp_timer_get_time();
printf("[#%d] 周期定时触发: %.3fms\n", ++count, time / 1000.0f);
// 运行100秒后停止
if (time > 100 * 1000000) {
ESP_ERROR_CHECK(esp_timer_stop(periodic_timer));
ESP_ERROR_CHECK(esp_timer_delete(periodic_timer));
printf("定时器已停止并删除\n");
}
}
void app_main() {
esp_timer_init();
// 创建并启动1秒周期定时器
ESP_ERROR_CHECK(esp_timer_create(&periodic_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 1000000));
}
五、关键注意事项
- 资源释放:必须调用
esp_timer_delete()
释放定时器资源 - 重启机制:重启运行中的定时器需先
stop
再start
- Flash操作延迟:SPI Flash操作期间回调可能被延迟
- 回调设计原则:
// 正确做法:快速传递数据 void good_callback(void* arg) { xQueueSend(data_queue, &sensor_data, 0); } // 错误做法:在回调中执行长操作 void bad_callback(void* arg) { vTaskDelay(100); // 绝对禁止! process_image(); // 耗时操作 }
六、性能对比
特性 | esp_timer | FreeRTOS定时器 |
---|---|---|
分辨率 | 1μs | ≥1ms |
回调执行上下文 | 高优先级任务 | 低优先级任务 |
最小单次触发 | 20μs | 1个tick |
最小周期 | 50μs | 1个tick |
需要更高实时性?考虑使用硬件外设(如GPTimer)或DMA传输!
完整API文档见ESP-IDF编程指南
版权声明:本文核心内容基于Espressif官方文档,示例代码采用MIT许可证,商业转载需注明出处。