[RESOLU] Une interruption, un boutton et une led pour un système sur batterie

Bonjour à tous !

je suis en train de me pencher sur les interruptions et à priori, je ne saisi pas tout... :slight_smile:
J'utilise le code de la page arduino attachinterrupt (qui fonctionne à l'origine et que j'ai un peu modifié), un atmega328, une led et un interrupteur (en pull-up). Ce que je cherche à faire, c'est allumer la led pendant une seconde dès l'appui sur l’interrupteur, même si j’appuie à nouveau, la led ne doit pas s'éteindre mais là, ça coince !

Petit précision, je souhaite utiliser une interruption et non pas "la voie classique" afin de consommer moins d'énergie. Lorsque le système n'est pas utilisé (pas de pression sur le bouton) le microcontrôleur ne fait rien d'autre dans mon application, il attend l’interruption et à ce moment là, il doit exécuter quelques lignes de code. Je ne sais d’ailleurs pas si j'utilise le meilleur moyen pour réaliser un système basse consommation ?

Si quelqu'un a un conseil ou une idée à ce sujet.. merci par avance !

const byte ledPin = 13;
const byte interruptPin = 3;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  if (state == HIGH);
  else
  {
  state = !state;
  delay(1000);
  }
}

Bonjour,

Pas de delay(x) dans une interruption.

Elle dois être la plus courte possible.

L'idéal c'est d'activer un drapeau ici "state " et de sortir de l'interruption.

Merci de relire et d'analyser la fonction blink... y a soucis dans le "déroulé".

void loop() {
  digitalWrite(ledPin, state);
}

ça c'est a enlever , il faut traiter l'état du drapeau activé dans la fonction blink

Génial, c'est exactement ce qu'il me faut !

Les tensions sont effectivement déjà minimales, je n'avais pas pensé à l'horloge... La led c'est pour valider mon soft, je préfère y aller pas à pas, car après, quand ça ne fonctionne pas, on ne sais jamais d'où ça viens.

je posterais mon code quand ça fonctionnera :slight_smile:
Merci à vous et bonne soirée.

Et hop, ça fonctionne :slight_smile:
J'ai finalement préféré mettre une interruption pour un niveau 0 sur la voie 2 (que niveau 1 sur la voie 3) car il me semble que cela consomme moins d'énergie de commuter la masse plutôt que le 5v (avec un mosfet) par exemple.
Si ça peux servir à quelqu'un...
Merci à vous !

#include <avr/sleep.h>

int wakePin = 2;                 // pin used for waking up
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  digitalWrite(LED_BUILTIN, HIGH);
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(9600);

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
}

void sleepNow()         // here we put the arduino to sleep
{ 
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 
    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 
    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(1);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.
}
void loop()
{
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // waits for a second
  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
      
    }
  }

  // check if it should go to sleep because of time
  if (count >= 10) {

      digitalWrite(LED_BUILTIN, LOW);
    
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
}

J'ai finalement une question sur ce code qui fonctionne car j'aimerai comprendre de quelle manière :

J'ai quelques lignes de code à y insérer et notamment dans "loop".

Je voit qu'une des instructions est delay(1000) à la sixième ligne de loop. Néanmoins je veux que mes instructions s'exécutent à une fréquence bien plus élevée ! Si je ne m'abuse, ce délai sera appliqué à tout le bloc... y a t-il donc un moyen de le contourner pour d'un coté jouer un code à une fréquence bien plus élevée tout en continuant à conter jusque 10 pour mettre en sommeil le moment venu ?

Par avance merci

hello
non testé

#include <avr/sleep.h>

int wakePin = 2;                 // pin used for waking up
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter
unsigned long deb=0;
unsigned long fin=0;
void wakeUpNow()        // here the interrupt is handled after wakeup
{
  digitalWrite(LED_BUILTIN, HIGH);
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(9600);

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
  deb=millis();                                    
}

void sleepNow()         // here we put the arduino to sleep
{ 
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 
    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 
    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(1);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.
}
void loop()
{
if ((millis()-deb)>1000){
  
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // waits for a second
  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
      
    }
  }

  // check if it should go to sleep because of time
  if (count >= 10) {

      digitalWrite(LED_BUILTIN, LOW);
    
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
  deb=millis(); 
}
else {
  Serial.println("dans ce else, je fais ce que je veux"); 
  }
}

Merci dfgh !

J'aimerais comprendre comment cela fonctionne, afin d'être un peu plus autonome :slight_smile: et aussi, essayer de débugger, car, après ajout de mon code, cela fonctionne après un seul réveil par interruption (mais pas deux fois !) Ensuite le microcontrôleur reste dans un état ou ma led builtin est allumée et il ne répond plus à rien :confused:
NB : Au niveau du moniteur série, ça reste sur : "Timer: Entering Sleep mode". Mon capteur ne reçois également plus les résultats et la led_2 ne s'allume plus si franchissement du seuil.

Je pense que le "sleep mode" affiché au moniteur série ne colle pas avec ce qui se passe réellement puisque ma led s'allume! Le microcontrôleur est donc bien passé par "voidwakeup" mais n'est visiblement pas entré dans "loop"
N'y a t-il pas un reset des variables a effectuer après chaque cycle sommeil/réveil ou alors un besoin de les redéfinir ? Est-il possible qu'une valeur s'accumule et sature un tampon ou quelque chose de ce genre?

Si quelqu'un à une idée.. je suis preneur !
merci à vous

#include <avr/sleep.h>
#include <IO_CAPTEUR.h>
#include <Wire.h>

IO_CAPTEUR capteur;
CAPTEUR_Values result;

int wakePin = 2;                 // pin used for waking up
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter
unsigned long deb=0;
unsigned long fin=0;

int LED_2 = 12;

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  digitalWrite(LED_BUILTIN, HIGH);
}

void setup()
{
  Wire.begin();
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(LED_2, OUTPUT);
  Serial.begin(9600);
  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function  // wakeUpNow when pin 2 gets LOW
  deb=millis();                                   

  
  capteur.begin();
  capteur.setOffset(CAPTEUR_OFFSET_DAC_EN_AUTO);
  capteur.setSensitivity(CAPTEUR_SENSITIVIT_100);
  capteur.setTout(CAPTEUR_TIMEOUT_128);
  capteur.setRange(CAPTEUR_RANGE_10);
  capteur.setup();

}

void sleepNow()         // here we put the arduino to sleep
{
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin
    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW
    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(1);      // disables interrupt 0 on pin 2 so the
                             // wakeUpNow code will not be executed
                             // during normal running time.
}
void loop()
{
if ((millis()-deb)>1000){
 
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(100);                           // waits for a second
  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep
      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
     
    }
  }

  // check if it should go to sleep because of time
  if (count >= 10) {

      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(LED_2, LOW);
   
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
  deb=millis();
}
else {
  
  result = capteur.getValue();
  Serial.print("Value :");
  Serial.print(result.value, DEC);
  delay(50);  //20
  Serial.println(); 

  if (result.value >= 1480) 
        digitalWrite(LED_2, HIGH);
  else
        digitalWrite(LED_2, LOW);
  }
}

Je pense avoir réussi à cerner le problème.
C'est à priori la ligne result = capteur.getValue(); de mon code qui fait planter le microcontrôleur. Le capteur fonctionne en i2c, je pense donc que l'échange ne se fait pas ou pas correctement au réveil du microcontrôleur. Quelqu’un as t-il déjà eu un souci similaire ?

hello
dans un premier temps veux tu tester ce prg
tu mets un BP entre D2 et la masse
tu lances le prg et tu ouvres le moniteur.
à chaque passage dans la loop, il y a affichage d'une "*"
le compteur compte les secondes et arrivé à 10, le µ part en sommeil.
pour le réveiller, il faut un appui sur le BP.

si pendant l'affichage des "*", tu envoies "S" par le moniteur, le µ part en sommeil
pour le réveiller, il faut un appui sur le BP.

tiens nous au courant

#include <avr/sleep.h>
//#include <IO_CAPTEUR.h>
#include <Wire.h>

//IO_CAPTEUR capteur;
//CAPTEUR_Values result;

int wakePin = 2;                 // pin utilise pour reveiller le µ
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter
unsigned long deb=0;
unsigned long fin=0;

int LED_13 = 13;

void wakeUpNow()                // ici l'interruption est traitée après le réveil
{
  digitalWrite(LED_BUILTIN, HIGH);
}

void setup()
{
  Wire.begin();
  pinMode(wakePin, INPUT_PULLUP);
  pinMode(LED_13, OUTPUT);digitalWrite(LED_13, LOW);
  Serial.begin(115200);
  attachInterrupt(0, wakeUpNow, FALLING);     // use interrupt 0 (pin 2) and run function  // wakeUpNow when pin 2 gets LOW
                                     

  /*
  capteur.begin();
  capteur.setOffset(CAPTEUR_OFFSET_DAC_EN_AUTO);
  capteur.setSensitivity(CAPTEUR_SENSITIVIT_100);
  capteur.setTout(CAPTEUR_TIMEOUT_128);
  capteur.setRange(CAPTEUR_RANGE_10);
  capteur.setup();
*/
deb=millis();
}

void sleepNow()         // here we put the arduino to sleep
{
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // sleep mode is set here
    sleep_enable();                         // enables the sleep bit in the mcucr register
                                            // so sleep is possible. just a safety pin
    attachInterrupt(0,wakeUpNow, LOW);      // use interrupt 0 (pin 2) and run function
                                            // wakeUpNow when pin 2 gets LOW
    sleep_mode();                           // here the device is actually put to sleep!!
                                            // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
    sleep_disable();                        // first thing after waking from sleep:
                                            // disable sleep...
    detachInterrupt(1);                     // disables interrupt 0 on pin 2 so the
                                            // wakeUpNow code will not be executed
                                            // during normal running time.                           
}
void loop()
{

//Serial.println("je fais ce que je veux a la vitesse de scrutation de la boucle");
Serial.print("*");
if (Serial.available())                     // compute the serial input
  {
    int val = Serial.read();
    if (val == 'S') 
    { 
      Serial.println(" ");
      Serial.println("entree en sommeil par l'envoi d'un S par la liaison serie du moniteur");
      delay(100);                           // this delay is needed, the sleep function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();                           // sleep function called here
      Serial.println("reveil du sommeil  S serie par l'entree interruptible D2 ");
    }
    if (val == 'A') 
    {
      Serial.println("Hola Caracola");      // classic dummy message
    }
  }
  digitalWrite(LED_13, HIGH);
  
if ((millis()-deb)>1000)
  {
  Serial.print("en eveil depuis ");         //eveil depuis  Awake for 
  Serial.print(count);
  Serial.println(" sec");
  count++;
  if (count >= 10) 
  {                                         // check if it should go to sleep because of time
      digitalWrite(LED_13, LOW);
      Serial.println(" ");
      Serial.println("entree en sommeil par le compteur qui est arrive a 10");
      delay(100);                           // this delay is needed, the sleep function will provoke a Serial error otherwise!!                
      count = 0;
      sleepNow();                           // sleep function called here
      Serial.println("reveil du sommeil compteur par l'entree interruptible D2 ");
  }
  deb=millis();
  }
}

Bonjour à tous,

merci dfgh, le code fonctionne bien si l'on laisse le compteur aller jusque 10. En revanche, si l'on force le sommeil avec S, le réveil avec D2 donne :

en eveil depuis 9 sec
 
entree en sommeil par le compteur qui est arrive a 10
reveil du sommeil compteur par l’entrée interruptible D2 
*

Je n'ai pas résisté à y inclure mon code pour le capteur... Le réveil fonctionne bien avec le BP, et le microcontroleur lis l'I2C sans problèmes. J'ai par contre le même bug que précédemment si je tente de réveiller le microcontrôleur avec mon capteur (mise à la masse de D2 via un Mosfet dont la gachette est triggée par le capteur) à la place du BP.

Je ne vois pas vraiment ce que ça change par rapport au BP, c'est peut-être une entrée plus bruitée (j'ai tenté une capa D2/masse sans succès). Y a t-il un rapport entre ces deux erreurs, je sèche...

Une idée ?
Merci encore !

NB : Une grosse erreur de ma part, j'avais oublié le pull up de D2 lors du trig avec le capteur.
Néanmoins, le problème persistant est que cela bug de temps en temps, un manque de stabilité et je n'arrive pas déterminer si c'est matériel ou logiciel.

hello
je viens de récupérer le code que je t'ai posté. j'ai viré l(affichage de "*" pour une question de possibilité de voir ce qui se passe sur le moniteur.

je confirme que le code que je t'ai passé fonctionne dans les deux cas.

voir la copie d'écran ci jointe:

en eveil depuis 0 sec
en eveil depuis 1 sec
en eveil depuis 2 sec
en eveil depuis 3 sec
en eveil depuis 4 sec
en eveil depuis 5 sec
en eveil depuis 6 sec
en eveil depuis 7 sec
en eveil depuis 8 sec
en eveil depuis 9 sec

entree en sommeil par le compteur qui est arrive a 10
reveil du sommeil compteur par l'entree interruptible D2
en eveil depuis 0 sec
en eveil depuis 1 sec
en eveil depuis 2 sec
en eveil depuis 3 sec
en eveil depuis 4 sec
en eveil depuis 5 sec

entree en sommeil par l'envoi d'un S par la liaison serie du moniteur
reveil du sommeil S serie par l'entree interruptible D2
en eveil depuis 0 sec
en eveil depuis 1 sec
en eveil depuis 2 sec
en eveil depuis 3 sec
en eveil depuis 4 sec
en eveil depuis 5 sec
en eveil depuis 6 sec
en eveil depuis 7 sec
en eveil depuis 8 sec
en eveil depuis 9 sec

entree en sommeil par le compteur qui est arrive a 10

que tu n'avais pas de résistance de pullup ...dans les déclarations tu trouveras:
int wakePin = 2;
pinMode(wakePin, INPUT_PULLUP);

par contre, pourquoi un mosfet pour mettre D2 à GND ?

si tu veux inverser le signal de ton capteur, tu peux :
mettre une résistance extérieure en pushdown,
modifier la déclaration du INPUT_PULLUP de pinMode(wakePin, INPUT_PULLUP) en INPUT simple
modifier le sens de l'interruption FALLING par RISING dans attachInterrupt(0, wakeUpNow, FALLING);

et ce sera fonctionnel.

Salut dfgh,

j'utilisais un mos car la consommation d'énergie est plus faible si l'on commute la masse. Finalement cela fait un composant en plus, avec ses déperditions... ce n'est surement pas un bon calcul car le signal venant du capteur ne dure quelques centaines de millisecondes.

J'ai modifié void setup

attachInterrupt(0, wakeUpNow, RISING);
pinMode(wakePin, INPUT);

et void sleepNow attachInterrupt(0,wakeUpNow, HIGH);

J'ai finalement relié la sortie du capteur en direct sur D2 et ça fonctionne. Le mos devais donc générer un signal incorrect sur D2. Par contre je me demandais s'il faillais préférer l'utilisation d'une des deux entrée (PD2 / PD3) selon que l'on réalise une interruption d'un état bas à haut et inversement ?

Merci ! :slight_smile: