Skip to content

  • 下面是门主引擎为你系统梳理 ESP32-S3 定时器的学习框架(基于ESP-IDF)。
  • 注意晶振质量:如果你的 DevKit 没有乐鑫(Espressif)标识的开发板晶振可能偏差较大(~100 ppm),长时间计时会有明显误差,这是产品、盗版硬件问题,与定时器类型无关

1. SDK路径:ESP-IDF 定时器需要掌握的核心知识点

1.1 ESP-IDF有哪些定时器?

ESP-IDF 中的定时器分为两大类:

定时器
├── 系统定时器
│   ├── esp_timer(高分辨率软件定时器)
│   └── FreeRTOS Timer(RTOS 软件定时器)
└── 通用定时器
    └── GPTimer(独立硬件定时器)
  1. ESP 定时器(高分辨率定时器)🔗
  2. ESP 定时器分类🔗
  3. 超时值限制🔗

2. 整体流程:各定时器的运行机制如何?

2.1 esp_timer 运行机制

硬件系统定时器计数
    ↓ 超时
ISR 通知 esp_timer 任务

高优先级 esp_timer 任务串行执行回调函数

2.2 GPTimer 运行机制(定时器中断读取 AHT30 温湿度数值的方案)

硬件定时器组外设计数(完全由硬件完成)
    ↓ 计数值达到警报值
触发中断(ISR 回调)

ISR 中发送消息到队列(xQueueSendFromISR)

普通任务从队列读取消息(xQueueReceive)

执行 I2C 读取 AHT30、esp_log 打印

关键点:GPTimer硬件计数完全独立,中断处理的延迟不影响定时精度。(General Purpose)

3. 对比区别:如何依据场景需求选择定时器?

3.1 图表对比

对比项GPTimer(硬件定时器)esp_timer(软件定时器)FreeRTOS Timer
时钟源XTAL_CLK / APB_CLKXTAL_CLKFreeRTOS Tick
分辨率纳秒级(可配置)1 µs~1–10 ms(Tick 周期)
回调上下文ISR 中直接执行高优先级任务(默认)低优先级定时器任务
硬件资源独享,不受其他模块干扰系统共用,阻塞时受影响纯软件,无硬件资源
额外功能事件捕获、ETM 联动睡眠时间自动补偿
使用难度较复杂,精度最高简单最简单

3.2 如何选择定时器?

定时器分辨率适用场景
esp_timer1 µs软件定时,管理多个定时器,使用简单
GPTimer纳秒级可配置高精度、波形生成、事件捕获
FreeRTOS Timer受 tick 频率限制(通常 1~10 ms)简单延时,可移植性好

4. 定时器中断的两种分发方式怎么理解?

4.1 定时器选择推荐:

针对多传感器场景,推荐使用 esp_timer

  • 定时需求是"每隔一小时触发一次",精度要求不高,esp_timer 的 1 µs 分辨率完全足够。
  • esp_timer 支持周期性定时器,可以自动重启,无需手动管理。
  • 它能处理多个定时器实例,适合同时管理 AHT30、BMP280 等多个传感器的采集周期。
  • 支持从 Light-sleep 唤醒后自动补偿睡眠时间,保持时间准确。

4.1 回调分发方式选择

esp_timer 提供两种回调分发方式:

  • 任务分发法(默认):从高优先级 esp_timer 任务中分发回调,适合你的场景(每小时触发一次,对时序要求不高)。在回调中使用 FreeRTOS 队列/信号量通知对应的传感器采集任务即可。(推荐使用)
  • 中断分发法(ISR):延迟更低,适合运行时间仅几微秒的简单回调。(这个方法要用 idf.py menuconfig,或者是打开 SDK configuration 在里面配置相关的参数)

esp_timer中断分发法SDKconfig

5. ESP32-S3 模组及模组时钟源分析

5.1 为什么深睡眠模式需要结合外部无源晶振来补偿时间?

ESP 定时器会初始化-深睡眠模式可选查看🔗

  1. ESP32-S3 核心开发板上面的 ESP32-S3 模组里面,已经集成了一个 40MHz 的外部高速晶振。这个晶振是非常稳定的,但是模组并没有集成外部低速的 32.768kHz 无源晶振(即类似石英表使用的时钟源)。
  2. 目前该模组集成的是 RC 振荡器。RC 振荡器的原理是利用电阻电容的充放电过程,受温度影响较大,因此在几个小时之内可能会产生几秒的偏移误差。如果长期使用,这种累积性的误差会非常显著。
  3. 因此,在以下场景中需要结合外部无源晶振作为补偿:
    1. ESP32-S3 需要进入深度睡眠(Deep Sleep)。
    2. 需要结合定时器中断,周期性地采集传感器数值。
  4. 补偿原理:
    1. 高速晶振(40MHz)是与内部数字内核及 CPU 关联的。当 CPU 等数字内核进入深度睡眠后,高速晶振将停止工作,无法累积计算当前时间。
    2. 那么在深度睡眠结束并退出时,就需要使用外部低速晶振源(或者内部低速 RC 振荡器)来补偿和计算具体睡眠了多久。为了保证精度,建议使用外部低速无源晶振。因为外部的低速无源晶振在深度睡眠的时候,依旧是工作的。

5.2 ESP32-S3 GPTimer 硬件定时器外设

5.2.1 为什么是 GPTimer?

GPTimer 是基于 ESP32-S3 的定时器组(Timer Group)外设实现的,它具有真正的硬件计数器: 所有通用定时器均基于 16 位预分频器和 54 位可自动重新加载向上/向下计数器。 这和 STM32 的定时器结构非常相似:

  • 预分频器(Prescaler):16 位,分频系数 2~65536
  • 计数器(Counter):54 位,可配置向上或向下计数
  • 自动重装(Auto-reload):硬件层面自动重装计数值
  • 报警/比较值(Alarm/Compare):计数器到达设定值时触发中断

5.2.2 esp_timer 和 GPTimer 的本质区别

GPTimeresp_timer
本质硬件计数器,直接操作寄存器软件定时器,基于系统定时器实现
类比 STM32✅ 类似 STM32 的 TIMx 定时器❌ 更像 STM32 的 SysTick 软件定时器
计数器可读✅ 可通过 gptimer_get_raw_count() 读取实时计数值❌ 没有直接暴露计数器
分辨率纳秒级可配置固定 1 µs

6. 如何使用esp_timer软件定时器实现定时器中断?

6.1 示例一:纯 esp_timer 模拟 LED 闪烁

6.1.1 纯 esp_timer 模拟 LED 闪烁具体步骤说明

步骤做什么实现的功能
1初始化 GPIO 38 为输出模式让引脚可以控制 LED
2创建"亮灯定时器"(led_on_timer)负责 5 秒后点亮 LED
3创建"熄灯定时器"(led_off_timer)负责 5 秒后熄灯并调用亮灯LED
4启动触发定时器(一次性,5 秒后触发)开始计时
5亮灯定时器到期 → 回调点亮 LED,启动熄灭定时器LED 亮起,同时开始 5 秒倒计时
6熄灭定时器到期 → 回调熄灭 LED,重新启动亮灯定时器LED 熄灭,等待下一个 5 秒

6.1.2 纯 esp_timer 模拟 LED 闪烁代码实现

C

#include "esp_timer.h"      // esp_timer 相关 API
#include "esp_log.h"        // ESP_LOGI 日志打印
#include "driver/gpio.h"    // GPIO 控制

#define LED_GPIO            GPIO_NUM_38         // LED 连接的引脚号
#define BLINK_INTERVAL_US   (5 * 1000000)       // 5 秒,单位:微秒
#define LED_ON_DURATION_US  (1 * 1000000)       // 亮 1 秒,单位:微秒

static const char *TAG = "ESP_TIMER_LED";

// -------------------------------------------------------
// 定时器句柄:相当于定时器的"身份证",后续操作都靠它
// -------------------------------------------------------
static esp_timer_handle_t led_on_timer_handle  = NULL; // 触发闪烁的定时器
static esp_timer_handle_t led_off_timer_handle = NULL; // 熄灭 LED 的定时器



// -------------------------------------------------------
// 回调函数 A:点亮 LED,然后启动 1 秒后熄灭的定时器
// 这个函数在"触发定时器"到期时自动被调用
// -------------------------------------------------------
static void led_on_callback(void *arg)
{
    gpio_set_level(LED_GPIO, 1);  // 点亮 LED(输出高电平)
    ESP_LOGI(TAG, "LED ON");

    // 启动熄灭定时器,1 秒后熄灭 LED
    ESP_ERROR_CHECK(esp_timer_start_once(led_off_timer_handle, LED_ON_DURATION_US));
}



// -------------------------------------------------------
// 回调函数 B:熄灭 LED,然后重新启动 5 秒触发定时器
// 这个函数在"熄灭定时器"到期时自动被调用
// -------------------------------------------------------
static void led_off_callback(void *arg)
{
    gpio_set_level(LED_GPIO, 0);  // 熄灭 LED(输出低电平)
    ESP_LOGI(TAG, "LED OFF");

    // 重新启动触发定时器,等待下一个 5 秒
    // esp_timer_start_once:一次性定时器,到期后只触发一次
    ESP_ERROR_CHECK(esp_timer_start_once(led_on_timer_handle, BLINK_INTERVAL_US));
}



void app_main(void)
{
    // -------------------------------------------------------
    // 第一步:初始化 GPIO 38 为输出模式
    // -------------------------------------------------------
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << LED_GPIO),  // 选择引脚 38
        .mode         = GPIO_MODE_OUTPUT,    // 设置为输出模式
        .pull_up_en   = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type    = GPIO_INTR_DISABLE,   // 不使用 GPIO 中断
    };
    gpio_config(&io_conf);
    gpio_set_level(LED_GPIO, 0);  // 初始状态:LED 熄灭

    // -------------------------------------------------------
    // 第二步:创建"点亮 LED"定时器
    // -------------------------------------------------------
    const esp_timer_create_args_t led_on_timer_args = {
        .callback = &led_on_callback,  // 到期时调用 led_on_callback
        .name     = "led_on_timer",
    };
    ESP_ERROR_CHECK(esp_timer_create(&led_on_timer_args, &led_on_timer_handle));

    // -------------------------------------------------------
    // 第三步:创建"熄灭 LED"定时器
    // esp_timer_create_args_t:定时器配置参数结构体
    //   .callback:定时器到期时调用哪个函数
    //   .name:定时器名字(调试用,随便起)
    // -------------------------------------------------------
    const esp_timer_create_args_t led_off_timer_args = {
        .callback = &led_off_callback,  // 到期时调用 led_off_callback
        .name     = "led_off_timer",
    };
    // esp_timer_create:根据配置参数创建定时器,把"身份证"存入 led_off_timer_handle
    ESP_ERROR_CHECK(esp_timer_create(&led_off_timer_args, &led_off_timer_handle));


    // -------------------------------------------------------
    // 第四步:启动触发定时器,5 秒后第一次触发
    // esp_timer_start_once:一次性定时器,到期后自动停止
    // -------------------------------------------------------
    ESP_ERROR_CHECK(esp_timer_start_once(led_on_timer_handle, BLINK_INTERVAL_US));
    ESP_LOGI(TAG, "Start LED timer");

    // -------------------------------------------------------
    // app_main 直接返回,主任务自动删除
    // 定时器会继续在后台运行,不受影响
    // -------------------------------------------------------
}

6.2 示例二:Task + 信号量 + esp_timer(推荐用于实际项目)

6.2.1 Task + 信号量 + esp_timer实现的具体步骤说明

步骤做什么实现的功能
1初始化 GPIO 38让引脚可以控制 LED
2创建二值信号量定时器和 Task 之间的"通知桥梁"
3创建"亮灯定时器"负责 1 秒后点亮 LED
4创建"周期性闪烁定时器"每 5 秒自动触发一次,释放信号量
5创建 LED 控制 Task专门等待信号量,收到后操作 LED
6定时器回调释放信号量 → Task 收到信号量 → 点亮 LED → 启动熄灭定时器完整的闪烁流程

6.2.2

C
#include "esp_timer.h"              // esp_timer 相关 API
#include "esp_log.h"                // 日志打印
#include "driver/gpio.h"            // GPIO 控制
#include "freertos/FreeRTOS.h"      // FreeRTOS 基础
#include "freertos/task.h"          // xTaskCreate 等任务 API
#include "freertos/semphr.h"        // 信号量 API

// -------------------------------------------------------
// 宏定义:引脚号和时间间隔
// -------------------------------------------------------
#define LED_GPIO              GPIO_NUM_38
#define INTERVAL_US   (5 * 1000000)   // 每 5 秒触发一次亮灯,单位:微秒
#define LED_ON_DURATION_US    (1 * 1000000)   // 亮灯持续 1 秒,单位:微秒

static const char *TAG = "LED_TIMER_TASK";

// -------------------------------------------------------
// 全局变量
// -------------------------------------------------------

// 二值信号量:只有"有信号(1)"和"无信号(0)"两种状态
// 定时器回调通过它通知 Task:"该亮灯了"
static SemaphoreHandle_t  led_sem_handle      = NULL;

// 亮灯触发定时器的句柄:每 5 秒触发一次,通知 Task 亮灯
static esp_timer_handle_t led_on_timer_handle    = NULL;

// 熄灯定时器的句柄:亮灯 1 秒后触发,将 LED 熄灭
static esp_timer_handle_t led_off_timer_handle   = NULL;

// -------------------------------------------------------
// 回调函数 A:熄灯
// 当"熄灯定时器"到期(亮灯 1 秒后),自动调用此函数
// 执行位置:esp_timer 内部任务(非中断上下文)
// -------------------------------------------------------
static void led_off_callback(void *arg)
{
    gpio_set_level(LED_GPIO, 0);    // 将 GPIO 38 输出低电平 → LED 熄灭
    ESP_LOGI(TAG, "LED 熄灭");
}

// -------------------------------------------------------
// 回调函数 B:释放信号量,通知 Task 执行亮灯操作
// 当"亮灯触发定时器"每 5 秒到期时,自动调用此函数
// 注意:此处只释放信号量,不直接操作 GPIO
//       实际亮灯操作在 Task 中完成,符合 ESP-IDF 最佳实践
// -------------------------------------------------------
static void led_sem_callback(void *arg)
{
    // xSemaphoreGiveFromISR:在回调/中断上下文中释放信号量
    // 第二个参数 NULL:不需要请求任务切换
    xSemaphoreGiveFromISR(led_sem_handle, NULL);
}

// -------------------------------------------------------
// LED 控制 Task:专门负责等待信号量并执行亮灯操作
// 收到信号量 → 点亮 LED → 启动熄灯定时器(1 秒后熄灭)
// 使用 for(;;) 无限循环,符合 FreeRTOS Task 的标准写法
// -------------------------------------------------------
static void led_control_task(void *pvParameters)
{
    for (;;) {
        // xSemaphoreTake:等待信号量
        // portMAX_DELAY:永久等待,直到信号量到来为止
        // 在等待期间,此 Task 处于阻塞状态,不占用 CPU
        if (xSemaphoreTake(led_sem_handle, portMAX_DELAY) == pdTRUE) {

            // 收到信号量,说明 5 秒定时器已到期,执行亮灯
            gpio_set_level(LED_GPIO, 1);    // 将 GPIO 38 输出高电平 → LED 点亮
            ESP_LOGI(TAG, "LED 点亮");

            // 启动熄灯定时器:1 秒后自动调用 led_off_callback 熄灭 LED
            // esp_timer_start_once:一次性定时器,到期后只触发一次,不自动重复
            // 注意:若上一次熄灯定时器还未到期,需先调用 esp_timer_stop() 再启动
            esp_timer_stop(led_off_timer_handle);  // 确保熄灯定时器未在运行
            ESP_ERROR_CHECK(esp_timer_start_once(led_off_timer_handle, LED_ON_DURATION_US));
        }
    }
}

// -------------------------------------------------------
// app_main:程序入口,完成所有初始化后直接返回
// 返回后主任务自动删除,其他 Task 和定时器继续运行
// -------------------------------------------------------
void app_main(void)
{
    // -------------------------------------------------------
    // 第一步:初始化 GPIO 38 为输出模式
    // gpio_config_t:GPIO 配置结构体
    // -------------------------------------------------------
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << LED_GPIO),  // 选择引脚 38(位掩码形式)
        .mode         = GPIO_MODE_OUTPUT,    // 设置为输出模式
        .pull_up_en   = GPIO_PULLUP_DISABLE, // 不启用内部上拉
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type    = GPIO_INTR_DISABLE,   // 不使用 GPIO 中断
    };
    gpio_config(&io_conf);
    gpio_set_level(LED_GPIO, 0);  // 初始状态:LED 熄灭

    // -------------------------------------------------------
    // 第二步:创建二值信号量
    // 二值信号量只有两种状态:有信号(1)和无信号(0)
    // 定时器回调"给出"信号量,Task"取走"信号量
    // -------------------------------------------------------
    led_sem_handle = xSemaphoreCreateBinary();



    // -------------------------------------------------------
    // 第三步:创建"sem 定时器"(周期性)
    // -------------------------------------------------------
    const esp_timer_create_args_t led_on_timer_args = {
        .callback = &led_sem_callback,  // 到期时释放信号量
        .name     = "led_sem_timer",
    };
    ESP_ERROR_CHECK(esp_timer_create(&led_on_timer_args, &led_on_timer_handle));


    // -------------------------------------------------------
    // 第四步:创建"熄灯定时器"
    // esp_timer_create_args_t:定时器配置参数
    //   .callback:定时器到期时调用哪个函数
    //   .name:定时器名字(仅用于调试,随便起)
    // esp_timer_create:根据配置创建定时器,句柄存入 led_off_timer
    // -------------------------------------------------------
    const esp_timer_create_args_t led_off_timer_args = {
        .callback = &led_off_callback,  // 到期时调用熄灯回调
        .name     = "led_off_timer",
    };
    ESP_ERROR_CHECK(esp_timer_create(&led_off_timer_args, &led_off_timer_handle));


    // esp_timer_start_periodic:启动周期性定时器
    // 每隔 INTERVAL_US(5 秒)自动触发一次,无需手动重启
    ESP_ERROR_CHECK(esp_timer_start_periodic(led_on_timer_handle, INTERVAL_US));


    // -------------------------------------------------------
    // 第五步:创建 LED 控制 Task
    // xTaskCreate 参数说明:
    //   led_control_task:Task 函数
    //   "led_ctrl_task":Task 名字(调试用)
    //   2048:栈大小(字节)
    //   NULL:传给 Task 的参数(不需要)
    //   5:Task 优先级(数字越大优先级越高)
    //   NULL:Task 句柄(不需要保存)
    // -------------------------------------------------------
    xTaskCreate(led_control_task, "led_ctrl_task", 2048, NULL, 5, NULL);

    // -------------------------------------------------------
    // app_main 直接返回
    // 主任务自动删除,led_control_task 和两个定时器继续运行
    // -------------------------------------------------------
}

6.3 GPTimer(通用硬件定时器)

GPTimer(通用硬件定时器)也是定时器,而且是硬件定时器,比 esp_timer 更底层。它直接操作 ESP32-S3 定时器组外设的硬件计数器,具有更高的精度和更多的功能(如事件捕获、与 GPIO 联动等)。GPTimer 概述

6.3.1 GPTimer 的使用流程

1. gptimer_new_timer()     —— 创建定时器,获得句柄

2. gptimer_set_alarm_action() —— 配置警报值(到多少计数触发中断)

3. gptimer_register_event_callbacks() —— 注册警报回调函数

4. gptimer_enable()        —— 使能定时器(申请系统资源)

5. gptimer_start()         —— 启动定时器,开始计数

6. 计数器到达警报值 → 触发回调函数

6.3.2 GPTimer完整代码

C
#include "driver/gpio.h"
#include "driver/gptimer.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

// -------------------------------------------------------
// 宏定义
// -------------------------------------------------------
#define LED_GPIO            GPIO_NUM_38
#define TIMER_RESOLUTION_HZ (1 * 1000 * 1000)  // 1 MHz,1 次计数 = 1 微秒

// 各阶段的计数值(单位:微秒)
#define WAIT_5S_COUNT   (5 * 1000 * 1000)   // 等待 5 秒 = 5,000,000 计数
#define LED_ON_COUNT    (1 * 1000 * 1000)   // 亮灯 1 秒 = 1,000,000 计数
// 熄灯后等待 1 秒(题目要求熄灭 1 秒后再等 5 秒,此处熄灭即进入下一轮等待)

static const char *TAG = "GPTIMER_LED";

// -------------------------------------------------------
// 状态枚举:描述当前 LED 处于哪个阶段
// -------------------------------------------------------
typedef enum {
    STATE_WAITING,      // 等待 5 秒阶段(LED 熄灭,等待下次点亮)
    STATE_LED_ON,       // 亮灯 1 秒阶段
} led_state_t;

// 当前状态,初始为"等待 5 秒"
static volatile led_state_t current_state = STATE_WAITING;

// GPTimer 句柄
static gptimer_handle_t gptimer = NULL;

// -------------------------------------------------------
// GPTimer 警报回调函数
// 在警报事件发生时自动调用,运行在中断上下文中
// 注意:不能在此处调用阻塞式 API
// -------------------------------------------------------
static bool timer_alarm_callback(gptimer_handle_t timer,
                                  const gptimer_alarm_event_data_t *edata,
                                  void *user_ctx)
{
    gptimer_alarm_config_t new_alarm = {};

    if (current_state == STATE_WAITING) {
        // 当前处于"等待 5 秒"阶段,5 秒到了 → 点亮 LED,切换到亮灯阶段
        gpio_set_level(LED_GPIO, 1);
        ESP_EARLY_LOGI(TAG, "LED 点亮");

        current_state = STATE_LED_ON;

        // 设置下一次警报:再过 1 秒触发(亮灯 1 秒后熄灭)
        // alarm_count = 当前警报值 + 1 秒的计数
        new_alarm.alarm_count = edata->alarm_value + LED_ON_COUNT;
        new_alarm.flags.auto_reload_on_alarm = false;
        gptimer_set_alarm_action(timer, &new_alarm);

    } else if (current_state == STATE_LED_ON) {
        // 当前处于"亮灯 1 秒"阶段,1 秒到了 → 熄灭 LED,切换到等待阶段
        gpio_set_level(LED_GPIO, 0);
        ESP_EARLY_LOGI(TAG, "LED 熄灭");

        current_state = STATE_WAITING;

        // 设置下一次警报:再过 5 秒触发(等待 5 秒后再次点亮)
        new_alarm.alarm_count = edata->alarm_value + WAIT_5S_COUNT;
        new_alarm.flags.auto_reload_on_alarm = false;
        gptimer_set_alarm_action(timer, &new_alarm);
    }

    // 返回 false:不需要请求任务切换
    return false;
}

void app_main(void)
{
    // -------------------------------------------------------
    // 第一步:初始化 GPIO 38 为输出模式
    // -------------------------------------------------------
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << LED_GPIO),
        .mode         = GPIO_MODE_OUTPUT,
        .pull_up_en   = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type    = GPIO_INTR_DISABLE,
    };
    gpio_config(&io_conf);
    gpio_set_level(LED_GPIO, 0);  // 初始状态:LED 熄灭

    // -------------------------------------------------------
    // 第二步:创建 GPTimer
    // gptimer_config_t:定时器配置结构体
    //   .clk_src:时钟源,选默认(通常为 APB 或 XTAL)
    //   .direction:计数方向,向上计数
    //   .resolution_hz:分辨率,1 MHz = 每计数 1 次代表 1 微秒
    // -------------------------------------------------------
    gptimer_config_t timer_config = {
        .clk_src       = GPTIMER_CLK_SRC_DEFAULT,
        .direction     = GPTIMER_COUNT_UP,
        .resolution_hz = TIMER_RESOLUTION_HZ,
    };
    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));

    // -------------------------------------------------------
    // 第三步:注册警报回调函数
    // 当计数器到达警报值时,自动调用 timer_alarm_callback
    // -------------------------------------------------------
    gptimer_event_callbacks_t cbs = {
        .on_alarm = timer_alarm_callback,
    };
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));

    // -------------------------------------------------------
    // 第四步:配置第一次警报
    // 第一次:等待 5 秒后点亮 LED
    // alarm_count = 5,000,000(5 秒后触发)
    // auto_reload_on_alarm = false:不自动重载,由回调手动更新下一次警报值
    // -------------------------------------------------------
    gptimer_alarm_config_t alarm_config = {
        .alarm_count              = WAIT_5S_COUNT,
        .flags.auto_reload_on_alarm = false,
    };
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));

    // -------------------------------------------------------
    // 第五步:使能并启动定时器
    // gptimer_enable():使能定时器,申请系统资源(电源管理锁等)
    // gptimer_start():启动计数器,开始计数
    // -------------------------------------------------------
    ESP_ERROR_CHECK(gptimer_enable(gptimer));
    ESP_ERROR_CHECK(gptimer_start(gptimer));

    // -------------------------------------------------------
    // app_main 直接返回,主任务自动删除
    // GPTimer 继续在后台运行,不受影响
    // -------------------------------------------------------
}

觉醒,然后燎原。 © 2026 门主引擎