ESP32开发(五)——定时器中断

本文介绍了ESP32的通用定时器资源,包括两个定时器组,每个组有两个定时器。使用driver/gptimer.h库进行定时器配置,详细讲解了创建定时器、设置回调函数、使能中断、设置告警事件等步骤。在代码示例中,展示了如何实现两个引脚电平每5秒翻转一次。注意中断回调函数需在使能定时器中断前注册。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在上最开始所提供的技术文档中,在通用定时器API中,它说给的库函数为"driver/gptimer.h",但是我在学习其他博主的关于ESP32的定时器时,发现他们所用的库函数是"driver/timer.h"。感到很迷茫。后来经过查阅资料发现,"driver/gptimer.h"是更新了的"driver/tmer.h","driver/timer.h"也是可以用的,本文将利用"driver/gptimer.h"这个库进行定时器配置。

 一.ESP32的定时器资源

         ESP32有两组通用定时器,每组又有两个定时器,具体的博主给出技术文档连接,自己去瞅吧!https://www.espressif.com.cn/sites/default/files/documentation/esp32_datasheet_cn.pdf

二.相关函数

(1)创建定时器

//参数:*config:用于定时器配置的结构体
//      *ret_timer:定时器句柄
//作用:创建定时器,新创建的定时器时初始化状态
esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer)




//定时器配置结构体
typedef struct {
    gptimer_clock_source_t clk_src;      //中断源
    gptimer_count_direction_t direction; //计数方式 
    uint32_t resolution_hz;              //定时时间,单位
    struct {
        uint32_t intr_shared: 1;        
    } flags;                             
} gptimer_config_t;

 (2)设置定时器回调函数

//参数:timer:定时器句柄
//     *cbs:回调函数结构体
//     *user_data:传入参数
//作用:注册中断回调函数
esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data)



//回调函数结构体
typedef struct {
    gptimer_alarm_cb_t on_alarm;         //也就是报警回调函数,直接传入函数名
} gptimer_event_callbacks_t;



//回调函数形式
typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);

(3)使能定时器中断

esp_err_t gptimer_enable(gptimer_handle_t timer)

(4)设置定时器告警事件动作。

//参数:timer:定时器句柄
//       config:警告配置结构体
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config)

(5)开始计数

esp_err_t gptimer_start(gptimer_handle_t timer)

三.代码

time.c

#include"time.h"
#include "driver/gptimer.h"
#include "driver/uart.h"
#include "myuart.h"
#include "math.h"
#include "esp_log.h"
#include <string.h>
#include "driver/gpio.h"

static const char *TAG = "TEST";

void IRAM_ATTR timer_on_alarm_cb (gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx){
    static int LED_leve = 1;
    gpio_set_level(RXD,LED_leve);
    gpio_set_level(TXD,LED_leve);
    if(LED_leve)
        LED_leve = 0;
    else
        LED_leve = 1;
        
}


void Time_int(void){
    gptimer_handle_t gptimer = NULL;                  //通用定时器句柄
    gptimer_config_t timer_config = {                 //初始化参数设置
        .clk_src = GPTIMER_CLK_SRC_DEFAULT,           //选择时钟源
        .direction = GPTIMER_COUNT_UP,                //向上计数
        .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us  设置定时时间
    };
    ESP_LOGI(TAG, "Start timer, stop it at alarm event");
    ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));  //创建一个通用定时器,返回任务句柄

    gptimer_event_callbacks_t cbs = {              //中断回调函数(alrm中断)
        .on_alarm = timer_on_alarm_cb,    
    };
    ESP_LOGI(TAG, "Enable timer");
    ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));    //第一次调用这个函数需要在调用gptimer_enable之前
    ESP_ERROR_CHECK(gptimer_enable(gptimer));                                   //使能定时器中断

     ESP_LOGI(TAG, "Start timer, auto-reload at alarm event");
    gptimer_alarm_config_t alarm_config = {
        .reload_count = 0,
        .alarm_count = 5000000, // period = 5s
        .flags.auto_reload_on_alarm = true,
    };
    ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
    ESP_ERROR_CHECK(gptimer_start(gptimer));
}

time.h

#ifndef _TIME_H_
#define _TIME_H_

#define RXD GPIO_NUM_19
#define TXD GPIO_NUM_23
#define RXD_OUTPUT_PIN_SEL (1ULL << RXD)   //配置GPIO_OUT寄存器
#define TXD_OUTPUT_PIN_SEL (1ULL << TXD)   

void Time_int(void);


#endif

main.c

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gptimer.h"
#include "esp_log.h"
#include "time.h"
#include "driver/gpio.h"


void IO_int(void){
    gpio_config_t IO_Config;

    IO_Config.pin_bit_mask = RXD_OUTPUT_PIN_SEL;
    IO_Config.mode = GPIO_MODE_DEF_OUTPUT;               /*!< GPIO mode: set input/output mode                     */
    IO_Config.pull_up_en = 1;       /*!< GPIO pull-up                                         */
    IO_Config.pull_down_en = 0;   /*!< GPIO pull-down                                       */
    IO_Config.intr_type = GPIO_INTR_DISABLE;    
    gpio_config(&IO_Config);

    IO_Config.pin_bit_mask = TXD_OUTPUT_PIN_SEL;
    gpio_config(&IO_Config);

    gpio_set_level(RXD,0);
    gpio_set_level(TXD,0);
}

void app_main(void)
{
  IO_int();
  Time_int();
  while (1)
  {
    vTaskDelay(1000/portTICK_PERIOD_MS);  //延迟1s
  }
  

}

四.现象

        实现两个引脚电平每5s翻转一次。

        需要注意的是,我在实现在定时回调函数中打印log时,并不能成功实现(还不知道原因),但是电平是成功翻转了的。在使用esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data)函数是需要注意,它必须在使能定时中断前。

### ESP32 定时器中断函数应用方法 #### 创建定时器并配置参数 为了创建一个可以触发中断定时器,首先需要初始化定时器对象,并设置其工作模式和其他必要参数。对于ESP32而言,该芯片内置有多个硬件定时器可供使用。 ```c #include "driver/timer.h" // 初始化定时器0于组0内 timer_config_t config = { .divider = 80, // 设置分频因子为80,则计数频率=APB_CLK/80 (默认 APB 频率为80MHz) .counter_dir = TIMER_COUNT_UP, // 计数方向设为向上增加 .counter_en = TIMER_PAUSE, // 初始状态下暂停计数 .alarm_en = TIMER_ALARM_EN, // 启用报警功能以便后续用于触发中断 .auto_reload = true // 自动重载使能,在达到警报值后自动重启计数值 }; timer_init(TIMER_GROUP_0, TIMER_0, &config); ``` #### 注册回调函数处理程序 当设定的时间到达时,将会调用预先注册好的ISR(Interrupt Service Routine),即中断服务例程来执行特定的任务逻辑。这里通过`timer_isr_register()`完成这一过程[^1]。 ```c void IRAM_ATTR timer_group0_alarm_callback(void* arg){ static uint64_t count = 0; printf("Timer triggered %llu times.\n", ++count); // 清除定时器告警标志位 timer_clear_intr_status(TIMER_GROUP_0, TIMER_0); } // 将上述定义的回调绑定到指定定时器上 timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_alarm_callback, NULL, /* 用户自定义参数 */ ESP_INTR_FLAG_IRAM,/* ISR位于IRAM中运行 */ NULL); /* 返回句柄指针 */ ``` #### 设定时间间隔与启动定时器 最后一步就是给定时器赋予具体的超时期限以及正式开启它的工作流程。这可以通过调整定时器的目标值(alarm value)实现,一旦当前计数值等于此目标值就会引发一次溢出事件从而激活相应的中断机制[^3]。 ```c uint64_t alarm_value = 50 * 10e3; // 延迟时间为50ms timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL); timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, alarm_value); timer_enable_intr(TIMER_GROUP_0, TIMER_0); timer_start(TIMER_GROUP_0, TIMER_0); ``` 以上就是在ESP32平台上利用C语言编写的一个简单定时器中断的例子。这段代码展示了如何配置、安装和启用带有周期性中断特性的硬件定时器实例[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Crystal(mercy)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值