<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