【ESP32】ESP-IDF开发 | Timer硬件定时器+定时器闹钟例程

1. 简介

        ESP32内置4个64-bit通用定时器。每个定时器包含一个16-bit预分频器和一个64-bit可自动重新加载向上/向下计数器。ESP32的定时器分为2组,每组2个。定时器具有闹钟功能,闹钟事件会引发重新加载和触发中断。

        硬件定时器的时钟是由APB时钟提供的,APB时钟默认是80MHz;定时器时钟经过预分频器的分频后,才是定时器计数的频率。

2. API

2.1 创建定时器

esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer);
  • config:定时器配置;
typedef struct {
    gptimer_clock_source_t clk_src;      /*!< GPTimer clock source */
    gptimer_count_direction_t direction; /*!< Count direction */
    uint32_t resolution_hz;              /*!< Counter resolution (working frequency) in Hz,
                                              hence, the step size of each count tick equals to (1 / resolution_hz) seconds */
    int intr_priority;                   /*!< GPTimer interrupt priority,
                                              if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
    struct {
        uint32_t intr_shared: 1;         /*!< Set true, the timer interrupt number can be shared with other peripherals */
        uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the GPTimer registers before/after entering/exist sleep mode.
                                              By this approach, the system can power off GPTimer's power domain.
                                              This can save power, but at the expense of more RAM being consumed */
    } flags;                             /*!< GPTimer config flags*/
} gptimer_config_t;

         clk_src:定时器时钟源;direction:定时器计数方向,向上或向下;resolution_hz:分辨率,即计数的频率;intr_priority:中断优先级,可选0-3,0为默认优先级。

  • ret_timer:定时器句柄。

2.2 删除定时器

esp_err_t gptimer_del_timer(gptimer_handle_t timer);
  • timer:定时器句柄。

2.3 注册中断回调

esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data);
  • timer:定时器句柄;
  • cbs:中断回调;
  • user_data:传入回调函数的用户数据。

2.4 初始化闹钟

esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config);
  • timer:定时器句柄;
  • config:配置项。
typedef struct {
    uint64_t alarm_count;  /*!< Alarm target count value */
    uint64_t reload_count; /*!< Alarm reload count value, effect only when `auto_reload_on_alarm` is set to true */
    struct {
        uint32_t auto_reload_on_alarm: 1; /*!< Reload the count value by hardware, immediately at the alarm event */
    } flags;                              /*!< Alarm config flags*/
} gptimer_alarm_config_t;

        alarm_count:闹钟触发值,触发频率 = 定时器频率 * 闹钟触发值;reload_count:重装载次数,为0表示一直重装载;auto_reload_on_alarm:使能闹钟重装载。

2.5 使能定时器

esp_err_t gptimer_enable(gptimer_handle_t timer);
  •  timer:定时器句柄。

2.6 启动定时器

esp_err_t gptimer_start(gptimer_handle_t timer);
  •  timer:定时器句柄。

3. 例程

        例程中实现一个定时器闹钟应用,间隔为1秒,每次闹钟触发就打印一条log。

#include "driver/gptimer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_log.h"

#include <string.h>

#define TAG "app"

gptimer_handle_t gptimer = NULL;
SemaphoreHandle_t sem = NULL;

bool timer_timeout_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
{
    BaseType_t higherTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(sem, &higherTaskWoken);
    return higherTaskWoken == pdTRUE;
}

void app_main()
{
    /* 初始化信号量 */
    sem = xSemaphoreCreateBinary();

    /* 初始化定时器 */
    gptimer_config_t timer_config = {
        .clk_src = GPTIMER_CLK_SRC_DEFAULT,  // 默认时钟,APB时钟
        .direction = GPTIMER_COUNT_UP,
        .resolution_hz = 1000000,  // 1MHz
        .intr_priority = 0,  // 默认中断优先级
    };
    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));

    /* 注册回调 */
    gptimer_event_callbacks_t cbs = {
        .on_alarm = timer_timeout_cb,
    };
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));

    /* 初始化闹钟 */
    gptimer_alarm_config_t alarm_config = {
        .reload_count = 0,  // 不断重载
        .alarm_count = 1000000,
        .flags.auto_reload_on_alarm = true,
    };
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));

    /* 使能定时器和闹钟 */
    ESP_ERROR_CHECK(gptimer_enable(gptimer));
    ESP_ERROR_CHECK(gptimer_start(gptimer));

    while (1) {
        if (pdTRUE == xSemaphoreTake(sem, portMAX_DELAY)) {
            ESP_LOGI(TAG, "Timer timeout");
        }
    }
}

         初始化定时器参数,resolution_hz设置1000000,即计数频率为1MHz;向上计数。下面注册定时器中断回调函数,结构体里面只有一个on_alarm的回调;回调函数的第二个参数内容如下。

typedef struct {
    uint64_t count_value; /*!< Current count value */
    uint64_t alarm_value; /*!< Current alarm value */
} gptimer_alarm_event_data_t;

        主要就是当前定时器的寄存器值和闹钟寄存器的值,基本不会用到。回调函数返回是否需要切换操作系统上下文,如果在回调函数里面有信号量、互斥量这种操作就要注意;如果没有用到,返回假就行了。

        初始化闹钟,设置无限次重装载;触发值为1000000,即1秒触发一次。

        最后是一个死循环,在里面程序会不断等待信号量的到来,获取到信号量表示闹钟触发了一次,然后打印一句log。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马浩同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值