ESP32定时器例程解析

/*定时器组例子:有两组定时器,每组有两个

*/


#include <stdio.h>

#include "esp_types.h"

#include "freertos/FreeRTOS.h"

#include "freertos/task.h"

#include "freertos/queue.h"

#include "soc/timer_group_struct.h"

#include "driver/periph_ctrl.h"

#include "driver/timer.h"


#define TIMER_DIVIDER    16 // 分频

#define TIMER_SCALE     (TIMER_BASE_CLK / TIMER_DIVIDER) // 转换为秒计数

#define TIMER_INTERVAL0_SEC (3.4179) // 定时器1时间间隔

#define TIMER_INTERVAL1_SEC (5.78) // 定时器2时间间隔

#define TEST_WITHOUT_RELOAD 0    // 不进行重装载

#define TEST_WITH_RELOAD   1    // 进行重装载


/*

 * A sample structure to pass events

 * from the timer interrupt handler to the main program.

 */

typedef struct {

  int type; // the type of timer's event

  int timer_group;

  int timer_idx;

  uint64_t timer_counter_value;

} timer_event_t;


xQueueHandle timer_queue;


/*

 * A simple helper function to print the raw timer counter value

 * and the counter value converted to seconds

 */

static void inline print_timer_counter(uint64_t counter_value)

{

  printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),

                  (uint32_t) (counter_value));

  printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE);

}


/*

 * Timer group0 ISR handler

 *

 * Note:

 * We don't call the timer API here because they are not declared with IRAM_ATTR.

 * If we're okay with the timer irq not being serviced while SPI flash cache is disabled,

 * we can allocate this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API.

 */

void IRAM_ATTR timer_group0_isr(void *para)

{

  int timer_idx = (int) para;//获取是定时器0还是定时器1


  /*读取定时器中断状态

   * */

  uint32_t intr_status = TIMERG0.int_st_timers.val;

  TIMERG0.hw_timer[timer_idx].update = 1;//定时器的当前值将保存在寄存器上

  uint64_t timer_counter_value = //获取定时器的当前值

    ((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32

    | TIMERG0.hw_timer[timer_idx].cnt_low;


  /*定义定时器基本事件,并初始化信息,用来发送到主任务

   * */

  timer_event_t evt;

  evt.timer_group = 0;

  evt.timer_idx = timer_idx;

  evt.timer_counter_value = timer_counter_value;


  /*判断是否是定时器0发生中断,还是定时器1发生

   * */

  if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {

   //假如定时器0发生

    evt.type = TEST_WITHOUT_RELOAD;//定时器不重载

    TIMERG0.int_clr_timers.t0 = 1;//清除定时器0中断标志

    timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);//重设定时器报警点的值

    TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32);

    TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value;

  } else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {//假如定时器1中断发生

    evt.type = TEST_WITH_RELOAD; //定时器1重装载

    TIMERG0.int_clr_timers.t1 = 1; //清除定时器1中断标志

  } else {

    evt.type = -1; // 是不支持的事件类型

  }


  /*再次启动定时器

   * */

  TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;


  /*现在只是把事件数据回到主程序的任务

   * */

  xQueueSendFromISR(timer_queue, &evt, NULL);

}


/*初始化定时器

 * */

static void example_tg0_timer_init(int timer_idx,

  bool auto_reload, double timer_interval_sec)

{

  /*初始化定时器参数配置

   * */

  timer_config_t config;

  config.divider = TIMER_DIVIDER;

  config.counter_dir = TIMER_COUNT_UP;

  config.counter_en = TIMER_PAUSE;

  config.alarm_en = TIMER_ALARM_EN;

  config.intr_type = TIMER_INTR_LEVEL;

  config.auto_reload = auto_reload;

  timer_init(TIMER_GROUP_0, timer_idx, &config);


  /* 设置定时器的初始值为0

   * */

  timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);


  /*设置定时器的报警值

   */

  timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);

  /*使能定时器中断

   * */

  timer_enable_intr(TIMER_GROUP_0, timer_idx);

  /*注册定时器中断处理函数

   * */

  timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,

    (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);

  /*启动定时器

   * */

  timer_start(TIMER_GROUP_0, timer_idx);

}


/*

 * The main task of this example program

 */

static void timer_example_evt_task(void *arg)

{

  while (1) {

    timer_event_t evt;

    xQueueReceive(timer_queue, &evt, portMAX_DELAY);//获取事件信息


    /*打印事件的类型信息

     * */

    if (evt.type == TEST_WITHOUT_RELOAD) {

      printf("\n  Example timer without reload\n");

    } else if (evt.type == TEST_WITH_RELOAD) {

      printf("\n  Example timer with auto reload\n");

    } else {

      printf("\n  UNKNOWN EVENT TYPE\n");

    }

    printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.timer_idx);


    /*打印定时器计数值

     * */

    printf("------- EVENT TIME --------\n");

    print_timer_counter(evt.timer_counter_value);


    /*获取硬件定时器的值并打印出来

     * */

    printf("-------- TASK TIME --------\n");

    uint64_t task_counter_value;

    timer_get_counter_value(evt.timer_group, evt.timer_idx, &task_counter_value);

    print_timer_counter(task_counter_value);

  }

}


/*

 * In this example, we will test hardware timer0 and timer1 of timer group0.

 */

void wifi_timer01()

{

  timer_queue = xQueueCreate(10, sizeof(timer_event_t));

  example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);

  example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD,  TIMER_INTERVAL1_SEC);

  xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);

}



串口输出结果:

  Example timer without reload

Group[0], timer[0] alarm event

------- EVENT TIME --------

Counter: 0x000000000104c3e2

Time : 3.41790120 s

-------- TASK TIME --------

Counter: 0x0000000001051f59

Time : 3.42258420 s


  Example timer with auto reload

Group[0], timer[1] alarm event

------- EVENT TIME --------

Counter: 0x0000000000000006

Time : 0.00000120 s

-------- TASK TIME --------

Counter: 0x0000000000005a53

Time : 0.00462460 s


  Example timer without reload

Group[0], timer[0] alarm event

------- EVENT TIME --------

Counter: 0x00000000020987c4

Time : 6.83580240 s

-------- TASK TIME --------

Counter: 0x000000000209e39d

Time : 6.84050500 s


  Example timer without reload

Group[0], timer[0] alarm event

------- EVENT TIME --------

Counter: 0x00000000030e4ba6

Time : 10.25370360 s

-------- TASK TIME --------

Counter: 0x00000000030eab1f

Time : 10.25859180 s


猜你喜欢

转载自blog.csdn.net/redsleep/article/details/79488941