第十六章 ESP32S3 WATCH_DOG 实验

发布于:2025-08-31 ⋅ 阅读:(17) ⋅ 点赞:(0)

本章,将学习看门狗,基于定时器功能,如何用定时器模拟看门狗功能。
本章分为如下几个小节:
16.1 看门狗简介
16.2 硬件设计
16.3 程序设计
16.4 下载验证

16.1 看门狗简介

        MCU 可能工作在一些复杂环境,可能受到某些电磁干扰出现程序跑飞,导致死循环无法继续执行工作,看门狗的作用就是为了避免这种情况。看门狗的本质也是一个定时器,在程序启动后,需要在一定的时间内再给它一个信号,俗称“喂狗”。如果没有按时“喂狗”,说明系统或软件出现了不可预知的问题(比如软件卡在某个循环或逾期事件中),这时看门狗就向系统发送个复位信号,使整个系统重启,重新进入正常的工作状态。看门狗有助于检测、处理系统或软件的错误行为。
        ESP32-S3中有三个数字看门狗定时器、 1个模拟看门狗定时器和一个 XTAL32K看门狗定时
器,他们在各自有特定条件运行。本实验主要用是通用定时器模拟看门狗功能。
        本实验用到的函数跟第十四章 ESPTIMER 实验用到的函数是一致的。

16.2 硬件设计

16.2.1 例程功能
        程序运行后,开发板板载的 LED 因不停的复位而闪烁,但如果按下 BOOT 按键进行喂狗,那么就不会产生复位, LED也就保持常亮,一旦超过看门狗的溢出时间(Tout=1000毫秒)没有按下 BOOT 按键进行喂狗,那么就会进行复位, LED 也就会熄灭一次。

16.2.2 硬件资源
        1. LED
                LED - IO1
        2. 按键
                BOOT - IO0
        3. ESPTIMER

16.2.3 原理图
        本章实验使用的定时器为 ESP32-S3 的片上资源,因此并没有相应的连接原理图。

16.3 程序设计

16.3.1 程序流程图
        本实验的程序流程图:

图 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 TWDT_TIMEOUT_MS         3000
#define TASK_RESET_PERIOD_MS    2000
#define MAIN_DELAY_MS           10000

/* 函数声明 */
void wdt_init(uint16_t arr, uint64_t tps);  /* 初始化独立看门狗 */
void restart_timer(uint64_t timeout);       /*  */
void IRAM_ATTR wdt_isr_handler(void *arg);

(2)wdt.c

esp_timer_handle_t esp_tim_handle;                          /* 定时器回调函数句柄 */

/**
 * @brief       初始化任务看门狗计时器
 * @param       arr: 自动重装载值
 *              tps: 定时器周期
 */
void wdt_init(uint16_t arr, uint64_t tps)
{
    /* 定义一个定时器结构体 */
    esp_timer_create_args_t tim_periodic_arg = {
    .callback =	&wdt_isr_handler,                           /* 设置回调函数 */
    .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 和传统定时器除外)不会重置。此函数不会返回。

        esp_restart()函数执行流程:

图 16.3.2.1 esp_restart()函数执行流程图

        硬件复位流程:
        1)关闭外设​​:

  • 禁用所有中断
  • 关闭WiFi/BT射频
  • 停止所有外设时钟

        2)内存清理​​:

  • 刷新缓存
  • 重置内存控制器
  • 保留RTC内存内容

        3)复位触发​​:
        4)启动流程​​:

  • CPU从复位向量(0x40000080)开始执行
  • 执行二级引导程序
  • 重新初始化硬件
  • 跳转到用户代码入口

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)

16.3.5 实验应用代码
        打开 main/main.c 文件,该文件定义了工程入口函数,名为 app_main。该函数代码如下。

/**
 * @brief       程序入口
 * @param       无
 * @retval      无
 */
void app_main(void)
{
    esp_err_t rets;
    
    rets = nvs_flash_init();            /* 初始化NVS */

    if (rets == ESP_ERR_NVS_NO_FREE_PAGES || rets == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        rets = nvs_flash_init();
    }

    led_init();                         /* 初始化LED */
    key_init();                         /* 初始化按键 */
    wdt_init(5000, 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 常亮。


网站公告

今日签到

点亮在社区的每一天
去签到