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

ESP32 IDF定时器中断实现GPIO高低电平切换问题求助

问题分析与修正方案

你的代码存在两个核心问题:

  • 函数调用错误:esp_timer_stop_periodic仅需传入定时器句柄一个参数,你传了两个参数(句柄+6000),这会直接导致编译失败。
  • 逻辑设计错误:固定周期的定时器无法实现两种不同时长的电平切换,而且你启动20ms周期后立刻停止定时器,最终定时器根本不会正常工作。

修正后的代码实现

要实现高电平20ms、低电平6ms的交替信号,推荐使用单次定时器:每次触发回调时切换GPIO电平,并根据当前电平状态设置下一次定时器的超时时长。

#include <stdio.h>
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define GPIO_OUTPUT_PIN GPIO_NUM_2

static esp_timer_handle_t timer_handler;
static bool is_high_level = false;

void timer_callback(void *param)
{
    is_high_level = !is_high_level;
    gpio_set_level(GPIO_OUTPUT_PIN, is_high_level);

    // 根据当前电平设置下一次定时器超时时间:高电平20ms,低电平6ms
    uint64_t next_timeout = is_high_level ? 20000 : 6000;
    // 重新启动单次定时器
    ESP_ERROR_CHECK(esp_timer_start_once(timer_handler, next_timeout));
}

void app_main(void)
{
    // GPIO初始化
    gpio_pad_select_gpio(GPIO_OUTPUT_PIN);
    gpio_set_direction(GPIO_OUTPUT_PIN, GPIO_MODE_OUTPUT);
    // 初始设置为低电平
    gpio_set_level(GPIO_OUTPUT_PIN, 0);

    // 创建单次定时器
    const esp_timer_create_args_t my_timer_args = {
        .callback = &timer_callback,
        .name = "signal_timer"};
    ESP_ERROR_CHECK(esp_timer_create(&my_timer_args, &timer_handler));

    // 第一次启动定时器,先进入高电平(20ms后触发回调)
    ESP_ERROR_CHECK(esp_timer_start_once(timer_handler, 20000));

    while (true)
    {
        // 这里可以保留你的其他逻辑
        esp_timer_dump(stdout);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

关键逻辑说明

  1. 单次定时器的复用:每次回调完成电平切换后,根据当前电平状态设置下一次的超时时间,然后重新启动单次定时器,以此实现两种不同时长的交替。
  2. 初始状态控制:初始将GPIO设为低电平,第一次启动定时器设置20ms超时,触发后切换为高电平,之后循环切换。
  3. 函数调用规范:严格遵循ESP-IDF的API要求,esp_timer_start_once用于启动单次触发的定时器,esp_timer_stop(如果需要停止)仅需传入句柄。

内容的提问来源于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.03 21:10:26