En este nuevo artículo vamos a ver qué es un watchdog, para qué se puede usar, y cómo usarlo en tus proyectos Arduino. Todo lo que necesitas saber sobre esta función tan interesante a la par que desconocida. Y sí, como su nombre indica (perro guardián), puede servir para rastrear algunos problemas.
Aquí vamos a ver todo lo que necesitas saber a respecto…
¿Qué es un watchdog?
En informática, un watchdog (perro guardián) es un mecanismo de supervisión que se utiliza para monitorear el funcionamiento de un sistema o programa. Su función principal es detectar y responder a situaciones anómalas o fallos en el sistema, como bloqueos o congelamientos, y tomar medidas correctivas para garantizar la continuidad de la operación o la recuperación del sistema.
El watchdog opera mediante un temporizador que se configura para un intervalo de tiempo específico. Si el sistema o programa no realiza una acción específica o no alimenta el watchdog (es decir, no lo reinicia) dentro de ese intervalo de tiempo, el watchdog asume que el sistema está en un estado no deseado o ha dejado de responder correctamente y toma una acción predeterminada. Esta acción puede variar según la implementación y puede incluir reiniciar el sistema, generar registros de errores, activar alarmas, o tomar medidas específicas para corregir el problema.
El watchdog se utiliza en una variedad de sistemas informáticos y dispositivos, desde sistemas operativos y servidores hasta dispositivos embebidos y sistemas críticos en tiempo real, entre ellos Arduino. Su objetivo principal es mejorar la fiabilidad y la disponibilidad del sistema al detectar y responder a problemas de manera automática, reduciendo así la necesidad de intervención manual en situaciones de fallo.
¿Qué es el watchdog de Arduino?
El temporizador de vigilancia, o watchdog timer de Arduino, debe ajustarse según las necesidades de la aplicación. El Watchdog Timer hace uso de una fuente de reloj interna de 128 kHz (puede variar según la placa y MCU utilizada). Cuando se activa, comienza a contar desde cero hasta un valor predeterminado por el usuario. Si el Watchdog Timer no se reinicia cuando alcanza dicho valor, este reinicia el microcontrolador.
El Watchdog Timer ATmega328P, que se implementa en Arduino UNO, ofrece 10 configuraciones de tiempo diferentes, cada una determinando cuándo el temporizador se desbordará y, por lo tanto, causará un reinicio. Los distintos intervalos de tiempo son los siguientes: 16 ms, 32 ms, 64 ms, 0.125 segundos, 0.25 segundos, 0.5 segundos, 1 segundo, 2 segundos, 4 segundos y 8 segundos, como veremos más adelante en la tabla que incluyo.
Si aún no te ha quedado claro qué puedes hacer con el Watchdog Timer de Arduino UNO, vamos a ver un ejemplo para que lo comprendas de forma gráfica. En este ejemplo, utilizaremos un sencillo parpadeo de LEDs (blink). Los LEDs parpadean durante un período determinado antes de ingresar al bucle while(). Este bucle while() se emplea como una alternativa a un sistema bloqueado. Dado que el Watchdog Timer no se reinicia mientras está en el bucle while(), provocará un reinicio del sistema, y los LEDs comenzarán a parpadear nuevamente antes de que el sistema se bloquee y reinicie. Este ciclo continuará…
Consideraciones y características
El Watchdog Timer se encuentra desactivado al inicio del código. Se incorpora un retraso de x segundos antes de habilitar el Watchdog. Este retraso es crucial para permitir que el gestor de arranque de Arduino verifique si se está cargando un nuevo código y para otorgar tiempo suficiente para grabar el código en la memoria flash. Este aspecto es relevante por precaución. Puede surgir una situación en la que, debido a una codificación defectuosa o consideraciones inadecuadas, el código escrito reinicie el microcontrolador en intervalos muy cortos de manera infinita. Esto puede dañar la placa Arduino y evitar que los códigos se carguen correctamente en ella. Si esto ocurre, es necesario grabar el cargador de arranque utilizando otro Arduino como ISP en el Arduino bloqueado…
Cuando empleamos el watchdog de Arduino, es necesario utilizar registros de bits para definir el comportamiento del chip. Los registros pertinentes y su significado se encuentran detallados en el datasheet del microcontrolador que está presente en la placa de Arduino. Sin embargo, el entorno de desarrollo integrado (IDE) de Arduino viene con algunas funciones y macros diseñadas para simplificar este proceso, las cuales pueden importarse mediante la inclusión de la biblioteca #include <avr/wdt.h> para usar el watchdog del chip AVR.
De esta manera, podemos configurar el watchdog activándolo mediante la función wdt_enable(). El argumento de esta función determina el tiempo antes de que la placa se reinicie en caso de que el temporizador no haya sido reiniciado. En cuanto a los valores que puedes configurar en el código, aquí te los incluyo:
Tiempo antes de que se dispare el watchdog | Argumento de wtd_enable() |
15 ms | WDTO_15MS |
30 ms | WDTO_30MS |
60 ms | WDTO_60MS |
120 ms | WDTO_120MS |
250 ms | WDTO_250MS |
500 ms | WDTO_500MS |
1 s | WDTO_1S |
2 s | WDTO_2S |
4 s | WDTO_4S |
8 s | WDTO_8S |
Ejemplo de uso de watchdog en Arduino
Para finalizar, vamos a ver cómo se usa de forma práctica el watchdog con un ejemplo en Arduino IDE. Como vemos, es bastante simple, puedes encontrar diversos códigos fuente como este en Internet, para poder practicar, modificar, y crear tus propios códigos para usar watchdog en tus proyectos. Veamos nuestro ejemplo:
#include <avr/wdt.h> // Incluir la biblioteca watchdog (wdt.h) void setup() { wdt_disable(); // Desactivar el watchdog mientras se configura, para que no se resetee wdt_enable(WDTO_2S); // Configurar watchdog a dos segundos } void loop() { wdt_reset(); // Actualizar el watchdog para que no produzca un reinicio //Aquí iría el código de tu programa... }
Como se puede observar en este ejemplo de sketch para Arduino, existen tres funciones del lenguaje de programación destacables para el manejo del watchdog, y estas son:
- wdt_disable() para desactivar el timer mientras se configura Arduino.
- wdt_enable(tiempo) para asignar un intervalo al timer e iniciarlo, especificando el tiempo correspondiente como he mostrado en la tabla anterior.
- wdt_reset() para renovar el intervalo asignado y que el programa no se reinicie.