103-ESP32_SDK开发-硬件定时器timer

<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/LearnESP32" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>

说明

硬件定时器有两组,0和1. 然后每一组都有两个定时器,0和1.

所以共有四个定时器

什么是定时器?定时器具体是怎么到了时间进去中断的?

定时器里面是啥?就是个计数器.定时器的时钟,就是计数器的时钟.假设计数器的时钟是1Hz

假设设置了计数器计数到1的时候就进入中断,那么就是每隔1S进入中断了.

 

假设计数器的时钟是80MHz,我想每隔1ms进入一次中断,我应该设置计数值是多少呢???

计数器每记一次需要 1/80000000 秒  也就是  1/80000 毫秒  

要记到80000次才到1ms

想定时多少毫秒,设置初值可以写成     X*(80000000/1000)  X就是要定时的ms数

假设时钟分频了8,那么现在就是10MHz

我想每隔1ms进入一次中断,我应该设置计数值是多少呢???

计数器记一次是 1/10000000 秒  也就是  1/10000 毫秒  

需要多少个 1/10000 毫秒  才能到1ms呢?   10000次

想定时多少毫秒,设置初值可以写成     X*(80000000/分频系数/1000)   X就是要定时的ms数

想定时多少微秒,设置初值可以写成     X*(80000000/分频系数)   X就是要定时的us数

使用定时器分组0的0号定时器产生1S中断

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "driver/timer.h"

#define gpio_pin 25


/*定时器中断函数
因为设置中断的时候,中断设置的 ESP_INTR_FLAG_IRAM 所以中断函数需要加 IRAM_ATTR
*/
void IRAM_ATTR timer_group0_isr(void *para)
{
    //获取定时器分组0中的哪一个定时器产生了中断
    uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
    if (timer_intr & TIMER_INTR_T0) {//定时器0分组的0号定时器产生中断
        /*清除中断*/
        timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
        /*重新使能定时器中断*/    
        timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0);
    }

    /*设置gpio输出高低电平*/
    gpio_set_level(gpio_pin, 1-gpio_get_level(gpio_pin));
}

void gpio_init(void){
    gpio_config_t io_conf;
    //禁止中断
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //输入输出模式
    io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
    //配置要设置的引脚
    io_conf.pin_bit_mask = (unsigned long long)1<<gpio_pin;
    //禁止下拉
    io_conf.pull_down_en = 0;
    //禁止上拉
    io_conf.pull_up_en = 0;
    //配置gpio(不设置上下拉默认输出低电平)
    gpio_config(&io_conf);

}

void app_main(void)
{ 
    gpio_init();//初始化gpio

    /*设置定时器初始化参数*/
    timer_config_t config = {
        .divider = 8,//分频系数[2-65535]
        .counter_dir = TIMER_COUNT_UP,//计数方式是向上计数
        .counter_en = TIMER_PAUSE,//调用timer_init函数以后不启动计数,调用timer_start时才开始计数
        .alarm_en = TIMER_ALARM_EN,//到达计数值启动报警(计数值溢出,进入中断)
        .auto_reload = 1,//自动重新装载预装值
    };
    /*初始化定时器;TIMER_GROUP_0(定时器分组0); TIMER_0(分组0中的0号定时器)*/
    timer_init(TIMER_GROUP_0, TIMER_0, &config);

    /*设置定时器预装值,0*/
    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL);
    /*设置报警阈值*/ // 1000[定时1000ms]*(TIMER_BASE_CLK[定时器时钟]/8[分频系数]/1000[想延时ms级别所以除以1000]),
    timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1000*(TIMER_BASE_CLK/8/1000) );
    /*使能定时器中断*/
    timer_enable_intr(TIMER_GROUP_0, TIMER_0);
    /*注册定时器中断函数*/
    timer_isr_register(TIMER_GROUP_0, TIMER_0, 
        timer_group0_isr,//定时器回调函数
        (void *) TIMER_0, //传递给定时器回调函数的参数
        ESP_INTR_FLAG_IRAM, //把中断放到 IRAM 中
        NULL //调用成功以后返回中断函数的地址,一般用不到
    );
    /*启动定时器*/
    timer_start(TIMER_GROUP_0, TIMER_0);
}

下载进去之后,会看到led每隔1S闪耀

如果想让定时器是一次性的,可以把重新使能屏蔽

如果想使用分组1  

TIMER_GROUP_1

原文地址:https://www.cnblogs.com/yangfengwu/p/15110828.html