ESP32开发教程(五)——定时器中断详解

        在上最开始所提供的技术文档中,在通用定时器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)函数是需要注意,它必须在使能定时中断前。

物联沃分享整理
物联沃-IOTWORD物联网 » ESP32开发教程(五)——定时器中断详解

发表评论