Arduino sleep

Arduinosleep

Se si deve fare solo qualche operazione ogni tanto è conveniente mettere Arduino a dormire (sleep mode) per tutto il resto del tempo, in modo da consumare solamente qualche microampere o anche meno, molto utile per esempio con alimentazione solare o batterie o condensatori, ecc…

Durante lo sleep Arduino però non potrà fare nulla, ci sono diversi modi di sleep, i più importanti sono con il timer interno e con un evento esterno.

Nel primo caso Arduino o meglio l’Atmega328p eseguirà qualche operazione e poi andrà in sleep, dopo un po’ il timer interno lo sveglierà, rieseguirà qualche operazione e poi di nuovo in sleep, poi si sveglierà e così via.

Il secondo caso è identico solo che sarà un evento esterno a svegliare l’Atmega328p, per esempio un pulsante, quindi farà qualche operazione e poi in sleep, dopo si sveglierà col pulsante, poi farà qualche operazione, poi in sleep, poi si sveglierà col pulsante e così via.

Ci sono diversi modi e librerie per realizzare lo sleep, il più semplice e veloce fa uso della libreria LowPower scaricabile da qua, dopo nell’ide, su sketch include library, Add .ZIP Library, per aggiungerla, ecco il codice:

#include <LowPower.h>
  int i=0;
void setup()                                         //esegue una sola volta
{
}
void loop()                                          //esegue ciclicamente
{
  for(i=0;i<3;i++)                                   //esegue 3 volte
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);    //lo sleep di 8s
                                                     //inserire qui il codice
}
  

Come si vede, il codice è semplicissimo, in sostanza il tempo più lungo del watchdogtimer è di soli 8 secondi, quindi con un ciclo for si fa ripetere questo tempo quante volte si vuole, in questo esempio ci saranno 24 secondi di sleep (3 volte 8s), low power down è, fra le varie modalità di sleep, quella con il massimo risparmio energetico.

Dove c’è inserire codice, bisgona inserire il codice del programma, da eseguire da sveglio, per esempio la lettura di un sensore, la trasmissione di un dato, l’acensione di un led o altro.

In questa modalità il consumo a riposo del microcontrollore è di circa una ventina di µA a 5V, che non è male.

Arduinosleep1

L’altra modalità di sleep è quella con un evento esterno cioè un interrupt al pin2 (int0), per esempio quando va a low tramite un pulsante.

Anche in questo caso si usa la libreria LowPower, ed ecco il codice:

#include <LowPower.h>
const int wakeUpPin = 2;                                  //dichiaro un intero wakeUpPin al pin2
void setup()                                              //esegue una sola volta
{
  pinMode(wakeUpPin, INPUT);                              //pin2 come input
}
void loop()                                               //esegue ciclicamente
{
    attachInterrupt(0, wakeUp, LOW);                      //abilita interrupt int0 (pin2), funzione wakeup a segnale LOW
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);  //sleep tempo indefinito
    detachInterrupt(0);                                   //disabilita interrupt 
                                                          //inserire qui il codice
}
  

wakeUpPin è il pin 2 cioè riceverà il segnale per svegliare il microcontrollore, la riga nel void setup verrà eseguita una sola volta ed imposterà il pin2 come input, attachInterrupt attiverà l’interrupt al pin int0 (nell’Arduino Uno è il pin2) quando ci sarà un segnale LOW (si può cambiare in HIGH, CHANGE, RISING, FALLING), low power down è la modalià a massimo risparmio, sleep forever è lo sleep, detachInterrupt disabilita l’interrupt per non andare in conflitto con il programma nella riga successiva, in inserire codice bisogna mettere il programma da eseguire da sveglio.

In questo caso il consumo è più elevato, circa 600µA a 5V.

Arduinosleep2

Un altro codice che fa uso della libreria JeeLib scaricabile da qua sempre con il timer, che consente di consumare circa 6µA è il seguente:

#include <JeeLib.h>
ISR(WDT_vect) { Sleepy::watchdogEvent(); } // Setup watchdog
void setup()
{
}
void loop()
{
                                            //inserire qui il codice
 Sleepy::loseSomeTime(60000);               //sleep di un minuto massimo 
}

LoseSomeTime si può usare al posto di delay, e funziona con tempi tra 16 e 60000 (ms), oltre bisogna usare un ciclo for, come già visto prima, la particolarità è che anche durante l’accensione di un led, il consumo si mantiene basso.

Arduinosleep4

Un altro codice, sempre con interrupt esterno, poco versatile ma che permette di scendere sotto il microampere, è il seguente:


  #include <avr/sleep.h>
byte i, adcsra, mcucr1, mcucr2;
void setup()
{
    for (i=0; i<20; i++)
    {
      pinMode(i, INPUT);          //tutti i pin input
      digitalWrite(i, HIGH);      //tutti high per ridurre il consumo
    }
    EICRA = 0x00;                 //pin2 richiesta interrupt a livello low
}

void loop()
{ 
    sleep_enable();                           //abilita sleep
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);      //modalità sleep massima
    adcsra = ADCSRA;                          //memorizza ADC e Stato Registro A
    ADCSRA = 0;                               //disabilita ADC
    cli();                                    //disabilita interrupts
    EIMSK |= _BV(INT0);                       //abilita INT0
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //spegne il brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;                
    MCUCR = mcucr2;
    sei();                         //abilita interrupts per potersi svegliare
    sleep_cpu();                   //sleep qua
    sleep_disable();               //sveglia quì
    ADCSRA = adcsra;               //ripristina ADCSRA
                                   //inserire qui il codice          
}
ISR(INT0_vect)
{
    EIMSK &= ~_BV(INT0);           //interrupt int0 per svegliarsi
}
  

Il difetto è che funziona solo con segnale LOW al pin2 e bisogna ricordarsi di mettere in outuput i pin da usare prima del codice.

Arduinosleep3 Arduinosleep5

Pur troppo il mio multimetro non è così sensibile da leggere sotto il microampere, ho dovuto usarne un’altro, sicuramente con queste correnti in gioco bisognerà tenere in considerazione anche l’autoscarica della batteria da usare, la disattivazione dei sensori e quant’altro per risparmiare corrente, un saluto e alla prossima.

Precedente Programmare Arduino su breadboard con Uno Successivo Programmare Attiny85 con Arduino Uno

2 thoughts on “Arduino sleep

  1. Francesco il said:

    salve, volevo chiedere se era possibile gestire il wakeup da un sms. Mi spiego meglio:
    avrei la necessità di far partire il programma all’interno del loop solo in seguito all’invio da parte di un sms. é possibile?
    Grazie, saluti.

    • Electrogreen il said:

      Salve, si è possibile, una volta in sleep, basta mandare un segnale temporaneo basso al pin D2 (int0) del Atmega328p e questo si sveglierà ed eseguirà le righe successive.
      L’impulso puoi mandarlo da un modulo gsm o dalla cassa o dalla vibrazione di un vecchio telefono cellulare.

I commenti sono chiusi.