Usar AVR Watchdog como ISR normal

15

Estoy tratando de envolver mi cabeza alrededor del temporizador de vigilancia de la serie ATTinyX5. Así que las cosas que he leído hacen que parezca que podrías usarlo para hacer que el programa haga algo específico cada N segundos, pero nunca mostró cómo. Otros hicieron que pareciera que solo restablecería el chip a menos que algo en el código se restablezca mientras tanto (lo que parece ser el uso "normal").

¿Hay alguna forma de usar el WDT como lo haría con TIMER1_COMPA_vect o similar? Noté que tiene un modo de tiempo de espera de 1 segundo y me encantaría poder usar eso para hacer que algo suceda cada 1 segundo en mi código (y preferiblemente dormir entre ellos).

¿Pensamientos?

* Actualización: * Desde que se me preguntó, me refiero a la sección 8.4 de Hoja de datos ATTinyX5 . No es que lo entienda completamente, que es mi problema ...

    
pregunta Adam Haile

3 respuestas

20

Lo más seguro es que puedas. De acuerdo con la hoja de datos, el temporizador de vigilancia puede configurarse para restablecer la MCU o provocar una interrupción cuando se dispara. Parece que estás más interesado en la posibilidad de interrupción.

El WDT es realmente más fácil de configurar que un temporizador normal por la misma razón que es menos útil: menos opciones. Se ejecuta en un reloj de 128 kHz calibrado internamente, lo que significa que su tiempo no se ve afectado por la velocidad del reloj principal de la MCU. También puede continuar ejecutándose durante los modos de suspensión más profundos para proporcionar una fuente de activación.

Voy a repasar un par de ejemplos de hojas de datos, así como algunos códigos que he usado (en C).

Archivos y definiciones incluidos

Para comenzar, es probable que desees incluir los siguientes dos archivos de encabezado para que las cosas funcionen:

#include <avr/wdt.h>        // Supplied Watch Dog Timer Macros 
#include <avr/sleep.h>      // Supplied AVR Sleep Macros

También utilizo la macro < _BV (BIT) > que se define en uno de los encabezados estándar de AVR como los siguientes (que pueden ser más familiares para usted):

#define _BV(BIT)   (1<<BIT)

Comienzo del código

Cuando se inicia por primera vez la MCU, normalmente se inicializa la E / S, se configuran los temporizadores, etc. En algún lugar aquí es un buen momento para asegurarse de que el WDT no causó un restablecimiento porque podría hacerlo nuevamente, manteniendo su programa en un bucle inestable.

if(MCUSR & _BV(WDRF)){            // If a reset was caused by the Watchdog Timer...
    MCUSR &= ~_BV(WDRF);                 // Clear the WDT reset flag
    WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
    WDTCSR = 0x00;                      // Disable the WDT
}

Configuración de WDT

Luego, una vez que haya configurado el resto del chip, vuelva a hacer el WDT. La configuración de WDT requiere una "secuencia programada", pero es muy fácil de hacer ...

// Set up Watch Dog Timer for Inactivity
WDTCSR |= (_BV(WDCE) | _BV(WDE));   // Enable the WD Change Bit
WDTCSR =   _BV(WDIE) |              // Enable WDT Interrupt
           _BV(WDP2) | _BV(WDP1);   // Set Timeout to ~1 seconds

Por supuesto, sus interrupciones deben estar deshabilitadas durante este código. ¡Asegúrate de volver a habilitarlos después!

cli();    // Disable the Interrupts
sei();    // Enable the Interrupts

Rutina de servicio de interrupción de WDT Lo siguiente de lo que preocuparse es el manejo del ISR de WDT. Esto se hace como tal:

ISR(WDT_vect)
{
  sleep_disable();          // Disable Sleep on Wakeup
  // Your code goes here...
  // Whatever needs to happen every 1 second
  sleep_enable();           // Enable Sleep Mode
}

MCU Sleep

En lugar de poner la MCU en reposo dentro del ISR de WDT, recomiendo simplemente habilitar el modo de suspensión al final de la ISR, luego hacer que el programa PRINCIPAL ponga a la MCU en suspensión. De esa manera, el programa en realidad está dejando el ISR antes de irse a dormir, y se activará y regresará directamente al ISR de WDT.

// Enable Sleep Mode for Power Down
set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // Set Sleep Mode: Power Down
sleep_enable();                     // Enable Sleep Mode  
sei();                              // Enable Interrupts 

/****************************
 *  Enter Main Program Loop  *
 ****************************/
 for(;;)
 {
   if (MCUCR & _BV(SE)){    // If Sleep is Enabled...
     cli();                 // Disable Interrupts
     sleep_bod_disable();   // Disable BOD
     sei();                 // Enable Interrupts
     sleep_cpu();           // Go to Sleep

 /****************************
  *   Sleep Until WDT Times Out  
  *   -> Go to WDT ISR   
  ****************************/

   }
 }
    
respondido por el Kurt E. Clothier
1

Según la ficha técnica es posible. Incluso puedes habilitar tanto una interrupción como el reinicio. Si ambos están habilitados, el primer tiempo de espera de vigilancia desencadenará la interrupción, lo que hace que el bit de Habilitación de interrupción se desactive (interrupción inhabilitada). El siguiente tiempo de espera reiniciará tu CPU. Si habilita la Interrupción directamente después de que se ejecutó, el siguiente tiempo de espera (nuevamente) activará solo una interrupción.

También puede habilitar la interrupción y no habilitar el restablecimiento en absoluto. Deberá establecer el bit WDIE cada vez que se active la interrupción.

    
respondido por el Tom L.
1

Esto es mucho más fácil que lo sugerido anteriormente y en otros lugares.

Mientras el fusible WDTON no esté programado (no está programado por defecto), solo necesita ...

  1. Establezca el bit de habilitación de interrupción de vigilancia y el tiempo de espera en el registro de control de vigilancia.
  2. Habilita las interrupciones.

Aquí hay un ejemplo de código que ejecutará un ISR una vez por segundo ...

ISR(WDT_vect) {
   // Any code here will get called once per second
}

void main(void) {
   WDTCR =  _BV(WDIE) | _BV( WDP2) | _BV( WDP1);    // Enable WDT interrupt, set timeout to 1 second
   sei();                                           // Turn on global interrupts
   // Put any code you want after here.
   // You can also go into deep sleep here and as long as 
   // global interrupts are eneabled, you will get woken up every second. 
   while (1);
}

Eso es realmente. Ya que nunca habilitamos el reinicio del watchdog, nunca tenemos que perder el tiempo con las secuencias cronometradas para deshabilitarlo. El indicador de interrupción de vigilancia se borra automáticamente cuando se llama al ISR.

Si desea un período diferente a cada 1 segundo, puede usar estos valores aquí para establecer los bits apropiados en WDTCR ...

    
respondido por el bigjosh

Lea otras preguntas en las etiquetas

Comentarios Recientes

en su iPhone o Windows para usar el modo Avión de Facebook, el modo Photo Rescue, para comunicarse con tabletas remotas Samsung Galaxy conectadas a la computadora (se venden por separado). Junto con el modo OTG Facebook Airplane con su Android Control Cam remota para wifi en televisores inteligentes para conectarse con otros dispositivos AVR en su teléfono. También puede conectar wi-fi a su computadora usando el modo OnLink / PureView en el módulo bluetooth 10.1.2.3. Para versiones anteriores del sistema operativo,... Lees verder