sleep mode

ciao a tutti, ho un atmega che va il sleep per 8 secondi con il wdc valuta una variabile , ed valuta se ritornare il sleep o restate attivo
si puo svegliare prima degli 8 secondi se ho un cambio di stato,del pin 2 o del 3 degli interrup , credo sia il suo nome,anche se e' in modalita sleep o devo aspettaregli 8 secondi ed eventualmente leggere qualcosa?

Certo che può, sul pin 2 hai l'INT0 quindi anch se in sleep viene notificato. Questa pagina sviscera bene i concetti e se non vado errato è un utente del forum internazionale "parecchio" esperto :slight_smile:

grazie della tua risposta, leggendo un po sono arrivato a una cosa cosi
sicuramente non sara' perfetto,ma qualcosa magari ho capito,
il wdt funziona legge la variabile e valuta, ne caso va il sleep per altri 8 secondi
come indicato wdt_enable(WDTO_8S);

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#define PU_ACC 2           //pulsante accensione
#define PU_AVV 3           //pulsante avviamento  
#define POWER 20           // alimentazione sensori
int Time ;       // varoalbile per sleep
int Time1 ;       // varoalbile per sleep

void enterSleep(void) {

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
digitalWrite(POWER, HIGH);
  
  sleep_enable();
  attachInterrupt(PU_ACC,  LOW); 
sleep_mode();
  /* Il programma riprende qui. */
  sleep_disable();
detachInterrupt(PU_ACC); 
}

void setup() {
   wdt_disable();
 digitalWrite(POWER, HIGH); 
  wdt_enable(WDTO_8S);
pinMode(PU_ACC, INPUT_PULLUP); // pulsante quadro
  pinMode(PU_AVV, INPUT_PULLUP);   //pulsante avviamento
 
}

void loop() {
  if (Time1 < Time) { //se ricezio e' inferiore a

    
    enterSleep();                     // metto in sleep
    while (1); 
  }
  wdt_reset();                //resetto  watchdog

}

la attachInterrupt è sbagliata manca la funzione ISR da richiamare, dalla documentazione ufficiale:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)

ok, deve attivarsi quando va da alto verso basso , quindi il comando e' FALLING

attachInterrupt(digitalPinToInterrupt(PU_ACC), ,LOOP,FALLING);

Scusami ma... resta comunque i fatto che non leggi la documentazione e manco quello che si scrive, o quantomeno lo fai superficialmente.
La funzione attachInterrupt prevede TRE parametri, il primo il pin, il secodo la ISR da richiamare e il terzo l'evento a cui deve essere scatenato l'interrupt.
Ammettendo un errore nella virgola in più non definisci l'ISR per gestire l'interrupt, se con LOOP intndevi richiamare il la funzione void loop stai sbagliando, studiati meglio gli esempi della documentazione per capire come gestire l'interrupt perché se l'idea era di richiamare il loop sulla pressione del tasto non hai per nulla chiaro di come funzionano gli interrupt e di come funziona il flusso del programma in caso di gestione dell'interrupt

ho cercato di leggere il piu' possibile su quanto mi hai suggerito.
per provare ho sostituito t time con un digitalRead() ed mi sembra che funzioni correttamente.
che sia chiaro. non voglio nulladi pronto,preferisco cercare di capire le cose...
ti ringrazio per quanto mi hai detto ora e per cercare di capire qualcosa

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#define PU_ACC 2           //pulsante accensione
#define PU_AVV 3           //pulsante avviamento 
#define POWER 13           // alimentazione sensori
int Time ;       // varoalbile per sleep
int Time1 ;       // varoalbile per sleep
void pin2Interrupt(void) {
  detachInterrupt(digitalPinToInterrupt(2));
  digitalWrite(13, HIGH);
}

void enterSleep(void) {
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  
   sleep_enable();  
  
  digitalWrite(13, LOW);
  attachInterrupt(digitalPinToInterrupt(PU_ACC), pin2Interrupt, LOW);
  sleep_mode();
 
  /* Il programma riprende qui. */
    
  sleep_disable(); 
}

void setup() {
  wdt_disable();
  Serial.begin(9600);
  wdt_enable(WDTO_8S);
   pinMode(PU_ACC, INPUT_PULLUP); // pulsante quadro
  pinMode(PU_AVV, INPUT_PULLUP);   //pulsante avviamento
 
}

void loop() {
  
   if (Time1 < Time) { //se ricezio e' inferiore a

    digitalWrite(POWER, LOW);
    enterSleep();                     // metto in sleep
    while (1);
  }
  wdt_reset();                //resetto  watchdog

}

}

Non so se è il comportamnto voluto ma qualora venga premuto il tasto esci dallo sleep e resti bloccato nel while(1) senza mai resettae il watchdog.

oggi riguardando il funzionamento , passo dopo passo e' come dici tu, ma non e' il modo in cui deve funzionare.
il watchdog si deve resettare quando metto a low ,(digitalPinToInterrupt(PU_ACC)

se si puo'dire, ha 2 modi di andare in sleep e di conseguenza svegliarsi.
il primo che da acceso valuta if (Time1 < Time) se vera va in sleep usando watchdog dorme 8 secondi si accende per 1 e valuta nuovamente l if.
la seconda che funziona in parallelo alla prima legge il pin Interrupt, e si sveglia valuta un if (il tempo tra una pressione di un tasto ed un alto )questo usando millis(), e dovrei arrangiarmi se e vera torna in sleep altrimenti va in loop.
a quando ce watchdog in esecuzione ,legge (digitalPinToInterrupt(PU_ACC)
e disattivi il watchdog durante l esecuzione
in qualsiasi momento

se durante il watchdog (digitalPinToInterrupt(PU_ACC) va low in ogni momento
si sveglia
valuta if (), o va in loop o va nuovamente in sleep_down e riattiva il wdt per 8 sec .
ogni 8 secondi valuta if(time) e procede di conseguenza

>pippero1979: in conformità al REGOLAMENTO, punto 13, il cross-posting è proibito (anche tra lingue diverse) per cui, il tuo post duplicato nella sezione Inglese del forum è stato cancellato.

Ti prego, per il futuro, di evitare di aprire più post sullo stesso argomento in sezioni differenti del forum. Grazie.

Guglielmo

chiedo scusa, per questo, evitero' che succeda nuovamente

... prova anche a descrivere ESATTAMENTE, magari anche con un bel diagramma, cosa vuoi che il tuo programma faccia, perché vedo molta confusione ... ::slight_smile:

Guglielmo

vediamo se ci riesco.

il wdt e attivo per 8 secondi, si attiva 1 secondo valuta l' if (Time1 < Time)
quindi o si riaddormenta per 8 secondi o resta sveglio.

il pin di risveglio interrupt deve uscire dallo sleep in qualsiasi momento degli 8 secondi
e valutare in if e andare in loop o ritornare il sleep

il wdt funziona legge la variabile e valuta, ne caso va il sleep per altri 8 secondi
come indicato wdt_enable(WDTO_8S);

Anche a me pare che ci sia un poco di confusione. Mettiamo che usi il wdt in modo originale ok, ma anche se fosse non vedo come il wdt possa fare dormire la MCU.

Facciamo chiarezza. Il wdt (cane da guardia) è un oscillatore locale indipendente dagli altri oscillatori presenti nella MCU. L'oscillatore è configurabile e lo si può avviare come pure fermare. A questo oscillatore è collegato un contatore, cioè un registro interno che si incrementa ogni colpo di clock, se ad esempio il registro è grande 8bit andrà in overflow quando il suo valore è 255 a cui si somma il colpo di clock, poiché 255+1 = 256 per contenere questo valore ci vorrebbero 9 bit ma ne abbiamo solo 8 allora 255+1 = 0 cioè il contatore riparte da zero, quando ciò accade la MCU viene resettata, si tratta di un vero e proprio reset o ripartenza. Per evitare che il contatore raggiunga 255+1 il programmatore deve azzerare il contatore, occhio che in questo caso non avviene il reset della MCU ma del wdt che continua ad oscillare e il contatore si incrementa ripartendo da zero. Quindi se tutto procede correttamente il wdt non resetterà mai la MCU.

Bene tutto questo in linea teorica, nella pratica bisogna leggere il datasheet della MCU poiché il wdt può essere implementato in modo differente e si presta anche ad essere usato in modo originale, ad esempio anziché un reset viene sollevata una IRQ (Interrupt Request, sarebbe a dire una richiesta di interruzione) a cui si associa una ISR (Interrupt Service Routine), sostanzialmente è una porzione di codice che viene eseguita quando il contatore del wdt va in overflow.

Con WDTO_8S il contatore va in overflow dopo circa 8 secondi.

Nota: per semplificare l'uso di questi meccanismi, arduino mette a disposizione delle funzioni (come ad esempio attachInterrupt) che permettono di associare una porzione di codice ad un evento. La porzione di codice in questo caso è una funzione detta genericamente "User Function" e svolge il compito della ISR, mentre l'evento corrisponde alla IRQ.

Ciao.

vediamo se ho capito, io dicevo che andava in sleep considerando una cosa sola il wdt e lo sleep, quindi mi spiegavo male
la mia domanda e' sbagliata perche io devo chiedere , mentre il wdt va avanti a contare come posso svegliare la mcu prima del limite che gli ho imposto mediante un attachInterrupt?
cosi e' piu ' corretto

Facciamo così, non parlare di sleep e di wdt ma di come si deve comportare la tua applicazione.

Più o meno posso intuire cosa vuoi ottenere, tuttavia al momento non so indicarti le istruzioni arduinesche ma ci si arriverà facilmente una volta capito come vuoi che si comporti la tua applicazione.

Ho dato una rilettura veloce al datahseet del atmega328 riguardo il wdt e lo sleep per rinfrescarmi le idee. Ricordavo correttamente il wdt è indipendente e può continuare ad oscillare anche se la MCU è in sleep mode. Quando il contatore del wdt va in overflow viene sollevata una IRQ, ciò causa il risveglio della MCU.
Quando in sleep mode qualunque IRQ venga sollevata comporta il risveglio (mmmm...quasi qualunque).

Per usare il wdt in questo modo lo si deve configurare in "interrupt mode" anziché in "reset mode".

In interrupt mode si dovrà associare alla IRQ (di nome WDT) una ISR che è quella porzione di codice che viene eseguita quando il contatore del wdt va in overflow. Supponiamo che dentro questa ISR tu ci scriva il codice per fare dormire la MCU allora il comportamento sarebbe:

Sta attivo In NON sleep per 8 secondi, poi viene eseguita la ISR dove dentro c'è scritto "vai in sleep mode"
e rimarra in sleep per almeno 8 secondi, oppure se viene sollevata un altra IRQ (ad esempio un pin changed) la MCU si sveglia prima di 8 secondi.

Per adesso accontentati della teoria, poi vediamo se arriva qualcuno che sa come fare queste cose con una libreria in modo arduinesco, diversamente in un modo o in un altro si risolve comunque.

Ciao.

si hai capito il mio bisogno, e me lo hai spiegato in modo perfetto, non come lo spiegavo io per ora ti ringrazio per il fatto che me lo hai spiegato in un linguaggio molto piu' tecnico di come lo spiegavo
grazie ancora

Maurotec:
... Per adesso accontentati della teoria, poi vediamo se arriva qualcuno che sa come fare queste cose con una libreria in modo arduinesco ...

Tutta la gestione dello sleep e tutta la gestione del wdt sono, come sempre, contenute in due moduli della AVR libc ...
... le funzioni relative alla gestione dello sleep sono in <avr/sleep.h>, mentre quelle relative alla gestione del wdt sono in <avr/wdt.h> :slight_smile:

Guglielmo

Dalla pagina DS40002061A-page 60 del datasheet.

In Interrupt mode, the WDT gives an interrupt when the timer expires. This interrupt can be used to wake the device from sleep-modes, and also as a general system timer.

Cioè:
In "Interrupt mode" il wdt da (solleva) un interrupt quando il timer scade. Questo interrupt può essere usato per svegliare la MCU da "sleep mode" e anche come un generico timer di sistema.

Quindi intanto serve capire se avr-libc fornisce delle api per configurare il wdt in "interrupt mode", l'alternativa è di configurare i registri.

Il registro si chiama "WDTCSR" il bit da accendere è il bit6 (WDIE), mentre il bit3 (WDE) deve essere spento. Se WDIE e WDE sono entrambe accesi il wdt si trova in " Interrupt and System Reset Mode", dove dopo il reset viene sollevato una IRQ.

WDTCSR |= _BV(WDIE);  // questo accende il bit6

Nota che si da per scontato che il registro WDTCSR sia zero prima di accendere il bit6.

La ISR che viene invocata è questa:

ISR(WDT_vect ) {
// qui il codice che viene eseguito dopo che il timer del wdt è andato in overflow
// chiama la funzione utente wdtHandler();
// wdtHandler(); // toggli // all'inizio per abilitare la chiamata a funzione
}

Se vuoi usare wdtHandler (gestore del wdt) la devi definire, cioè:

void wdtHandler() {

}

Ciao.

Posso suggerirvi di studiarvi gli ottimi due tutorial di leo? PRIMO e SECONDO ... troverete tutto spiegato :wink:

Guglielmo