/*定时器组例子:有两组定时器,每组有两个
*/
#include
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/timer_group_struct.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#define TIMER_DIVIDER 16 // 分频
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // 转换为秒计数
#define TIMER_INTERVAL0_SEC (3.4179) // 定时器1时间间隔
#define TIMER_INTERVAL1_SEC (5.78) // 定时器2时间间隔
#define TEST_WITHOUT_RELOAD 0 // 不进行重装载
#define TEST_WITH_RELOAD 1 // 进行重装载
/*
* A sample structure to pass events
* from the timer interrupt handler to the main program.
*/
typedef struct {
int type; // the type of timer's event
int timer_group;
int timer_idx;
uint64_t timer_counter_value;
} timer_event_t;
xQueueHandle timer_queue;
/*
* A simple helper function to print the raw timer counter value
* and the counter value converted to seconds
*/
static void inline print_timer_counter(uint64_t counter_value)
{
printf("Counter: 0x%08x%08x\n", (uint32_t) (counter_value >> 32),
(uint32_t) (counter_value));
printf("Time : %.8f s\n", (double) counter_value / TIMER_SCALE);
}
/*
* Timer group0 ISR handler
*
* Note:
* We don't call the timer API here because they are not declared with IRAM_ATTR.
* If we're okay with the timer irq not being serviced while SPI flash cache is disabled,
* we can allocate this interrupt without the ESP_INTR_FLAG_IRAM flag and use the normal API.
*/
void IRAM_ATTR timer_group0_isr(void *para)
{
int timer_idx = (int) para;//获取是定时器0还是定时器1
/*读取定时器中断状态
* */
uint32_t intr_status = TIMERG0.int_st_timers.val;
TIMERG0.hw_timer[timer_idx].update = 1;//定时器的当前值将保存在寄存器上
uint64_t timer_counter_value = //获取定时器的当前值
((uint64_t) TIMERG0.hw_timer[timer_idx].cnt_high) << 32
| TIMERG0.hw_timer[timer_idx].cnt_low;
/*定义定时器基本事件,并初始化信息,用来发送到主任务
* */
timer_event_t evt;
evt.timer_group = 0;
evt.timer_idx = timer_idx;
evt.timer_counter_value = timer_counter_value;
/*判断是否是定时器0发生中断,还是定时器1发生
* */
if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_0) {
//假如定时器0发生
evt.type = TEST_WITHOUT_RELOAD;//定时器不重载
TIMERG0.int_clr_timers.t0 = 1;//清除定时器0中断标志
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);//重设定时器报警点的值
TIMERG0.hw_timer[timer_idx].alarm_high = (uint32_t) (timer_counter_value >> 32);
TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value;
} else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) {//假如定时器1中断发生
evt.type = TEST_WITH_RELOAD; //定时器1重装载
TIMERG0.int_clr_timers.t1 = 1; //清除定时器1中断标志
} else {
evt.type = -1; // 是不支持的事件类型
}
/*再次启动定时器
* */
TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN;
/*现在只是把事件数据回到主程序的任务
* */
xQueueSendFromISR(timer_queue, &evt, NULL);
}
/*初始化定时器
* */
static void example_tg0_timer_init(int timer_idx,
bool auto_reload, double timer_interval_sec)
{
/*初始化定时器参数配置
* */
timer_config_t config;
config.divider = TIMER_DIVIDER;
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 = auto_reload;
timer_init(TIMER_GROUP_0, timer_idx, &config);
/* 设置定时器的初始值为0
* */
timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);
/*设置定时器的报警值
*/
timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);
/*使能定时器中断
* */
timer_enable_intr(TIMER_GROUP_0, timer_idx);
/*注册定时器中断处理函数
* */
timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,
(void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
/*启动定时器
* */
timer_start(TIMER_GROUP_0, timer_idx);
}
/*
* The main task of this example program
*/
static void timer_example_evt_task(void *arg)
{
while (1) {
timer_event_t evt;
xQueueReceive(timer_queue, &evt, portMAX_DELAY);//获取事件信息
/*打印事件的类型信息
* */
if (evt.type == TEST_WITHOUT_RELOAD) {
printf("\n Example timer without reload\n");
} else if (evt.type == TEST_WITH_RELOAD) {
printf("\n Example timer with auto reload\n");
} else {
printf("\n UNKNOWN EVENT TYPE\n");
}
printf("Group[%d], timer[%d] alarm event\n", evt.timer_group, evt.timer_idx);
/*打印定时器计数值
* */
printf("------- EVENT TIME --------\n");
print_timer_counter(evt.timer_counter_value);
/*获取硬件定时器的值并打印出来
* */
printf("-------- TASK TIME --------\n");
uint64_t task_counter_value;
timer_get_counter_value(evt.timer_group, evt.timer_idx, &task_counter_value);
print_timer_counter(task_counter_value);
}
}
/*
* In this example, we will test hardware timer0 and timer1 of timer group0.
*/
void wifi_timer01()
{
timer_queue = xQueueCreate(10, sizeof(timer_event_t));
example_tg0_timer_init(TIMER_0, TEST_WITHOUT_RELOAD, TIMER_INTERVAL0_SEC);
example_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, TIMER_INTERVAL1_SEC);
xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL);
}
串口输出结果:
Example timer without reload
Group[0], timer[0] alarm event
------- EVENT TIME --------
Counter: 0x000000000104c3e2
Time : 3.41790120 s
-------- TASK TIME --------
Counter: 0x0000000001051f59
Time : 3.42258420 s
Example timer with auto reload
Group[0], timer[1] alarm event
------- EVENT TIME --------
Counter: 0x0000000000000006
Time : 0.00000120 s
-------- TASK TIME --------
Counter: 0x0000000000005a53
Time : 0.00462460 s
Example timer without reload
Group[0], timer[0] alarm event
------- EVENT TIME --------
Counter: 0x00000000020987c4
Time : 6.83580240 s
-------- TASK TIME --------
Counter: 0x000000000209e39d
Time : 6.84050500 s
Example timer without reload
Group[0], timer[0] alarm event
------- EVENT TIME --------
Counter: 0x00000000030e4ba6
Time : 10.25370360 s
-------- TASK TIME --------
Counter: 0x00000000030eab1f
Time : 10.25859180 s