图14.3.1.1 ESPTIMER实验程序流程图
14.3.2 ESPTIMER函数解析
ESP-IDF提供了一套API来配置高精度定时器。要使用此功能,需要导入必要的头文件:
#include "esp_timer.h"
接下来,作者将介绍一些常用的ESPTIMER函数,这些函数的描述及其作用如下:
1,创建一个事件
该函数用于创建ESPTIMER实例,其函数原型如下所示:
esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args,
esp_timer_handle_t* out_handle);
该函数的形参描述如下表所示:
表14.3.2.1 函数esp_timer_create()形参描述
返回值:ESP_OK表示创建成功。其他表示创建失败。
下面是esp_timer_create_args_t结构体的成员变量描述。
| 参数1 | |
| | |
void* arg:一个指针类型,将参数传递给回调函数。 | |
dispatch_method:从task或ISR调用回调。 | |
constchar* name: 定时器名称,用于ESPTIMER转储功能。 | |
skip_unhandled_events:跳过周期计时器的未处理事件。 | |
表14.3.2.2 结构体tim_periodic_arg描述
2,每个周期内触发一次
该函数用于使能定时器的指定中断,其函数原型如下所示:
esp_err_t IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer,
uint64_t period_us);
该函数的形参描述,如下表所示:
| |
| 使用esp_timer_create创建的定时器句柄 |
| |
表14.3.2.3 函数esp_timer_start_periodict()形参描述
返回值:ESP_OK表示开启定时器成功。其他表示开启失败。
14.3.3 ESPTIMER驱动解析
在IDF版的05_esp_timer例程中,作者在05_esp_timer \components\BSP路径下新增了一个ESPTIM文件夹,用于存放esptim.c和esptim.h这两个文件。其中,esptim.h文件负责声明ESPTIMER相关的函数和变量,而esptim.c文件则实现了ESPTIMER的驱动代码。下面,我们将详细解析这两个文件的实现内容。
1,esptim.h文件
/* 函数声明 */
void esptim_int_init(uint64_t tps); /* 初始化初始化高分辨率定时器 */
void esptim_callback(void *arg); /* 定时器回调函数 */
2,esptim.c文件
/**
* @param tps: 定时器周期,以微妙为单位(μs),以一秒为定时器周期来执行一次定时器中断,那此处tps = 1s = 1000000μs * @retval 无
*/
void esptim_int_init(uint64_t tps)
{
esp_timer_handle_t esp_tim_handle; /* 定时器回调函数句柄 */
/* 定义一个定时器结构体 */
esp_timer_create_args_t tim_periodic_arg = {
.callback = &esptim_callback, /* 设置回调函数 */
.arg = NULL, /* 不携带参数 */
};
esp_timer_create(&tim_periodic_arg, &esp_tim_handle); /* 创建一个事件 */
esp_timer_start_periodic(esp_tim_handle, tps); /* 每周期内触发一次 */
}
/**
* @brief 定时器回调函数
* @param arg: 不携带参数
* @retval 无
*/
void esptim_callback(void *arg)
{
LED_TOGGLE();
}
从ESPTIMER的初始化代码中可以看到,结构体esp_timer_create_args_t通过其中两个结构体成员,以指针的形式调用定时器回调函数。传入的参数tim_periodic_arg,目的在于方便后续的调用,而esp_timer_create()函数便是通过指针的方式完成对该结构体的调用,之后再通过esp_timer_start_periodic()函数设定周期,最终完成ESPTIMER的初始化配置。
在定时器回调函数中,我们调用了LED状态翻转函数,并设定,定时器的每一次计数溢出都会翻转一次LED的状态。关于ESPTIMER结构体的介绍,请读者回顾本章节的14.3.2小节内容。
14.3.4 CMakeLists.txt文件
打开本实验BSP下的CMakeLists.txt文件,其内容如下所示:
set(src_dirs
ESPTIM
LED)
set(include_dirs
ESPTIM
LED)
set(requires
driver
esp_timer)
idf_component_register(SRC_DIRS ${src_dirs}
INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
上述的红色ESPTIM驱动需要由开发者自行添加,以确保ESPTIM驱动能够顺利集成到构建系统中,需要注意的是我们的依赖库(requires)需要添加上ESP32-S3定时器的库。这一步骤是必不可少的,它确保了ESPTIM驱动的正确性和可用性,为后续的开发工作提供了坚实的基础。
14.3.5 实验应用代码
打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
uint8_t len = 0;
uint16_t times = 0;
unsigned char data[RX_BUF_SIZE] = {0};
ret = nvs_flash_init(); /* 初始化NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
led_init(); /* 初始化LED */
esptim_int_init(1000000); /* 初始化高分辨率定时器,此处设置定时器周期为1秒,
但该函数以微秒为单位进行计算,
故而1秒钟换算为1000000微秒 */
}
从上面的代码中可以看到,ESP定时器的周期值配置为1000000,因为ESP32-S3高分辨率定时器的计数周期是以微秒作为基础单位进行运算,所以当我们设定计数周期为1秒时需要将单位换算为微秒。因此LED的闪烁周期为1秒。
14.4 下载验证
在完成编译和烧录操作后,可以看到板子上的LED在闪烁,LED在ESP定时器的中断回调函数中被改变状态,LED每间隔1000毫秒改变一次状态。