Arduino Atmega328 modo de suspensión con temporizador interno de interrupción

0

Estoy tratando de reducir el consumo de corriente de mi Atmega328 -Arduino- usando los modos de suspensión. En mi código, quiero activar cada 10ms , leer el valor de ADC y volver al modo de suspensión nuevamente.

Hay algunas instrucciones útiles ( aquí y aquí ), pero la mayoría de ellas están basadas en Watch Dog Timre o interrupción externa de los pines.

Aquí está el código simplificado mío, pero no funciona (no va a la función del controlador de interrupciones):

En la configuración, me ocupo del temporizador y su controlador:

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

   Timer1.initialize(10000);  //10ms sampling rate
   Timer1.attachInterrupt(ReadMyADC,10000);

   power_spi_disable(); // SPI
   power_timer0_disable();// Timer 0
}

El resto del código que incluye loop() es el siguiente:

void ReadMyADC(){
    sleep_disable();
    PRR = PRR & 0b00000000;
    Serial.print("sth");
    power_adc_enable(); // ebable ADC converter
    //Read ADC
    power_adc_disable();
}
void loop() {
    // ----------------low power ---------------
    PRR = PRR | 0b00100000;
    sleep_enable();
    set_sleep_mode(SLEEP_MODE_STANDBY);
    EIMSK |= _BV(INT0);            //enable INT0
    ADCSRA = 0;                    //disable ADC
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    sleep_disable();               //wake up here
    Serial.print("Wake\n");
}

Aparentemente, el temporizador 1 no puede salir de la CPU desde el modo de suspensión. ¿Tiene alguna idea de cómo gestionar eso o dónde está el problema?

    
pregunta Farzad

2 respuestas

2

Los modos de suspensión más profundos apagan más el chip para reducir el consumo de corriente.

Los modos más profundos apagan los contadores del temporizador, ya que consumen bastante corriente.

En su lugar, use el temporizador de vigilancia en el modo de interrupción, o para un máximo de apagado, use un decaimiento RC externo controlado por un micro para interrumpir el micro después de un breve período.

    
respondido por el Trevor_G
1

Sleep_Mode_Standby no permite que se ejecute Timer1 ya que el dominio del reloj está desactivado. Solo puedes usar Timer1 en Sleep_Mode_Idle, tu código debería funcionar si usas ese modo.

Use el WDT ya que tiene su propio reloj a 128 kHz que está habilitado cuando está encendido.

Código como este puede funcionar para usted:

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

void setup () { }

const byte LED = 13;   //Nano LED

void flashLED ()
{
 pinMode (LED, OUTPUT);
  // Flash the LED 
 for (byte i = 0; i < 10; i++)
    {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
    }
 } 

// Watchdog ISR routine
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
   // Return from ISR
}  


void loop () 
{

  flashLED ();

  // disable ADC
  ADCSRA = 0;  

  // clear all MCUSR flags
  MCUSR = 0;     
  // allow changes, disable reset pin
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0);    // set WDIE, and 2 second WDT delay
  wdt_reset();  // Start the timer

  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  noInterrupts ();           // timed sequence follows
  sleep_enable();

  // turn off brown-out detector
  MCUCR = bit (BODS) | bit (BODSE);
  MCUCR = bit (BODS); 
  interrupts ();
  sleep_cpu (); 

   // Sleep here in powerdown state
  // Return here after WDT return from ISR 

  // disable sleep
  sleep_disable();

  // Do your thing here

  }
    
respondido por el Jack Creasey

Lea otras preguntas en las etiquetas