СТОРОЖЕВОЙ ТАЙМЕР ARDUINO

Watchdog (англ. сторожевой пёс) – отдельный таймер на микроконтроллере, который имеет собственный источник тактирования и ни от кого не зависит. По данному таймеру можно ловить прерывания и использовать их в своих целях, а также он может перезагрузить микроконтроллер в случае зависания. Внимание! WDT для перезагрузки МК поддерживают не все загрузчики! Смотрите пример с проверкой работоспособности. Обычные прерывания по вочдогу работают на всех загрузчиках.

БИБЛИОТЕКА GYVERWDT

Библиотека для расширенной и удобной работы с watchdog

  • Перезагрузка по прерыванию
  • Вызов обычных прерываний
  • Настройка периода работы
  • Разработчик: Egor ‘Nich1con’ Zaharov

Поддерживаемые платформы: все Arduino

ДОКУМЕНТАЦИЯ


	void reset(void);                               // сброс
void disable(void);                             // отключить WDT
void enable(uint8_t mode, uint8_t prescaler);   // включить WDT с настройками
// mode:
// RESET_MODE - сброс при зависании (при тайм-ауте WDT)
// INTERRUPT_MODE - прерывание при зависании (при тайм-ауте WDT)
// INTERRUPT_RESET_MODE - первый таймаут - прерывание, второй - сброс
// prescaler:
// WDT_PRESCALER_2, WDT_PRESCALER_4... WDT_PRESCALER_1024

ПРИМЕРЫ


#include "GyverWDT.h"

/*
  Пример тестирующий поддержку всех функций watchdog на вышем устройстве
  > После 10 секунд отсчета программа стартует заного -> поддерживаются все функции
  > После таймаута устройство зависает, светодиод на D13 начинает мигать -> подерживается только INTERRUPT_MODE
  В случае bootloop у вас будет 10 секунд на перепрошивку устройства после подачи питания
  Для добавления поддержки всего функционала watchdog загрузите optiboot или откажитесь от загрузчика
*/


void setup() {
  Serial.begin(9600);

  Serial.println("Program started , wait 10 seconds");
  delay(10000);                                             // 10 секунд на перепрошивку в случае bootloop

  Watchdog.enable(RESET_MODE, WDT_PRESCALER_1024);          // Режим сторжевого сброса , таймаут ~8с
  Serial.println("watchdog enabled");

  while (1) {                                               // Бесконечный цикл , эмуляция "зависания"
    if (!(millis() % 1000)) {                               // Каждую секунду
      Serial.println((uint16_t)((millis() / 1000) - 10));   // Вывести время после включения watchdog в секундах
      delay(10);
    }
  }

}

void loop() {}
#include "GyverWDT.h"

/*
   Пример использования watchdog в качестве генератора прерываний
   Зависимость таймаутов от делителей см. в GyverWDT.h
*/

void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  Watchdog.enable(INTERRUPT_MODE, WDT_PRESCALER_128); // Режим генерации прерываний , таймаут ~1с
}

void loop() {
  /* Загруженный цикл */
  digitalWrite(13, HIGH);
  delay(5000);
  digitalWrite(13, LOW);
  delay(5000);
}

/* Прерывание watchdog */
ISR(WATCHDOG) {
  Serial.println("Hello from interrupt");
}
#include "GyverWDT.h"

/*
  Пример классического применения watchdog - сброс устройства при зависании
  Если не вызвать Watchdog.reset() вовремя - произойдет сброс
  Зависимость таймаутов от делителей см. в GyverWDT.h
*/

void setup() {
  pinMode(13, OUTPUT);
  Watchdog.enable(RESET_MODE, WDT_PRESCALER_512); // Режим сторжевого сброса , таймаут ~4с
}

void loop() {
  /* Ваш полезный код */
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
   
  Watchdog.reset(); // Переодический сброс watchdog, означающий, что устройство не зависло
}
#include "GyverWDT.h"
#include <avr/sleep.h>

/*
   Пример использования watchdog в "будильника"
   Зависимость таймаутов от делителей см. в GyverWDT.h
*/

void setup() {
  pinMode(13, OUTPUT);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Выбираем нужный режим сна
}

void loop() {

  /* Мигаем светодиодом , а в паузах спим */
  digitalWrite(13, HIGH);

  Watchdog.enable(INTERRUPT_MODE, WDT_PRESCALER_128); // Режим прерываний , таймаут ~1c
  sleep_enable();                                     // Разрешаем сон
  sleep_cpu();                                        // Уходим в сон

  digitalWrite(13, LOW);

  Watchdog.enable(INTERRUPT_MODE, WDT_PRESCALER_128); // Режим прерываний , таймаут ~1c
  sleep_enable();                                     // Разрешаем сон
  sleep_cpu();                                        // Уходим в сон

}

/* Прерывание watchdog , в нем мы просыпаемся */
ISR(WATCHDOG) {
  sleep_disable();     // Запрещаем сон
  Watchdog.disable();  // Выключаем watchdog
}
#include "GyverWDT.h"

/*
   Пример работы watchdog для контроля сразу за двумя устройствами
   В данном случае - arduino + esp8266 модуль
   Зависимость таймаутов от делителей см. в GyverWDT.h
*/

void setup() {
  Serial.begin(9600);                                         // На этом последовательном порту у нас wifi-модуль
  pinMode(8, INPUT);                                          // Этот пин сбрасывает wifi-модуль при переходе в режим OUTPUT
  Watchdog.enable(INTERRUPT_RESET_MODE, WDT_PRESCALER_1024);  // Комбинированный сторжевой режим , таймаут ~8с
}


void loop() {
  /* Ваш полезный код */
}

/* Если wifi-модуль нам что то отправил , а мы его поняли - никто из нас не завис */
void serialEvent() {
  Watchdog.reset();  // Сбросить watchdog
}

/* Если wifi-модуль не отправлял нам что то более 8с - он завис */
ISR(WATCHDOG) {
  pinMode(8, OUTPUT);                                         // Тянем за reset модуля
  Watchdog.enable(INTERRUPT_RESET_MODE, WDT_PRESCALER_1024);  // Если мы не смогли перенастроить watchdog - значит мы зависли
  Watchdog.reset();                                           // Если не зависли - сбросить watchdog и продолжить
  pinMode(8, INPUT);                                          // Отпускаем reset модуля
}
#include "GyverWDT.h"

/*
   Пример использования watchdog в комбинированном режиме
   Может использоваться для оповещения в случае зависания
   Первый тайм-аут вызывает прерывание, второе - сброс
   Перенастройте watchdog чтобы избежать сброса
   Зависимость таймаутов от делителей см. в GyverWDT.h
*/

void setup() {
  Serial.begin(9600);
  Serial.println("Program started");
  Watchdog.enable(INTERRUPT_RESET_MODE, WDT_PRESCALER_128);   // Комбинированный режим , таймаут ~1c
  Serial.println("watchdog enabled");
  while (1);                                                  // Причина зависания
  Serial.println("loop started");                             // Этого мы не увидим из-за зависания
}

void loop() {
  /* этого кода программа не достигнет - зависание в setup */
  Serial.println("hello");
  delay(500);
}

/* Первый тайм-аут вызывает прерывание */
ISR(WATCHDOG) {
  // Если причина зависания программная - тут можно попытаться исправить ее */
  Serial.println("warning!");
  // Если исправить причину не вышло - следующий таймаут вызывает сброс
  // Watchdog.enable(INTERRUPT_RESET_MODE, WDT_PRESCALER_128); // Если перенастроить watchdog здесь - сброса не будет
}

ОСТАЛЬНЫЕ БИБЛИОТЕКИ

У меня есть ещё очень много всего интересного! Смотрите полный список библиотек вот здесь.