ESP32定时器使用
esp32定时器一共有2组,每组有两个,每个定时器都是64位的。每一组还会包含一个看门狗定时器。结构如下:
定时器
- 定时器组0
- 定时器0
- 定时器1
- WDT定时器
- 定时器组1
- 定时器0
- 定时器1
- WDT定时器
定时器时钟:
每个定时器都以 APB 时钟(缩写 APB_CLK,频率通常为 80 MHz)作为基础时钟 。知道了时钟频率就好配置分频值和计数值来产生自己想要的定时中断。
例如我需要1s中产生一次定时器中断;我可以把分频值设为80,这个计数器的频率为80mhz/80=1mhz,也就是1us计数器会记一个值。然后我再设定计数到1000000产生alarm中断。1us*1000000=1s
下面用代码解释下具体如何配置产生1s的定时器中断:
定时器初始化
使用的是定时器组0的定时器0,简称为timer00
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void timer00_init() { timer_config_t config; config.divider = 80; //分频值,默认时钟是80mhz 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 = 1; //使能自动装载 timer_init(TIMER_GROUP_0, TIMER_0, &config); timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL); timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1000000); timer_enable_intr(TIMER_GROUP_0, TIMER_0); timer_isr_register(TIMER_GROUP_0, TIMER_0, timer00_isr, (void *) TIMER_0, ESP_INTR_FLAG_IRAM, NULL); timer_start(TIMER_GROUP_0, TIMER_0); } |
如上代码,从函数名称基本上也可以看出来每一步的作用。
- 根据结构体进行timer的初始化
- 设定定时器计数器值,这个值需要注意,下次自动装载的时候用的也是这个值
- 设定alarm报警计数值
- 使能timer中断
- 中断服务函数注册,这个函数请看下面
- 启动定时器
定时器中断服务函数
1 2 3 4 5 6 7 8 9 10 11 12 |
void IRAM_ATTR timer00_isr(void *para) { int timer_idx = (int) para; //获取定时器中断状态 uint32_t intr_status = TIMERG0.int_st_timers.val; if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) { TIMERG0.int_clr_timers.t0 = 1; //清除中断标志 } TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN; //再次使能alarm uart_write_bytes(UART_NUM_0, (char *)"=======\r\n", 9); //通过串口0打印出来,中断服务函数中不能使用printf } |
中断函数处理流程就很简单。
- 先获取定时器中断状态
- 清除中断标志
- 再次使能定时器alarm,这个地方比较关键。假如不再次使能定时器alarm只会触发这一次。要持续1s触发就要再次打开