je suis en train de me pencher sur les interruptions et à priori, je ne saisi pas tout...
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 !
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
Merci à vous et bonne soirée.
Et hop, ça fonctionne
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 ?
#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");
}
}
J'aimerais comprendre comment cela fonctionne, afin d'être un peu plus autonome 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
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();
}
}
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...
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);
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.
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 ?