You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:50:31