esp32学习笔记(2)——timer

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

ESP32 内置 4 个定时器分为两组,每组两个。每个定时器包含一个 16-bit 预分频器和一个 64-bit 可自动重新加载向上/向下计数器。

一、定时器配置步骤

要使用定时器首先要引用库

#include "driver/timer.h"
//1、定时器初始化
timer_init(TIMER_GROUP_x,TIMER_x,&timer_config_t;)
//参数1、定时器组0-1;2、定时器号0-1;3、定时器配置结构体
typedef struct {
    timer_alarm_t alarm_en;      /*!< 报警使能 */
    timer_start_t counter_en;    /*!< 计数使能,初始化时通常设置为PAUSE,在开启定时器的时候计数器就会开始计数 */
    timer_intr_mode_t intr_type; /*!< 中断模式 *///计数器报警后是否产生中断
    timer_count_dir_t counter_dir; /*!<计数方向  */	//向上或者向下计数
    timer_autoreload_t auto_reload;   /*!< 自动重装载*///计数器报警后是否自动重载指定的值
    uint32_t divider;   /*!< 预分频值.  2 to 65536. */
} timer_config_t;

//2、设置计数器的计数开始值	num:值
timer_set_counter_value(TIMER_GROUP_x, TIMER_x, num);

//3、设置报警值
timer_set_alarm_value(TIMER_GROUP_x, TIMER_x, num);
//	num:计数多少次进入中断
//	1/(Base_clock/divider/num)=定时器时间

//4、使能定时器中断
timer_enable_intr(TIMER_GROUP_x, TIMER_x);

//5、添加中断回调函数
timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags);
//注意:这里第三个参数是中断处理函数的名字,第四个参数是中断处理函数的参数;第五个参数是用于分配中断的标志如果设置为ESP_INTR_FLAG_IRAM,那么handler函数必须用IRAM_ATTR属性声明,它只能调用IRAM或ROM中的函数,不能调用其他定时器api
//6、打开定时器
timer_start();
//7、中断处理函数
typedef bool (*timer_isr_t)(void *);
//这个中断处理函数的返回应是布尔型bool如果你在回调中调用FreeRTOS函数,你需要根据参数'pxHigherPriorityTaskwoken'的返回值返回true或false。例如,'xQueueSendFromISR'在回调中被调用,如果任何FreeRTos调用的返回值' pxhigherprioritytaskoken是pdTRUE,返回true;否则返回false。

二、参考部分代码

定时器初始化:

void my_timer_init(void)
{
    timer_config_t timer_config_str;
    timer_config_str.divider = timer_divider;     //分频值,默认时钟是80mhz,80mhz/80=1mhz=1us
    timer_config_str.counter_dir = TIMER_COUNT_UP;//向上计数模式
    timer_config_str.counter_en = TIMER_PAUSE;//定时器计数失能
    timer_config_str.alarm_en = TIMER_ALARM_EN;//使能定时器报警
    timer_config_str.auto_reload = 1;  //使能自动装载
    timer_init(TIMER_GROUP_0,TIMER_0,&timer_config_str);//esp32定时器共有两组,每组两个
    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);//设置定时器的计数值
    timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 100000);//设置定时器的报警值(进入中断的值)
    timer_enable_intr(TIMER_GROUP_0, TIMER_0);//使能定时器中断
    timer_isr_callback_add(TIMER_GROUP_0, TIMER_0, timer_group_isr_callback, NULL, ESP_INTR_FLAG_IRAM);
    // timer_isr_callback_add(TIMER_GROUP_0, TIMER_0,  timer_group_isr_callback, NULL,0);//添加定时器中断回调
    timer_start(TIMER_GROUP_0, TIMER_0);//打开定时器
    printf("打开定时器成功");
}

2、定时器中断服务函数

static bool IRAM_ATTR timer_group_isr_callback(void *args)
{

    BaseType_t pxHigherPriorityTaskWoken = pdFALSE;

	// 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);
	// }
    io_state = ! io_state;
    gpio_set_level(led_gpio,io_state);
    timer_count++;
    return pxHigherPriorityTaskWoken;
}

对于中断函数来说,这个代码中只是在中断里面把led灯进行反转,还有每进一次中断就会记一次数
还有一点不太理解,就是根据官方手册给的数据,每进一次定时器中断就要清除一下标志位,然后就要重新使能报警中断,这个我也试验过,中断清与不清,定时器还都是会运行的。希望有了解的帮我解答一下

三.运行效果

在这里插入图片描述

总结

在控制台可以看到,打印的计数是一次加10,因为我i设置的分频是80,80mhz/80=1mhz,每计一次数就是1us,设置的是向上计数,并且是每计100000个数就会进入一次中断,那就是每0.1s就led灯就会翻转一次,count值就会加一次,因为在while循环里面打印数据之前设置了一个1000ms的延时,那就是说每次打印数据就会进入10次中断,count就会加10。

附上代码地址
代码