ESP32 IDF定时器中断任务问题:GPIO20ms高/6ms低电平信号生成故障排查
ESP32 IDF定时器生成20ms高/6ms低电平信号问题修正
问题分析
你的代码存在几个关键问题导致无法生成预期信号:
- 启动定时器后立刻调用
esp_timer_stop,定时器根本没有机会触发回调,GPIO电平不会发生变化。 - 使用两个周期定时器的思路错误:两个周期定时器会各自按固定间隔触发,导致GPIO电平被反复覆盖,无法形成稳定的20ms高+6ms低的循环逻辑。
- 复用了同一个
timer_handler变量,第一个定时器的句柄被第二个覆盖,会造成内存泄漏。
修正方案
正确的思路是使用一个一次性定时器,在回调函数中切换GPIO电平,并根据当前电平状态设置下一次定时器触发的时长(高电平时设置20ms后触发,低电平时设置6ms后触发),以此循环往复。
修正后的代码:
#include <stdio.h> #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" #include <stdbool.h> #include "esp_err.h" // 全局变量记录当前GPIO电平状态 static bool gpio_high = false; static esp_timer_handle_t timer_handler; void timer_callback(void *param) { gpio_high = !gpio_high; gpio_set_level(GPIO_NUM_2, gpio_high ? 1 : 0); // 根据当前电平设置下一次触发的时间 uint64_t next_timeout = gpio_high ? 20000 : 6000; // 再次启动一次性定时器,形成循环 ESP_ERROR_CHECK(esp_timer_start_once(timer_handler, next_timeout)); } void app_main(void) { // GPIO初始化 gpio_pad_select_gpio(GPIO_NUM_2); gpio_set_direction(GPIO_NUM_2, GPIO_MODE_OUTPUT); // 创建定时器 const esp_timer_create_args_t timer_args = { .callback = &timer_callback, .name = "signal_timer" }; ESP_ERROR_CHECK(esp_timer_create(&timer_args, &timer_handler)); // 首次启动定时器:初始设为低电平,6ms后切换为高电平 gpio_set_level(GPIO_NUM_2, 0); ESP_ERROR_CHECK(esp_timer_start_once(timer_handler, 6000)); while (true) { esp_timer_dump(stdout); vTaskDelay(pdMS_TO_TICKS(1000)); } }
关键理解纠正
- 周期定时器vs一次性定时器:周期定时器适合固定间隔的重复任务,而高低电平时长不同的场景需要用一次性定时器动态调整触发间隔。
- 定时器启动后不能立即停止:
esp_timer_start_periodic或esp_timer_start_once调用后,必须让定时器保持运行状态,才能触发回调函数执行逻辑。 - 定时器句柄不能复用:每个定时器需要独立的句柄变量,避免覆盖导致的资源泄漏或逻辑错误。
内容的提问来源于stack exchange,提问作者Balaji Baski
相关产品推荐
相关产品推荐

