Calcolare consumo Arduino

Salve a tutti! :smiley:

Allora, vi spiego la mia situazione:

Ho monitorato i consumi di arduino in mA durante le fasi di accensione e inizializzazione (Setup) e durante il loop, i risultati sono i seguenti:

1.) Senza limitazioni di consumo (nessuno sleep) all'avvio ho: 25mA per l'inizializzazione e circa 39/40mA durante il loop
2.) Inserendo la funzione sleep periodica impostata a 8 secondi, ho un consumo di 25mA per il setup (normalissimo) e un consumo nel loop in Standby di circa 8/9mA (tutto normale...tenendo conto che questi mA sono consumati dal led PWR e dallo stabilizzatore...). Una volta "Svegliato" l'arduino, torno a consumare circa 25mA.

Adesso mi chiedo: come posso calcolare l'ipotetica durata della batteria sapendo che nella fase di setup consumo 25mA e che durante il loop ho un'alternanza di consumo che va da 8mA e 25mA?

Ecco i dati:

Consumo iniziale 25mA
Consumo in "loop attivo": 25mA
Consumo in Sleep: 9mA
mA batteria: 250.

...il mio problema è: come calcolo la durata della batteria tenendo conto del ciclo iniziale di Setup e del Loop, a sua volta alternato di 8 secondi?

Grazie.

Il consumo lo calcoli facendo semplicemente la media del consumo e poi dividendo la capacità della batteria per il valore che hai ottenuto.
Ovviamente sulla media devi tener conto del fatto che il consumo del setup incide solo all'accensione del circuito mentre poi devi calcolare il tutto sulle letture che hai fatto con il loop attivo e con il loop in stand-by.
Visto che hai un ciclo idle di 8 secondi, il tempo attivo se è limitato a qualche millisecondo puoi anche trascurarlo o farlo incidere in minima percentuale.

Se vuoi abbassare ulteriormente i consumi, valuta l'idea di mettere in standalone il tuo circuito.

Si, ok, mettiamo di avere questo loop:

 LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  if (digitalRead(13) == HIGH)
  {
    digitalWrite(13, LOW);    
    analogWrite(Led_1, 0);
    analogWrite(Led_2, 0);
  }
  else
  {
    digitalWrite(13, HIGH);
    analogWrite(Led_1, 255);
    analogWrite(Led_2, 255);
  }

La libreria mi manda in sleep Arduino per 8 secondi e poi me lo sveglia per altri 8 secondi, bene, come calcolo la durata avendo quei dati?

Si, ci sto seriamente pensando alla soluzione di passare in standalone...(magari usando un attiny85)...che tu sappia le librerie:
http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
sono compatibili con l' Attiny85?

Se hai 8s in idle ed 8s attivo, il consumo è dato da ((25mA8s)+(8mA8s))/16s=16 mA di media.
Quella libreria è stata scritta per l'Atmega328, per lo meno vedo dalle parti in cui manipola i timer. Quindi così com'è non la puoi usare su un Tiny.

Però non devi obbligatoriamente dipendere da librerie esterne per pilotare i registri di risparmio energetico.
Puoi manipolare direttamente i registri del microcontrollore (leggi il datasheet del micro che intendi utilizzare) oppure usare la libreria Avr power.h con la quale puoi disattivare le periferiche che non intendi utilizzare:
http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html

Si, ma non saprei come mettere in sleep l'attiny85 con le stesse modalità usate per l'arduino...
sapresti darmi una mano?

fardox:
Si, ma non saprei come mettere in sleep l'attiny85 con le stesse modalità usate per l'arduino...
sapresti darmi una mano?

Usando la libreria Avr sleep.h.
Qui c'è un po' di teoria:
http://playground.arduino.cc/Learning/arduinoSleepCode

Ti passo questo sketch che scrissi tempo fa per fare dei test sull'Attiny85 quando con Menniti stavano analizzando la questione della sua barriera infrarossi. Usa anche la libreria PinChangeInterrupt (che puoi scaricare dallo stesso sito da cui hai prelevato il core Tiny):

#include <avr/sleep.h>  // libreria standard (avrlib) per lo sleep
#include <PinChangeInterruptSimple.h> // questa libreria permette di usare un qualsiasi pin come interrupt
/* Sleep test */
#define Sveglia 0    // pin 7 dell'attiny corrispondente a INT0
#define LED     3    // pin 3 dell'attiny85

void sbadiglio()        // risveglio dallo sleep
{
  // inserire eventuali azioni legate all'interrupt
}

void setup()
{
  pinMode(Sveglia, INPUT);
  //digitalWrite(Sveglia, HIGH);
  pinMode(LED, OUTPUT);
  
  //digitalWrite(Sveglia, 1);              // pull up attiva sul pin interrupt, ma conviene usare una 180K esterna
  attachPcInterrupt(Sveglia, sbadiglio, LOW);    // interrupt 0 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // setta registri per il modo sleep
  sleep_enable();                        // abilita la sleep all'uso
}

void A_nanna()                      // funzione attivazione sleep
{
    attachPcInterrupt(Sveglia, sbadiglio, CHANGE); // riattiva l'interrupt
    ADCSRA &= ~(1 << ADEN);
    sleep_mode();                          // mette in stato di sleep
    sleep_disable();      // disattiva la modalità sleep e riporta il micro a piena operatività
    detachPcInterrupt(Sveglia);  // disattiva l'interrupt
}
void loop()
{
  for(byte i=0;i<4;i++)
   {
    digitalWrite(LED, HIGH);
    delay(200);
    digitalWrite(LED, LOW);
    delay(200);
   }
  A_nanna();               // mette il micro in sleep
}

Mette in sleep il micro e lo risveglia con un PCINT su un pin. E' tutto commentato.

Ma: set_sleep_mode(SLEEP_MODE_PWR_DOWN); non necessita di un interrupt esterno per il Wake up?

Se io volessi usare la temporizzazione interna(come facevo nello sketch precedente) come devo fare?

Thanks! :smiley:

Sai come funziona almeno lo sketch che hai usato? Hai letto la libreria LowPower?
Immagino di no :wink:

Funziona attivando il watchdog, che è un circuito interno alimentato separatamente dal clock principale. Il clock principale negli sleep "profondi" viene disattivato quindi tutto si ferma. Senza un qualcosa che risvegli il micro, il micro è in ibernazione. Lo sketch ti ho postato io usa appunto un interrupt esterno. La LowPower usa invece il watchdog per resettare il microcontrollore.
In pratica, ogni 8 secondi resetta l'Atmega e fa ripartire tutto lo sketch. Ecco perché leggi sempre anche il consumo generato dal setup(), perché ogni 8 secondi tutto il codice viene rieseguito.

Quindi, non volendo usare il timer Watchdog, ma il timer da 16bit (timer1) come dovrei adattare il tuo sketch?

fardox:
Quindi, non volendo usare il timer Watchdog, ma il timer da 16bit (timer1) come dovrei adattare il tuo sketch?

Puoi farlo ma solo in modalità risparmio energetico "IDLE", l'unica che non disattiva i timer.
A questo punto basta attaccare un interrupt all'overflow del timer e sei a posto.
Tieni però presente che in modalità IDLE si spenge solo la CPU, quindi il risparmio è minimo.

Datasheet Attiny85, cap. 7 pag. 35 e seguenti.

Provo a spiegare quello che voglio fare in modo da cercare di risolvere il problema:

Allora, l'attiny una volta inizializzato, deve leggere periodicamente 4/8 secondi un sensore, se viene superata una certa soglia allora l'attiny si deve svegliare e segnalarlo attraverso un led per un certo tot, dopo di chè deve tornare in sleep e prepararsi per un nuovo ciclo.

come penseresti di impostare il tutto?

il problema è che il tutto è gestito da una batteria al litio CR2032, da 250mA circa.

fardox:
Provo a spiegare quello che voglio fare in modo da cercare di risolvere il problema:

Allora, l'attiny una volta inizializzato, deve leggere periodicamente 4/8 secondi un sensore, se viene superata una certa soglia allora l'attiny si deve svegliare e segnalarlo attraverso un led per un certo tot, dopo di chè deve tornare in sleep e prepararsi per un nuovo ciclo.

come penseresti di impostare il tutto?

il problema è che il tutto è gestito da una batteria al litio CR2032, da 250mA circa.

Includi la libreria wdt.h per gestire il watchdog, poi includi la lib sleep.h per gestire gli sleep.
A questo punto scrivi una roba del genere:

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

const byte mioPin = xx;

void setup() {
    MCUSR = 0;
    wdt_disable();
    pinMode(mioPin, INPUT);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // setta registri per il modo sleep
    sleep_enable();                        // abilita la sleep all'uso
}

void loop() {
    if (digitalRead(mioPin) == STATO_CHE_VUOI_CONTROLLARE) {
        //.... codice da eseguire...
    }
    wdt_enable(WDTO_8S);
    power_adc_disable();
    power_timer0_disable();
    power_timer1_disable();
    sleep_mode();
    while (1); //inutile, tanto non ci arriverà mai, serve solo al compilatore
}

In questo modo lo risvegli col watchdog.
Ed ora studiati queste pagine perché altrimenti non ti aiuto più :stuck_out_tongue:
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html
http://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html

leo72:
Sai come funziona almeno lo sketch che hai usato? Hai letto la libreria LowPower?
Immagino di no :wink:

Funziona attivando il watchdog, che è un circuito interno alimentato separatamente dal clock principale. Il clock principale negli sleep "profondi" viene disattivato quindi tutto si ferma. Senza un qualcosa che risvegli il micro, il micro è in ibernazione. Lo sketch ti ho postato io usa appunto un interrupt esterno. La LowPower usa invece il watchdog per resettare il microcontrollore.
In pratica, ogni 8 secondi resetta l'Atmega e fa ripartire tutto lo sketch. Ecco perché leggi sempre anche il consumo generato dal setup(), perché ogni 8 secondi tutto il codice viene rieseguito.

Scusami Leo, ma nel datasheet leggo che è possibile utilizzare il timer watchdog per generare un interrupt e non un reset!

fardox:

leo72:
Sai come funziona almeno lo sketch che hai usato? Hai letto la libreria LowPower?
Immagino di no :wink:

Funziona attivando il watchdog, che è un circuito interno alimentato separatamente dal clock principale. Il clock principale negli sleep "profondi" viene disattivato quindi tutto si ferma. Senza un qualcosa che risvegli il micro, il micro è in ibernazione. Lo sketch ti ho postato io usa appunto un interrupt esterno. La LowPower usa invece il watchdog per resettare il microcontrollore.
In pratica, ogni 8 secondi resetta l'Atmega e fa ripartire tutto lo sketch. Ecco perché leggi sempre anche il consumo generato dal setup(), perché ogni 8 secondi tutto il codice viene rieseguito.

Scusami Leo, ma nel datasheet leggo che è possibile utilizzare il timer watchdog per generare un interrupt e non un reset!

Certamente. E' la tecnica che ho usato sul leOS2.
Basta impostare nel registro WDTCR il bit WDIE su 1, che il watchdog genera un interrupt e non un reset.
Devi però ogni volta reimpostare il bit altrimenti la volta seguente il watchdog resetta comunque il microcontrollore.
Se vuoi studiarti questa cosa analizza il codice del leOS2.

Ok, credo di aver risolto per quanto riguarda il risparmio energetico, adesso mi studio i manuali e i datasheet e vedrò :smiley:

quindi ricapitolando per la durata della batteria, posso escludere la fase di setup nel consumo globale? (tanto dura pochissimo...)

e fare in questo modo: mAmedi= ((ConsumoAttivoTattivo)+(ConsumoPassivoTpassivo))
-------------------------------------------------------------- = mA medi
Tattivo+Tpassivo

Durata totale in ore = mABatteria
--------------- = [ore]
mAmedi

Confermi?

Allora, la questione è: per impostare il watchdog in modalità "interrupt" e non "reset" devi lavorare di registri, non c'è una libreria già pronta che te lo fa.
Se hai dato un'occhiata al leOS2 ed al meccanismo che uso, avrai notato che non è così semplice e va anche usata una ISR per poter pilotare il watchdog. Se non te la senti, ti consiglio di seguire la strada più semplice, quella di utilizzare il programma che ti ho abbozzato.

Per il consumo, la formula è giusta.