<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/LearnESP32" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
<iframe frameborder="0" height="1500" name="ifd" scrolling="auto" src="https://mnifdv.cn/resource/cnblogs/LearnESP32" width="100%"></iframe>
说明
硬件定时器有两组,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