定时器组

# Example: timer_group

This example uses the timer group driver to generate timer interrupts at two specified alarm intervals.

Two timers are configured
* Each timer is set with some sample alarm interval
* On reaching the interval value each timer will generate an alarm
* One of the timers is configured to automatically reload it's counter value on the alarm
* The other timer is configured to keep incrementing and is reloaded by the application each time the alarm happens

 

定时器组,这个例子用0组的0和1  

其中0 不是reload  1是reload的

 

分步解析一下:

 

typedef volatile struct {
    struct{
        union {
            struct {
                uint32_t reserved0:   10;
                uint32_t alarm_en:     1;             /*When set  alarm is enabled*/
                uint32_t level_int_en: 1;             /*When set  level type interrupt will be generated during alarm*/
                uint32_t edge_int_en:  1;             /*When set  edge type interrupt will be generated during alarm*/
                uint32_t divider:     16;             /*Timer clock (T0/1_clk) pre-scale value.*/
                uint32_t autoreload:   1;             /*When set  timer 0/1 auto-reload at alarming is enabled*/
                uint32_t increase:     1;             /*When set  timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/
                uint32_t enable:       1;             /*When set  timer 0/1 time-base counter is enabled*/
            };
            uint32_t val;
        } config;
        uint32_t cnt_low;                             /*Register to store timer 0/1 time-base counter current value lower 32 bits.*/
        uint32_t cnt_high;                            /*Register to store timer 0 time-base counter current value higher 32 bits.*/
        uint32_t update;                              /*Write any value will trigger a timer 0 time-base counter value update (timer 0 current value will be stored in registers above)*/
        uint32_t alarm_low;                           /*Timer 0 time-base counter value lower 32 bits that will trigger the alarm*/
        uint32_t alarm_high;                          /*Timer 0 time-base counter value higher 32 bits that will trigger the alarm*/
        uint32_t load_low;                            /*Lower 32 bits of the value that will load into timer 0 time-base counter*/
        uint32_t load_high;                           /*higher 32 bits of the value that will load into timer 0 time-base counter*/
        uint32_t reload;                              /*Write any value will trigger timer 0 time-base counter reload*/
    } hw_timer[2];

 

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;

 




void
app_main() { timer_queue = xQueueCreate(10, sizeof(timer_event_t));//建立一个队列专门放timer_event_t结构的数据 example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);//goup0 tim0 noado reload example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC);//goup0 tim1 rel xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);//建立任务 }

 

static void timer_example_evt_task(void *arg)
{
    while (1) {
        timer_event_t evt;
        xQueueReceive(timer_queue, &evt, portMAX_DELAY);//阻塞

        /* Print information that the timer reported an event */
        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);

        /* Print the timer values passed by event */
        printf("------- EVENT TIME --------\n");
        print_timer_counter(evt.timer_counter_value);

        /* Print the timer values as visible by this task */
        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);
    }
}

1.xQueueReceive(timer_queue, &evt, portMAX_DELAY);//阻塞阻塞等待

2. if (evt.type == TEST_WITHOUT_RELOAD)判断0 还是1

3.打印信息

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

/* Print the timer values passed by event */
printf("------- EVENT TIME --------\n");
print_timer_counter(evt.timer_counter_value);

/* Print the timer values as visible by this task */
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);

 

下面看初始化

/*
 * Initialize selected timer of the timer group 0
 *
 * timer_idx - the timer number to initialize
 * auto_reload - should the timer auto reload on alarm?
 * timer_interval_sec - the interval of alarm to set
 */
static void example_tg0_timer_init(int timer_idx, 
    bool auto_reload, double timer_interval_sec)
{
    /* Select and initialize basic parameters of the timer */
    timer_config_t config;
    config.divider = TIMER_DIVIDER; //80/16=5
    config.counter_dir = TIMER_COUNT_UP;//上升沿
    config.counter_en = TIMER_PAUSE;//先停止计数
    config.alarm_en = TIMER_ALARM_EN;//警报打开
    config.intr_type = TIMER_INTR_LEVEL;//LEVEL模式
    config.auto_reload = auto_reload;//自动
    timer_init(TIMER_GROUP_0, timer_idx, &config);//用上面的参数来初始化

    /* Timer's counter will initially start from value below.
       Also, if auto_reload is set, this value will be automatically reload on alarm */
    timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);//先清0定时器计数

    /* Configure the alarm value and the interrupt on alarm. */
    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);
}

1.timer_init初始化

2.清0 counter

3.设置alarm时间。

timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);//

这里设置成timer_interval_sec * TIMER_SCALE 相当于sec级的定时

#define TIMER_DIVIDER 16 // Hardware timer clock divider 80/16
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
#define TIMER_INTERVAL0_SEC (3.4179) // sample test interval for the first timer   3.4179s
#define TIMER_INTERVAL1_SEC (5.78) // sample test interval for the second timer
#define TEST_WITHOUT_RELOAD 0 // testing will be done without auto reload 5.78s
#define TEST_WITH_RELOAD 1 // testing will be done with auto reload

查看一下TIMER_BASE_CLK,是80 000 000  ,这里/16就是5M---定时器现在是base on 5M了

0.2us一次中断。

这里相当于 设置5M,但也计5M次,也就是1s-----再乘以上面的设置的3.4179s和5.78s

 

4.

timer_enable_intr(TIMER_GROUP_0, timer_idx);

enable 组0 的0或者1

5.回调
timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,
(void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);

6.

timer_start(TIMER_GROUP_0, timer_idx);定时器开始

 

下面看回调

void IRAM_ATTR timer_group0_isr(void *para)
{
    int timer_idx = (int) para;

    /* Retrieve the interrupt status and the counter value
       from the timer that reported the interrupt */
    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;

    /* Prepare basic event data
       that will be then sent back to the main program task */
    timer_event_t evt;
    evt.timer_group = 0;
    evt.timer_idx = timer_idx;
    evt.timer_counter_value = timer_counter_value;

    /* Clear the interrupt
       and update the alarm time for the timer with without reload */
    if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
        evt.type = TEST_WITHOUT_RELOAD;
        TIMERG0.int_clr_timers.t0 = 1;
        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) {
        evt.type = TEST_WITH_RELOAD;
        TIMERG0.int_clr_timers.t1 = 1;
    } else {
        evt.type = -1; // not supported even type
    }

    /* After the alarm has been triggered
      we need enable it again, so it is triggered the next time */
    TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;

    /* Now just send the event data back to the main program task */
    xQueueSendFromISR(timer_queue, &evt, NULL);//下面阻塞,这里发送过去
}

 

1.若是0 则增加一次interval加到下一次时间里面。

2.若是1 因为是reload的,就不用了。

3.定时器的alarm值是 32位低位+32位高位的。

4.发送queue,解除task的阻塞,并将此时的count值打印出来

 

```
Example timer with auto reload
Group[0], timer[1] alarm event
------- EVENT TIME --------
Counter: 0x000000000000000a      --------------------evnet1的时间,应该是5.7s多的,应该不会溢出才对,这里为何counter是a???
Time : 0.00000200 s         --这里明显可以看出来是 2us/a=0.2us一次计算
-------- TASK TIME --------
Counter: 0x00000000000107ff
Time : 0.01351660 s

Example timer without reload
Group[0], timer[0] alarm event
------- EVENT TIME --------
Counter: 0x00000000092ae316      ----看间隔
Time : 30.76111800 s
-------- TASK TIME --------
Counter: 0x00000000092bd535    ---看间隔
Time : 30.77351460 s

```

posted @ 2018-01-22 23:00  XZHDJH  阅读(306)  评论(0)    收藏  举报