ITPub博客

首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > 《ESP32S3 Arduino开发指南 V1.0 》第十二章 WATCH_DOG实验

《ESP32S3 Arduino开发指南 V1.0 》第十二章 WATCH_DOG实验

原创 嵌入式/内核开发 作者:正点原子 时间:2024-12-05 09:17:58 0 删除 编辑

第十二章 WATCH_DOG实验


       本章,我们将学习看门狗,基于定时器功能,教大家如何用定时器模拟看门狗功能。

       本章分为如下几个小节:

       12.1 看门狗介绍

       12.2 硬件设计

       12.3 软件设计

       12.4 下载验证


        12.1 看门狗简介

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

       ESP32-S3中有三个数字看门狗定时器、1个模拟看门狗定时器和一个XTAL32K看门狗定时器,他们在各自有特定条件运行。本实验主要用是通用定时器模拟看门狗功能。

       本实验用到的函数跟第十一章定时器中断实验用到的函数是一致的。


        12.2 硬件设计


       1. 例程功能

       程序启动后,配置定时器的定时时间为1.2秒,定时到来时执行中断回调函数中打印操作以及软件复位操作。主循环中每隔1秒给进行喂狗,若按下按键会延时0.5秒,会导致无法在1.2秒内进行喂狗,导致进入中断回调函数中进行软件复位。


       2. 硬件资源


       1)独立按键

              BOOT-IO0


       2)USART0

              U0TXD-IO43

              U0RXD-IO44


       3)Timer1


       3. 原理图

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


        12.3 软件设计


       12.3.1 程序流程图

       下面看看本实验的程序流程图:


图12.3.1.1 程序流程图


       12.3.2 程序解析


       1. watchdog驱动代码

       这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。EXTI驱动源码包括两个文件:watchdog.cpp和watchdog.h。

       下面我们先解析watchdog.h的程序。对看门狗功能的定时器做了相关定义。

#define WDG_TIMx    1            /* 模拟看门狗用到的定时器 */
#define WDG_ISR     tim1_ISR   /* 定时器中断服务函数 */

       我们选择使用通用定时器1作为模拟看门狗的定时器,当然你也可以通过改变WDG_TIMx的值选择别的定时器作为看门狗功能。WDG_ISR宏是定时器1的中断回调函数,采用该宏移植性更加强。

       下面我们再解析watchdog.cpp的程序,这里有两个函数wdg_init和TIMX_ISR,其定义如下:

hw_timer_t *wdg_timer = NULL;
 
/**
 * @brief 初始化看门狗
 * @note
 *           定时器的时钟来自APB,而APB为80M
 *         所以定时器时钟 = (80/psc)Mhz, 单位时间为 1 / (80 / psc) = x us
 *           定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us
 *          Ft=定时器工作频率,单位:Mhz
 *
 * @param arr: 自动重装值
 * @param  psc: 时钟预分频数
 * @retval  无
 */
void wdg_init(uint32_t arr, uint16_t psc)
{
    wdg_timer = timerBegin(WDG_TIMx, psc, true);  /* 初始化定时器1 */
 
    timerAlarmWrite(wdg_timer, arr, true);          /* 设置中断时间 */
 
    timerAttachInterrupt(wdg_timer, &WDG_ISR, true); /* 配置定时器中断回调函数 */
 
    timerAlarmEnable(wdg_timer);                        /* 使能定时器中断 */
}
 
/**
 * @brief   看门狗定时器中断回调函数
 * @param  无
 * @retval  无
 */
void WDG_ISR(void)
{
    ets_printf("reboot\n");
    esp_restart();
}

       wdg_init函数是初始化定时器1,首先调用timerBegin函数初始化一个定时器对象并采用向上计数方式,然后调用timerAlarmWrite函数配置中断时间并设置自动加载,后面再调用timerAttachInterrupt函数设置定时器边沿触发中断,最后调用timerAlarmEnable函数使能开启定时器。

       注意:定时器的定时时间是由wdg_init函数的参数决定,这里我们还定义了一个全局的hw_timer_t类型的结构体指针wdg_timer。

       WDG_ISR函数就是定时器1中断回调函数。函数比较简单,调用ets_printf函数打印“reboot”,后面就是调用esp_restart函数执行软件复位。

       这里需要注意:需要在watchdog.h中添加esp_system头文件支持。


       2. 06_watch_dog.ino代码

       在06_watch_dog.ino里面编写如下代码:

#include "uart.h"
#include "key.h"
#include "watchdog.h"
 
 
#define wdg_timeout 1200    /* 看门狗定时时间,1200ms */
 
/**
 * @brief   当程序开始执行时,将调用setup()函数,通常用来初始化变量、函数等
 * @param   无
 * @retval  无
 */
void setup() 
{
    key_init();                       /* KEY初始化 */
    uart_init(0, 115200);                  /* 串口0初始化 */
    Serial.println("running setup");   /* 打印标志性信息 方便查看系统开始 */
 
    wdg_init(wdg_timeout * 1000, 80); /* 初始化看门狗,80分频,定时时间1.2秒 */
}
 
/**
 * @brief   循环函数,通常放程序的主体或者需要不断刷新的语句
 * @param  无
 * @retval  无
 */
void loop() 
{
    Serial.println("running main loop"); /* 打印标志性信息 方便查看系统开始 */
 
    timerWrite(wdg_timer, 0);              /* 复位定时器(喂狗) */
 
    long looptime = millis();             
/* 通过millis函数获取开发板开始运行当前程序以来经过的毫秒数 */
 
    while (!KEY) /* 按下按键会延时500ms,最终会导致looptime时间变为1.5秒,还没有来得及喂狗,就进入到定时器中断回调函数中复位 */
    {
        Serial.println("key pressed, delay_500ms");
        delay(500);
    }
 
    delay(1000);                          
    looptime = millis() - looptime;    /* 监控上过程运行时间 */
 
    Serial.print("loop time is = ");    /* 打印上过程运行时间 */
    Serial.println(looptime); 
}

       在setup函数中,调用key_init完成按键初始化,调用uart_init函数完成串口0的初始化,然后调用wdg_init函数初始化定时器1,这里设置的定时的时间为1.2秒,通过wdg_timeout宏决定。

       在loop函数中,一开始串口打印时间执行的标识,然后调用timerWrite函数设置定时器的计数器值为0。该操作相当于喂狗操作,这时候,定时器就会从0开始计数,向1200000递增计数,当计数到1199999就会进入到我们编写好的WDG_ISR中执行操作。但是程序正常执行下(把按键检测的程序去掉),这时候会调用delay函数延时1秒,这种执行下,定时器进入不到中断的。所以要使得定时器进入到中断,就需要按下按键,这时候就会超时,没有在1.2秒内喂狗,导致进入到中断回调函数中进行软件复位操作。

       以上就是简单的例子演示模拟看门狗,无法及时喂狗,就会导致程序复位。很多时候,编写程序,会发现程序一直重启,不能正常运行,很大可能就是系统跑飞,导致看门狗无法及时喂养。

       上面程序中用到函数millis,该函数的作用是获得程序运行的时间(以毫秒为单位)。


        12.4 下载验证

       下载代码完成后,ESP32-S3开发板串口输出信息,执行loop代码的时间。当按键按下时,会进行复位。无按键按下时,会隔1秒打印loop代码执行时间。有无按键按下时程序执行情况如下图所示。


图12.4.1 有无按键按下时程序执行情况


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3054706/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-08-30

  • 博文量
    588
  • 访问量
    764184