typedef struct
{ timer_alarm_t alarm_en; /*!< Timer alarm enable */ timer_start_t counter_en; /*!< Counter enable */ timer_intr_mode_t intr_type; /*!< Interrupt mode */ timer_count_dir_t counter_dir; /*!< Counter direction */ timer_autoreload_t auto_reload; /*!< Timer auto-reload */ uint32_t divider; /*!< Counter clock divider. The divider's range is from from 2 to 65536. */ } timer_config_t;
定时器初始化结构体成员6个,从上到下依次是,中断使能,计数使能,中断模式,计数方向,自动重载,分频系数。
timer_init(TIMER_GROUP_0,TIMER_1,&timerconfig);
初始化结构体后,调用初始化函数,三个参数包括,定时器组号,定时器编号,初始化结构体地址
timer_set_counter_value(TIMER_GROUP_0,TIMER_1,0x00000000ULL); timer_set_alarm_value(TIMER_GROUP_0,TIMER_1,TIMER_BASE_CLK/8); timer_enable_intr(TIMER_GROUP_0,TIMER_1); timer_isr_register(TIMER_GROUP_0,TIMER_1,timer_isr_handler,(void *)TIMER_1,ESP_INTR_FLAG_IRAM,NULL); timer_start(TIMER_GROUP_0,TIMER_1);
接下来需要调用设定定时器初值的函数,设定警报值的函数,使能定时器中断,并注册定时器中断服务函数,注册定时器中断服务函数的参数有
定时器中断服务函数的指针以及传参和中断函数存储地址分类。
接下来就需要编写定时器中断服务函数
void IRAM_ATTR timer_isr_handler(void *arg) { u32_t intr=timer_group_get_intr_status_in_isr(TIMER_GROUP_0); // if(intr&TIMER_INTR_T0) // { // timer_group_clr_intr_status_in_isr(TIMER_GROUP_0,TIMER_1); // gpio_set_level(LED_PIN,1-gpio_get_level(LED_PIN)); // timer_group_enable_alarm_in_isr(TIMER_GROUP_0,TIMER_1); // } if(TIMER_1==(u32_t)arg) { timer_group_clr_intr_status_in_isr(TIMER_GROUP_0,TIMER_1); gpio_set_level(LED_PIN,1-gpio_get_level(LED_PIN)); timer_group_enable_alarm_in_isr(TIMER_GROUP_0,TIMER_1); } }
在中断服务函数中需要判断下产生中断的定时器是否是我们设定的定时器,这是为了在使用多个定时器时可以把同一组的定时器中断服务
都注册在一个函数,区分产生中断的外设可以根据检测定时器分组中的中断状态标志位,看对应的T0位是否为1,也可以根据我们注册中断服务函数时
传入的参数来判断中断的定时器。
需要注意的是,定时器中断标志位需要软件手动清除,如果想继续使用闹铃功能,需要重新使能闹铃功能。
上面是ESP32的硬件定时器,在软件中还有一种esp_timer即软件定时器
/** * @brief Timer configuration passed to esp_timer_create */ typedef struct { esp_timer_cb_t callback; //!< Function to call when timer expires void* arg; //!< Argument to pass to the callback esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR const char* name; //!< Timer name, used in esp_timer_dump function bool skip_unhandled_events; //!< Skip unhandled events for periodic timers } esp_timer_create_args_t;
这是esp_timer创建时所需参数的结构体,结构体成员有5个成员
第一个是当定时器到达设定值时回调函数的地址。
第二个是回调函数的传递参数
第三个是调用回调函数的方式,是从task中回调还是从ISR中回调,esp32目前只支持task中回调。所以不用设置
第四个是定时器的名字
第五个是当周期定时发生时是否跳过未处理的事件
esp_err_t err=esp_timer_create(&esp_timer_args_t1,&esp_timer_handle_timer1); err=esp_timer_start_periodic(esp_timer_handle_timer1,1000000); if(err==ERR_OK) printf("esp-timer initialation is ok!\n");
初始化参数赋值完后就可以调用创建函数了,创建函数中的参数包括创建参数的结构体和esp_timer句柄,后期会用到句柄。
启动定时器如果单次定时使用start_once,如果是周期性使用调用start_periodic
因为软件定时器的周期是固定的1us所以设定的溢出值是以us位单位。剩下的就是在回调函数中编写我们需要的功能了。
软件定时器不需要清楚标志位,在定时器计数达到设定值后会调用回调函数并将计数值清0。