domanda interrupt + sleep mode + evetuali ethernet interrupt

buon pomeriggio ragazzi,
sto provando a far consumare di meno al mio arduino uno, per lo meno a provare a fargli consumare di meno.
guardo i vari metodi, trovo le sleep mode e mi interessa subito la sleep_pwr_mod quella orientato al massimo risparmio, quindi mi dirigo subito verso i watchdog.

studio un po’ di programmi e trovo in quello di leo72 un ottimo punto di partenza.

link programma

fin qui tutto ok.

io voglio far registrare ogni tot minuti/secondi dati su un file nella mia SD e se arduino (uno) non sta registrando lo metto in sleep mode.

però ho anche la possibilità di vedere questi dati via web.

ho pensato di mettere in ascolto arduino su ethernet e dirgli che quando riceve un interrupt da ethernet si deve svegliare e fare le cose che gli dico io (idea molto bella ma…)

ho provato i vari attachinterrupt ma niente non ci sono riuscito…

allora ho provato ad inserire altre modifiche nel codice di leo ricordandomi che arduino si sveglia ogni secondo per aggiornare il flag.

allora per prima cosa posto il codice funzionante (senza ultime modifica riguardanti ethernet)

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

const byte LED7 = 7;
const byte LED6 = 6;

byte ledStatus = 1;

volatile unsigned int counter = 0;

volatile byte flag = 0;

File mio;

int i = 1;

void setup() {

                       if (!SD.begin(4)) 
                      {
                          return; 
                      }

              
              MCUSR = 0; //resetta il registro di stato della MCU
              
              wdt_disable(); //disattiva il watchdog
   
              pinMode(LED7, OUTPUT); //pin 13 in OUTPUT

              pinMode(LED6, OUTPUT);

              digitalWrite(LED7, 0); //spento
   
              digitalWrite(LED6, ledStatus); //stato iniziale acceso
   
               setWdt(); //imposta il watchdog
   
                //imposta lo sleep
                set_sleep_mode(SLEEP_MODE_PWR_DOWN); //modalità di sleep - POWER DOWN


            
}

void loop() {
             power_adc_disable();
              power_timer0_disable();
               power_timer1_disable();
              power_timer2_disable();
               power_twi_disable();
                power_usart0_disable();

               // power_all_disable();
   
               sleep_mode(); //cpu a nanna - corrisponde a sleep_enable+sleep_cpu+sleep_disable
                
               power_all_enable();
   
                if (flag) 
                {
                    wdt_disable();
                    counter = 0;
                    flag = 0;
      
                    //fai qui quello che devi fare

                    mio = SD.open("digimon.txt", FILE_WRITE);

                    mio.println(i);

                    i++;

                    mio.close();
                      
                    ledStatus ^= 1; //cambio lo stato al led
                    
                    
                    digitalWrite(LED6, ledStatus);
      
                    setWdt(); //reimposta il watchdog
                  }
                  
}

void setWdt() {

  
   SREG &= ~(1<<SREG_I); //disattiva tutti gli interrupt
   //imposta il registro del watchdog
   WDTCSR |= ((1<<WDCE) | (1<<WDE));
   //imposta la modalità "interrupt" ed il timeout ad 1 secondo
   WDTCSR = ((1<<WDIE)| (1<<WDP2) | (1<<WDP1)); 
   SREG |= (1<<SREG_I); //riattiviamo gli interrupt globali
}


//funzione per settare quanto tempo dorme
ISR(WDT_vect) 
{
  
  
    if (++counter >= 8) 
   { //impostare qui il numero di timeout (secondi)
      flag = 1;
   } 

   
}

ora metto le modifiche che ho provato ad aggiungere ma con scarsi risultati(però non so quanto mi faranno risparmiare, non ci sono le varie impostazioni per l’ethernet ma nello sketch sono presenti in setup())…

ISR(WDT_vect) 
{
  
  EthernetClient client = server.available();
  if(client)
  {
    while(client.connected())
    {
        accendi();
    }
    
    
      spegni();
    
    
    
    
  }
  
    if (++counter >= 1) 
   { //impostare qui il numero di timeout (secondi)
      flag = 1;
   } 

   
}

la luce del led 7 mi si accende quando io mi connetto ad arduino (uno) tramite browser ma non si spegne più, e ovviamente non ritorno in loop(non glielo dico da nessuna parte)…

chiedo cortesemente a voi se sapete, o indicarmi, qualche metodo per andare a far svegliare arduino da sleep mode da ethernet quando io mi voglio connettere a lui tramite html.

(io avevo pensato di usare 2 arduino collegati tramite i2c, ma vorrei vedere se è possibile con solo un arduino)

se non sono stato chiaro ditelo pure che rispiego il mio intento/dubbio.

buona serata.

La shield non presenta interrupt, devi essere tu ad intervalli regolari a chiedere se vi sono tentativi di connessione, e questo ti porta alla scioccante verità il tempo di sonno deve essere estremamente limitato, sinceramente con un dT di 1s credo tu possa rischiare di non rispondere in tempo ad una connessione, non esiste uno standard, un browser può anche fare 40 tentativi di connessione ad un server prima di rinunciare oppure provare una singola volta.

Ad ogni modo nella ISR non puoi includere tutte quelle operazioni. In linea generale nel loop esegui la misura, la salvi e verifichi una connessione in entrata, eventualmente la gestisci e poi entri in sleep per xms sfruttando il watchdog. Al risveglio tutto da capo, identifica il tempo di sonno migliore per il tuo progetto.

buongiorno ragazzi,
grazie RobertoBochet avevo pensato anche io che la ISR era un po' troppo pesante con le modifiche apportate da me...

il mio problema è che non so se riesco a pensare ad un tempo di sleep ottimale perchè la pagina html sul mio server web di arduino (uno) è sempre disponibile, cioè non do all'utente un tempo (o un intervallo di tempo) prestabilito per la connessione, quindi posso a qualunque ora connettermi per quello che avevo pensato ad un interrupt da parte di ethernet che come tu hai ben detto non è possibile.

In linea generale nel loop esegui la misura, la salvi e verifichi una connessione in entrata, eventualmente la gestisci e poi entri in sleep per xms sfruttando il watchdog.

però io voglio registrare la misura ogni tot secondi, ad esempio 10 sec, quindi, secondo me come dici tu che nel loop misuro, salvo e poi gestisco andrei a gestire la connessione ogni 10 sec.
non riesco a trovare un' idea di come gestire la connessione nel loop.

chiedo se qualcuno ha un' idea o qualche consiglio.

proverò ancora nel mio intento prendendo spunto dalle parole di RobertoBochet.

rimango aperto per altre domande e/o suggerimenti

buona giornata.

ribuongiorno ragazzi,

mi sono reso conto nel lasso di tempo che è trascorso dal mio ultimo post che in questo ultimo ho scritto un po’ di boiate :slight_smile:

sui suggerimenti di roberto ho modificato il mio sketch solamente nel loop.

posto solamente le modifiche dello sketch precendente…

void loop() {

               power_all_disable();
   
               sleep_mode(); //cpu a nanna - corrisponde a sleep_enable+sleep_cpu+sleep_disable
                
               power_all_enable();

                EthernetClient client = server.available();
                
               if(client)
               {

                wdt_disable();

                accendi();
                    
                    
                  boolean currentLineIsBlank = true;
                  while (client.connected()) {
                                              //if (client.available()) {
                                                                        char c = client.read();
        
        
                                                                        if (c == '\n' && currentLineIsBlank) {
                                                                                                                // send a standard http response header
                                                                                                                client.println(F("HTTP/1.1 200 OK"));
                                                                                                                client.println(F("Content-Type: text/html"));
                                                                                                                client.println(F("Connection: close"));  // the connection will be closed after completion of the response
                                                                                                                client.println(F("Refresh: 5"));  // refresh the page automatically every 5 sec
                                                                                                                client.println();
                                                                                                                client.println(F("<!DOCTYPE HTML>"));
                                                                                                                client.println(F("<html>"));
                                                                          
                                                                                                                // output the value of each analog input pin
                                                                                                                for (int analogChannel = 0; analogChannel < 6; analogChannel++) 
                                                                                                                {
                                                                                                                          int sensorReading = analogRead(analogChannel);
                                                                                                                          client.print(F("analog input "));
                                                                                                                          client.print(analogChannel);
                                                                                                                          client.print(F(" is "));
                                                                                                                          client.print(sensorReading);
                                                                                                                          client.println(F("
"));
                                                                                                                }
                                                                                                                
                                                                                                                client.println(F("</html>"));
                                                                                                                break;
                                                                                                                }
                                                                          if (c == '\n') 
                                                                          {
                                                                              // you're starting a new line
                                                                              currentLineIsBlank = true;
                                                                          }
                                                                          else if (c != '\r') 
                                                                          {
                                                                                    // you've gotten a character on the current line
                                                                                    currentLineIsBlank = false;
                                                                          }
                                                                       // }
                                              }
                                                                          
                                                                          
                    // give the web browser time to receive the data
                    delay(1);
                    // close the connection:
                    client.stop();


                    spegni();

                    setWdt();


                  
                   }
               

               

                
                if (flag) 
                {

                    // fa queste istruzioni ogni n secondi impostati nel counter
                    
                    wdt_disable();
                    counter = 0;
                    flag = 0;

                    spegni();
      
                    //fai qui quello che devi fare

                    mio = SD.open("pokemon.txt", FILE_WRITE);

                    mio.println(i);

                    i++;

                    mio.close();
                      
                    ledStatus ^= 1; //cambio lo stato al led
                    
                    
                    digitalWrite(LED6, ledStatus);

                    
      
                    setWdt(); //reimposta il watchdog
                    
                  }
                  
}

void setWdt() 
{

  
   SREG &= ~(1<<SREG_I); //disattiva tutti gli interrupt
   //imposta il registro del watchdog
   WDTCSR |= ((1<<WDCE) | (1<<WDE));
   //imposta la modalità "interrupt" ed il timeout ad 1 secondo
   WDTCSR = ((1<<WDIE)| (1<<WDP2) | (1<<WDP1)); 
   SREG |= (1<<SREG_I); //riattiviamo gli interrupt globali
}


//funzione per settare quanto tempo dorme
ISR(WDT_vect) 
{
  
    if (++counter >= 8) 
   { //impostare qui il numero di timeout (secondi)
      flag = 1;
   } 

   
}

chiedo cortesemente se secondo voi le modifiche sono abbastanza ragionevoli (d’altronde è quello che devo fare :slight_smile: ) , e chiedo anche se così a naso o a occhio risparmierei davvero qualcosa implementando la sleep mode o posso fare anche a meno, certo questo dovrò andarlo a verificare io misurando i consumi del mio arduino (chiedo solo perchè secondo me non avrei poi dei vantaggi nei consumi, ma è solo un mio parere )

buona giornata

Ok cosi gia ci siamo di piu, apporterei qualche modifica logica.
Primo leggo la misura e la salvo.
Secondo verifico che vi siano connessioni in ingresso.
Terzo metto a nanna il dispositivo.
Come fai tu la lettura potrebbe non essere disponibile quando viene richiesta la pagina, ma questo accade solo nel primo ciclo.
Altra cosa, interagisti troppe volte con le direttive per la sospensione.
Appena esci dalla modalità sleep disattivi la stessa, disattivi il wdt, esegui le operazioni sopra indicate, attivi il WDT e metti a dormire la scheda.

Non ha molto senso disattivare il WDT 2 volte in punti diversi. Per il resto non sembra presentare particolari problemi. Ricordati che si Arduino va il sleep mode ma la ethernet continua a lavorare, quindi in linea torica non perdi mai connessioni in ingresso, al massimo non rispondi in tempo.

buongiorno ragazzi,
scusate il ritardo ma i weekend con la famiglia sono impegnativi :slight_smile:

@RobertoBochet, grazie mille per le dritte che mi hai dato, proverò con ancora un po' di prove per migliorare lo sketch sulle tracce di quello che mi hai detto.

grazie mille

buona giornata