Arduino (IoT): Simple Tutorial RTC: Parte IV – WatchDog Timer (WDT)

Arduino Honduras Santiapps Marcio Valenzuela

Tutorial RTC: Parte IV – WatchDog Timer (WDT)

En esta parte utilizamos nuestro el WatchDogTimer (WDT) interno del Arduino para resetear nuestra Arduino UNO cada 8 segundo.  El WDT es otra manera de “despertar” una Arduino o resetearla.  Es muy común a la hora de revivir una Arduino que por mal código o malas condiciones electrónicas puede haber caído en un loop y esta atascada.

Requisitos:

  1. Computadora (mac)
  2. Arduino UNO
  3. Breadboard
  4. Arduino IDE (https://www.arduino.cc/en/Main/Software)
Arduino Tutorial Real Time Clock RTC DS1307 Santiapps Marcio Valenzuela
Arduino Tutorial Real Time Clock RTC DS1307

El código:

#include <avr/wdt.h>
#define RESETWATCHDOG
void setup(){
 Serial.begin(57600);
 Serial.println("");
 Serial.println ("------->Arduino Rebooted");
 Serial.println("");
 wdt_enable(WDTO_8S); // Reseteara la Arduino c/ 8 segundos
}
void loop(){
#ifdef RESETWATCHDOG
 wdt_reset(); // Reiniciar el WDT (Pat the Dog)
#endif
 Serial.println("Arduino Running");
 delay(1000);
}

 

Con este código respetamos la Arduino cada 8 segundos usando el WDT.  Al definir RESETWATCHDOG, corremos el bloque que incluye wdt_reset().  Este comando es conocido como “Pat the Dog” lo cual se traduce a “tranquilizar al perro dandole unas palmadas suaves sobre la cabeza”.  Esto es por lo siguiente: Consideramos que el timer así como cualquier alarma es como tener un perro despertador que muerde.  Cuando la alarma se dispara se dice que el perro mordió!  Pero si al perro enojado, antes que muerda, se le da unas palmadas en la cabeza, el perro se tranquiliza por un rato y no muerde.  En resumen, al configurar un timer cada 8S, estamos esperando que el perro nos muerda a los 8 segundos de arrancar el timer.  Pero si queremos que no nos muerda, le damos un “Pat” en la cabeza para que se vuelva a dormir.

8 segundos es el máximo sin embargo podemos usar un poco de ingenio de programación para alargar ese tiempo.  Por ejemplo:

#include <avr/sleep.h>
#include <avr/wdt.h>

/*********************
* PRESCALER - modifies the clock times. For delay(1000) with Mode 4, delay would be 16x longer.
* Mode 0 - Do nothing - normal 16Mhz clock
* Mode 1 - Clock divide by 2 - 8MHz
* Mode 2 - Clock divide by 4 - 4MHz
* Mode 3 - Clock divide by 8 - 2MHz
* Mode 4 - Clock divide by 16 - 1MHz
* Mode 5 - Clock divide by 32 - 500kHz
* Mode 6 - Clock divide by 64 - 250kHz
* Mode 7 - Clock divide by 128 - 125kHz
* Mode 8 - Clock divide by 256 - 62.5kHz
*********************/
#define Set_prescaler(x)  (CLKPR = (1<<CLKPCE),CLKPR = x) //for any delays, they are multiplied by the prescaler time
#define LED 5
int Prescaler_mode = 4;
const int A0_pin = A0;


/*********************
* WATCHDOG INTERRUPT
*********************/
ISR(WDT_vect) {
  wdt_disable();  // disable watchdog
}
void myWatchdogEnable(const byte interval) {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
} 

void setup(){
  Set_prescaler(Prescaler_mode);  // 1/16 clock speed
  int i;
  for(i = 0; i <= 19; i++)  // all pins set as input w/ pulp resistor
  {
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  } 
  pinMode (LED, OUTPUT);
  pinMode(A0_pin, INPUT);
}

void loop(){
  if (analogRead(A0_pin) >= 1000){
    digitalWrite (LED, LOW);
  } else {
    digitalWrite (LED, HIGH);
  }
  delay(65);
  /*********************
   * SLEEP BIT PATTERNS
   * 1 second:  0b000110
   * 2 seconds: 0b000111
   * 4 seconds: 0b100000
   * 8 seconds: 0b100001
   *********************/

  // sleep for a total of 240 seconds [240/8=30]
  int i;
  for (i = 0; i < 30; i++)
  {  
    myWatchdogEnable (0b000110);  // 1 seconds
  }
}

Aquí estamos durmiendo la UNO por 30 unidades de 8 segundos cada una, ósea 240 segundos en total o 4 minutos.  Referencia: http://forum.arduino.cc/index.php/topic,173850.0.html

Que hemos aprendido con este tema de dormir el MCU?  Pues tenemos una manera de ahorrar energía y de resetear la MCU para que se puede recuperar de algún error. La primera function tiene una utilidad clara, ahorrar energía en momentos donde es limitada, como cuando corremos un proyecto desde una fuente de energía limitada como ser un battery pack recargado por un panel solar u otra fuente temporal.  Esto nos obliga a usar nuestra energía de manera conservadora.

La segunda función es util para recuperar el MCU de un problema de código o algo externo que haya interrumpido la operación normal del programa base (setup() -> loop() ).  Esto nos permite revisar la MCU cada tanto tiempo y ella debe responder correctamente, conocido como “patting the dog”.  De no ser así, la alarma se dispara, el perro nos muerde y procedemos a reiniciar la MCU.

Este es un tema bien complejo y espero que si tienes dudas nos las hagas llegar.  Cualquier cosa lee nuestra serie de Arduino Durmiente para entender un poco mas sobre el WatchDog Timer.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s