Mode sleep arduino avec Watchdog Timer et interruption externe

Salut à tous,

J'ai suivie le très bon tuto ici : Arduino, Zigbee and Embedded Development: Sleeping Arduino - Part 5 Wake Up Via The Watchdog Timer
Pour mettre en repos mon arduino pour l'optimisation de la conso sur baterrie.

Je voulais savoir si des gens était arrivé à faire fonctioner le mode Watchdog Timer et interruption externe en même temps ? car d'après mes premiers tests, j'y suis pas arrivé ...

En gros j'ai fait une fusion des 2 codes en modifiant ensuite la fonction :

void enterSleep(void)
{
  
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, RISING);
  delay(100);
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  
  sleep_mode();
  
  /* The program will continue from here. */
  
  /* First thing to do is disable sleep. */
  sleep_disable(); 
}

car en gros je voudrais réveiller l'arduino pour acquérir une donnée toutes les 5min sauf si on appuie sur un bouton.

Merci par avance de votre aide.

ce serai mieu que tu donne ton code complet.
d'apres les liens que tu donne:

le detachInterrupt(0) dans la routine IT pre-supose qu'on y retourne plus et donc peut etre devalidé avant le sleep mode.

l'interruption wdg est prioritaire a int0.
la routine IT peut donc etre interrompue par le wdog, ce qui n'est pas souhaitable, vu que t'es deja reveillé.
il faut jouer du cli() et sei().

ca fonctionne:

/*
 * Sketch for testing sleep mode with wake up on WDT.
 * Donal Morrissey - 2011.
 *
 */
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define LED_PIN (13)

volatile int f_wdt=1;


//***************************************************
void pin2Interrupt(void)
{
  cli();
  
  sleep_disable(); /* First thing to do is disable sleep. */
  power_all_enable();
  //if(f_wdt == 0) {f_wdt=1;}

  delay(200);
  Serial.println("wakeUp Interrupt ...");
  delay(200);

  //detachInterrupt(0);
  digitalWrite(LED_PIN, !digitalRead(LED_PIN));
  
  sei();
  
}

/***************************************************
 *  Name:        ISR(WDT_vect)
 *  Returns:     Nothing.
 *  Parameters:  None.
 *  Description: Watchdog Interrupt Service. This
 *               is executed when watchdog timed out.
 *
 ***************************************************/
ISR(WDT_vect)
{
  if(f_wdt == 0) {f_wdt=1;}
  else
  {
    Serial.println("WDT Overrun!!!");
  }
}

/***************************************************
 *  Name:        enterSleep
 *  Returns:     Nothing.
 *  Parameters:  None.
 *  Description: Enters the arduino into sleep mode.
 *
 ***************************************************/
void enterSleep(void)
{
  
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}

/***************************************************
 *  Name:        setup
 *  Returns:     Nothing.
 *  Parameters:  None.
 *  Description: Setup for the serial comms and the
 *                Watch dog timeout. 
 *
 ***************************************************/
void setup()
{
  Serial.begin(9600);
  Serial.println("Initialising...");
  delay(100); //Allow for serial print to complete.

  pinMode(LED_PIN,OUTPUT);

  /*** Setup the WDT ***/
  
  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);
  
  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */
  
  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
  
  Serial.println("Initialisation complete.");
  delay(100); //Allow for serial print to complete.

  attachInterrupt(0, pin2Interrupt, CHANGE);
  Serial.println("Interrup attached.");
  delay(200);

}

/***************************************************
 *  Name:        enterSleep
 *  Returns:     Nothing.
 *  Parameters:  None.
 *  Description: Main application loop.
 *
 ***************************************************/
void loop()
{
  if(f_wdt == 1)
  {
    /* Toggle the LED */
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    
    /* Don't forget to clear the flag. */
    f_wdt = 0;
    
    Serial.println("enterring sleep mode.");
    delay(200);

    /* Re-enter sleep mode. */
    enterSleep();

    Serial.println("outging from sleep mode.");
    delay(200);
  }
  else
  {
    /* Do nothing. */
  }
}

Ok, je vais me tester ça.

Merci encore :slight_smile:

ça marche nikel, merci encore :slight_smile:

Salut,

J'ai une petite question, je suis en train de me coder une petite librairie sleep en C++ pour mes projets mais je sais pas comment coder mon ISR(WDT_vect) dans ma librairie C++.

car après le timeout, il va chercher la fonction ISR() mais pas la methode Sleep::ISR() ? si je ne me trompe pas?

Merci par avance.

je te conseil vivement de te pencher sur le datasheet du controleur.
ISR(WDT_vect) delcare une routine a l'adresse memoire pointé par un vecteur d'interrution.
kesako? sans rentrer dans des details qui peuvent avoir leur importance, surtout si t'es au cycle horloge pres:
lors d'un interruption, on interrompt le programe en cours ou qu'il soit, on traite traite l'interruption, puis on revient ou on etait.
pour que ce soit transparent au programe en cours, il faut sauvegarder l'etat d'ou on vient, ce n'est pas exactement pareil que d'appeler une fonction.
c'est ce qui se passe avec millis, par exemple. tu l'utilise de maniere transparente parce que ton programme est interrompu par timer regulièrement pour incrémenter la variable, puis reprend avec les registres du controleur dans l'etat ou ils etaient.

ce n'est pas parce que t'as créé une fonction a cette adresse, qu'elle va etre appelée, ca depend des "masques d'interruption", en gros des zones memoires qui gerent ces interruptions. les interruptions peuvent s'imbriquer entres elles (une interruption peut etre interrompue par une autre, comme tu viens de le constater)

voir egalement wiring.c, WInterrupt.c, sleep.h
ce qu'il faut donc que tu fasse, c'est parametrer les zones memoire concerné.

si j'ai bien compris ce que tu voulais faire...?