用Arduino写个ESP32看门狗

本文介绍了如何利用Arduino IDE中的示例程序理解ESP32的看门狗功能,并创建了一个自定义的看门狗封装,使得看门狗如同定时器般工作,当超时时执行系统复位。作者提供了详细的代码实现,包括初始化、喂狗及按键超时验证的示例,便于读者理解和应用。

        参考了很多网上的关于ESP32看门狗文章,很多设置不正确,看门狗不起作用!无意间在Arduino软件的示例程序中翻到个Watchdog例程,打工一看,恍然大悟,原来就是个定时中断嘛!只不过中断程序执行一条复位指令就行了!我去,我以前认识中都觉得看门狗应该是独立的一个硬件,就只能看门,根本就没想他也可以是一个定时器!

        但软件中那个例程不够让我满意,干脆做个看门狗封装,方便以后使用.程序非常简单,有注释,大家一看就明白了.下面贴出代码,欢迎批评指正.

模块文件:Watchdog.c

/*
 * ESP32看门狗对象使用方法:
 * 1、引用对象定义文件(本文件):#include "Watchdog.C"
 * 2、申明看门狗对象变量:WATCHDOG Watchdog;
 * 3、初始化对象:Watchdog.begin();//默认使用定时器0,10秒超时。//也可以Watchdog.begin(1,1000);//指定定时器和超时时间。
 * 4、喂狗:Watchdog.feed();
 */
#ifndef ESP_RT_WDT_H  //避免重复定义.
  #define ESP_RT_WDT_H  
  #include "esp_system.h"
  class WATCHDOG {
    private:
      hw_timer_t *timer = NULL;//定时器对象.
      uint8_t Timerindex=0;//硬件定时器编号.默认定时器0.
      uint16_t Timeout=10000;//定时器计数.默认10秒超时.
    protected:
      static void Callback(){
        //定时器溢出回调函数,直接复位.
        esp_restart();
      }
      void Init(){
        if(timer!=NULL){timerEnd(timer);}//如果之前有设置过定时器,则关闭相应的定时器.
        timer=timerBegin(Timerindex,80,true);//使用硬件定时器,预分频80,向上计数。
        timerAttachInterrupt(timer,Callback,true);//设置回调函数,边延触发。
        timerAlarmWrite(timer,Timeout*1000,true);//设定中断计数器值,自动重启计数(循环定时)。CPU主频80MHz/80/1000=1毫秒。
        timerAlarmEnable(timer);//开启定时器。
      }
    public:
      WATCHDOG(){Timerindex=0;Timeout=10000;}
      void begin(){Init();}
      void begin(uint8_t Esp_Timerindex,uint16_t Esp_Timerout){Timerindex=Esp_Timerindex,Timeout=Esp_Timerout;begin();}
      void feed(void){timerWrite(timer,0);}//喂狗.
  };
#endif

验证程序文件Watchdog.ino

#include "Watchdog.C"
uint8_t button=0;//按键IO--D0(GPIO0)
WATCHDOG Watchdog;//看门狗对象.
void setup() {
  Serial.begin(115200);//串口波特率.
  Serial.println("系统复位!");//打印启动信息,以指示模块已经复位.
  pinMode(button,INPUT_PULLUP);//按键IO输入模式.
  Watchdog.begin();//默认定时器0,10秒超时.
  //Watchdog.begin(1,1000);//看门狗初始化,使用定时器1,1秒超时.
}

void loop() {
  Watchdog.feed();//喂狗.
  long loopTime = millis();
  while (!digitalRead(button)) {;}//如果按键超过设定时间,则会因来不及喂狗而超时.
  loopTime=millis()-loopTime;
  if(loopTime>1){Serial.printf("\r\n按键时间:%d毫秒.",loopTime);}//按键未超时则显示按键所用时间.
}

如果按键超时,就全重启,

<think>我们参考了上述引用资料,特别是引用[2]中提到的Arduino框架下ESP32 rtc看门狗使用示例和引用[5]中关于看门狗任务的深入解析。根据用户需求,我们需要提供一个在Arduino开发环境下使用ESP32看门狗的示例代码。 在ESP32中,看门狗主要分为两种:中断看门狗(Interrupt Watchdog Timer, IWDT)和任务看门狗(Task Watchdog Timer, TWDT)。此外,还有RTC看门狗(XTAL32K看门狗)等。在Arduino环境下,我们可以使用任务看门狗(TWDT)来监控任务是否正常运行。 以下是一个简单的任务看门狗(TWDT)使用示例。这个示例展示了如何初始化看门狗定时器,如何给看门狗喂狗,以及如何创建一个任务并让该任务定期喂狗。 注意:在Arduino框架中,我们通常使用`setup()`和`loop()`函数。但是,如果我们要使用FreeRTOS任务,我们可以创建额外的任务。 步骤: 1. 包含必要的头文件。 2. 初始化看门狗定时器(TWDT)。 3. 将当前任务(比如loop任务)添加到看门狗监控中(可选)。 4. 在需要监控的地方定期喂狗。 示例代码: ```cpp #include <esp_task_wdt.h> void setup() { Serial.begin(115200); // 初始化任务看门狗定时器(TWDT) esp_task_wdt_init(5, true); // 5秒超时,并且在超时后触发panic(重启) // 将当前任务(setup任务)添加到看门狗监控中(注意:setup任务在setup函数执行完成后就结束了,所以通常我们监控loop任务) // 因此,更常见的是在loop任务开始前将loop任务添加到看门狗 } void loop() { // 将loop任务添加到看门狗监控(每个任务只需要添加一次) // 注意:这里为了避免重复添加,我们使用一个静态变量标记 static bool taskAdded = false; if (!taskAdded) { esp_task_wdt_add(NULL); // NULL表示当前任务(即loop任务所在的FreeRTOS任务) taskAdded = true; } // 定期喂狗 esp_task_wdt_reset(); // 这里模拟一些工作 Serial.println("Working..."); delay(1000); // 延时1秒,但看门狗超时设为5秒,所以不会触发 // 如果我们在这里模拟一个长时间阻塞(超过5秒),则会触发看门狗重启 // 取消注释以下代码测试看门狗效果 // delay(6000); // 延时6秒,超过5秒,看门狗会重启系统 } ``` 代码说明: 1. `esp_task_wdt_init(5, true)`:初始化看门狗,设置超时时间为5秒,第二个参数为`true`表示超时后系统重启(panic)。 2. `esp_task_wdt_add(NULL)`:将当前任务(即调用该函数的任务)添加到看门狗监控列表中。注意,每个任务只需要添加一次,所以我们使用静态变量`taskAdded`来确保只添加一次。 3. `esp_task_wdt_reset()`:重置看门狗定时器(喂狗)。在loop中每次循环都会喂狗,保证正常运行时不会超时。 注意:在Arduino环境中,`loop()`函数运行在一个FreeRTOS任务中(通常称为loopTask)。所以我们监控的就是这个任务。 测试: 1. 正常情况下,每1秒打印一次"Working...",喂狗间隔小于5秒,因此不会触发看门狗。 2. 如果取消注释`delay(6000);`,则每次循环会阻塞6秒,超过5秒的看门狗超时时间,系统将会重启。 此外,引用[3]中提到RTC看门狗的使用,但需要注意的是,在Arduino-ESP32中默认可能没有启用RTC看门狗。如果需要使用RTC看门狗,可能需要直接操作寄存器,或者使用ESP-IDF的API(在Arduino中可以通过包含头文件`esp_system.h`并使用`esp_rtc_wdt_XXX`系列函数)。但引用[2]中提到的例子使用的是定时器(属于RTC看门狗),我们可以参考如下: RTC看门狗示例(注意:这个在Arduino环境中可能较少使用,而且需要特别注意,因为RTC看门狗是在RTC控制器中,即使在深度睡眠时也可能运行): ```cpp // RTC看门狗示例(需要包含头文件) #include "esp_system.h" void setup() { // 启用RTC看门狗,设置超时时间(单位是RTC时钟周期的倍数,通常RTC时钟为150kHz左右) // 超时时间 = 时钟周期 * 计数值 // 例如,设置3秒超时:3秒 * 150000 = 450000 esp_rtc_wdt_protect_off(); // 关闭保护 esp_rtc_wdt_enable(450000); // 设置超时计数值 esp_rtc_wdt_protect_on(); // 开启保护(可选) } void loop() { // 喂RTC看门狗 esp_rtc_wdt_protect_off(); esp_rtc_wdt_feed(); esp_rtc_wdt_protect_on(); delay(1000); } ``` 但是,请注意,RTC看门狗的使用需要谨慎,因为如果错误配置可能会导致频繁重启。而且,在Arduino环境中,这些函数可能没有被封装,所以可能需要检查Arduino-ESP32的版本是否支持。 综上所述,对于大多数应用,任务看门狗(TWDT)已经足够。因此,我们推荐使用任务看门狗。 根据引用[4]的比喻,看门狗就像一个闹钟,需要定期喂狗。如果忘记喂狗,系统就会重启。这可以增强系统的可靠性。 最后,引用[5]中还提到了看门狗任务的一些高级应用,例如将看门狗作为一个独立的任务来管理其他任务的状态,但这通常需要更复杂的FreeRTOS编程。 因此,我们提供了一个简单的任务看门狗示例,适用于Arduino环境下的ESP32。 相关问题: 1. 如何在Arduino框架下为ESP32启用中断看门狗(IWDT)? 2. 任务看门狗(TWDT)和中断看门狗(IWDT)有什么区别? 3. 如何配置RTC看门狗,并在深度睡眠模式下使用? 4. 如何避免看门狗误触发(例如在长时间操作中如何正确喂狗)? 5. 看门狗定时器在系统可靠性设计中的作用是什么? 请根据实际需求选择适合的看门狗类型并进行配置。 注意:以上代码示例仅供参考,具体使用时请根据实际情况调整。 </think>根据提供的引用资料,以下是 ESP32Arduino 开发环境下使用看门狗的示例代码和关键说明: ### 任务看门狗(TWDT)基础示例 ```cpp #include <esp_task_wdt.h> // 包含看门狗库 void setup() { Serial.begin(115200); // 初始化TWDT(超时时间5秒,触发panic重启) esp_task_wdt_init(5, true); // 将当前任务(主循环)注册到看门狗 esp_task_wdt_add(NULL); } void loop() { // 喂狗操作(必须在超时前执行) esp_task_wdt_reset(); Serial.println("正常工作状态"); delay(1000); // 模拟任务执行 } ``` ### RTC 看门狗高级示例 ```cpp #include "soc/timer_group_reg.h" #include "soc/timer_group_struct.h" void enable_rtc_wdt() { // STEP 1: 关闭保护 TIMERG0.wdt_wprotect = 0x50D83AA1; // 解锁寄存器 // STEP 2: 配置看门狗参数 TIMERG0.wdt_config0.en = 1; // 使能看门狗 TIMERG0.wdt_config0.stg0 = 1; // 第一阶段触发中断 TIMERG0.wdt_config0.stg1 = 3; // 第二阶段触发系统复位 TIMERG0.wdt_config0.sys_reset_length = 7; // 复位脉冲长度 TIMERG0.wdt_config0.cpu_reset_length = 7; TIMERG0.wdt_config1 = 5000000; // 5秒超时(单位:微秒) // STEP 3: 重新启用保护 TIMERG0.wdt_wprotect = 0; } void feed_rtc_wdt() { TIMERG0.wdt_wprotect = 0x50D83AA1; // 解锁 TIMERG0.wdt_feed = 1; // 喂狗 TIMERG0.wdt_wprotect = 0; // 加锁 } void setup() { enable_rtc_wdt(); } void loop() { feed_rtc_wdt(); // 必须定期喂食 delay(1000); } ``` ### 关键说明 1. **看门狗类型选择** - 任务看门狗(TWDT):监控 FreeRTOS 任务运行状态(推荐基础使用)[^2][^5] - RTC 看门狗:底层硬件看门狗,独立于系统运行[^3][^4] 2. **注意事项** - 喂狗间隔必须小于超时时间(如 5 秒示例需每 <5 秒喂一次) - RTC 看门狗需操作寄存器,每次喂狗需解锁-操作-加锁[^3] - 深度睡眠时普通看门狗会暂停,RTC 看门狗仍可工作[^2] 3. **典型应用场景** - 防止网络请求阻塞导致系统假死 - 传感器数据采集超时恢复 - 关键任务进程监控[^5] > 引用[^4]的精妙比喻:看门狗如同定时闹钟,必须定期"安抚",否则会"叫醒"整个系统重启恢复。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟渔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值