图16.3.1.1 WATCH_DOG实验程序流程图
16.3.2 WATCH_DOG函数解析
本实验用到的函数跟第十四章ESPTIMER实验使用的定时器是一致的,在此不作出赘述,请读者们参考第十四章的内容。
16.3.3 WATCH_DOG驱动解析
在IDF版的07_wdt例程中,作者在07_wdt \components\BSP路径下新增了一个WDT文件夹,用于存放wdt.c和wdt.h这两个文件。其中,wdt.h文件负责声明WDT相关的函数和变量,而wdt.c文件则实现了WDT的驱动代码。下面,我们将详细解析这两个文件的实现内容。
1,wdt.h文件
/* 引脚定义 */
#define BOOT_INT_GPIO_PIN GPIO_NUM_0
/*IO操作*/
#define BOOT gpio_get_level(BOOT_INT_GPIO_PIN)
/* 函数声明 */
void exit_init(void); /* 外部中断初始化程序 */
2,wdt.c文件
/**
*/
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 timeout: 定时器超时时间,该超时时间以微妙作为基本计算单位,
故而设置超时时间为1s,则需要转换为微妙(μs),
即timeout = 1s = 1000000μs
* @retval 无
*/
void restart_timer(uint64_t timeout)
{
/* 重新启动当前运行的计时器,用以模拟喂狗过程 */
esp_timer_restart(esp_tim_handle, timeout);
}
/**
* @brief 看门狗回调函数
* @param arg: 无参数传入
* @retval 无
*/
void IRAM_ATTR wdt_isr_handler(void *arg)
{
esp_restart(); /* 若没有及时进行喂狗,那么芯片将一直进行复位 */
}
WDT的初始化函数中调用了看门狗回调函数,用以模拟当定时器溢出时产生的复位现象。
同时,我们在restart_timer()函数中调用了esp_timer_restart()。该函数的主要作用在于:当函数在调用时重新启动当前所运行的定时器,用以模拟喂狗过程。对于该函数而言,我们假设给定的计时器为一次性计时器,那么计时器将立即重启,并在timeout_us微秒内超时一次。当假设给定的计时器为周期性计时器,那么立即以新的timeout_us微秒周期重新启动计时器。
另外,在wdt_isr_handler()中调用了esp_restart()。该函数的主要作用在于将芯片复位,用以模拟程序在没有“喂狗”的情况下跑飞。此函数既可以从PRO中调用,也可以从APPCPU调用。成功重启后,CPU重置原因将为SW_CPU_reset。外设如Wi-Fi、BT、UART0、SPI1和传统定时器除外)不会重置。此函数不会返回。
16.3.4 CMakeLists.txt文件
打开本实验BSP下的CMakeLists.txt文件,其内容如下所示:
set(src_dirs
KEY
LED
WDT)
set(include_dirs
KEY
LED
WDT)
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)
上述的红色KEY、WDT驱动需要由开发者自行添加,以确保WDT驱动能够顺利集成到构建系统中。需要注意的是我们的依赖库(requires)需要添加上ESP32-S3定时器定时器的库,这些步骤是必不可少的,它确保了WDT驱动的正确性和可用性,为后续的开发工作提供了坚实的基础。
16.3.5 实验应用代码
打开main/main.c文件,该文件定义了工程入口函数,名为app_main。该函数代码如下。
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t rets;
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 */
key_init(); /* 初始化按键 */
wdt_init(1000000); /* 初始化定时器 */
LED(0); /* LED灯常亮 */
while (1)
{
if (key_scan(0) == BOOT_PRES) /* 如果BOOT按下则喂狗 */
{
restart_timer(1000000); /* 喂狗 */
}
vTaskDelay(10); /* LED闪烁 */
}
}
可以看到应用代码中,LED初始化后,LED会处于常亮状态,随后初始化WDT模拟定时器溢出过程,会看见LED在不断闪烁,此时的ESP32-S3芯片处于一直复位状态。接着在while循环中重复判断BOOT按键是否被按下,若按下则进行“喂狗”操作,若在WDT溢出前都为按下BOOT按键,那么就不会产生复位,LED也就保持常亮。
16.4 下载验证
在完成编译和烧录操作后,可以看到板子上的LED每间隔一段时间(大约1秒)就闪烁一次,这是因为WDT不断地对芯片进行复位。接下来若以时间间隔小于1秒(大约)的速度频繁地按下BOOT按键,则可以在芯片复位前及时“喂狗”,具体的现象为LED常亮。