Problème avec un reveil par interruption

Bonjour, ;D

J’ai un petit souci sur un projet. J’ai installé au dessus d’une porte une capteur qui est sensé me prévenir de l’ouverture de la porte.
Il s’agit d’un Arduino avec un module nrf24l01+ avec un interrupteur magnétique. Le tout est sur piles.
Le dispositif reste en veille, avec un envoi de l’état de la batterie et de l’état de interrupteur toute les 800 secondes → OK ca fonctionne bien.

En toute logique, je voudrais que le dispositif envoi également un message lors du changement de l’état de l’interrupteur (ouverte ou fermeture de la porte). Mais là ca coince. J’ai consultez plusieurs forums et blog, et mon code me semble bon. Qu’est ce que j’ai raté ? Il me semble bien avoir attaché l’interruption au bon endroit ? ::slight_smile:

J’ai vérifié le câblage, l’arduino capte bien l’état de l’interrupteur, mais le changement d’état ne semble pas le réveiller.

Merci d’avance pour votre aide !

#include <SPI.h>
#include “RF24.h”
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

RF24 radio(9,10);
#define PIN_SWITCH 2

byte addresse = { 0x19,0x03,0x55,0x02,0x02 }; //relai NRF/Ethernet
String genTopic=“porte1/”;
// Watchdog Interrupt Service est exécité lors d’un timeout du WDT
ISR (WDT_vect)
{
wdt_disable(); //désactive le watchdog
}

void ISR_door(){

}

void enterSleep(int ii) {// paramètre : 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9=8 sec

byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;

// Clear the reset flag
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCSR = bb;
WDTCSR |= _BV(WDIE);

wdt_reset();
ADCSRA = 0; //désactive ADC
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();

MCUCR = _BV (BODS) | _BV (BODSE);
MCUCR = _BV (BODS);
attachInterrupt(digitalPinToInterrupt(PIN_SWITCH),ISR_door,CHANGE);
sleep_cpu();
sleep_disable();
detachInterrupt(digitalPinToInterrupt(PIN_SWITCH));

}

void send(String msg)
{
radio.powerUp();
byte packet[32]; //Packet envoyé par RF
msg.toCharArray(packet,32);
radio.write(&packet,32,1); //avec ACK
radio.powerDown();
}
void setup()
{
//Serial.begin(9600);
radio.begin(); // Start up the radio
//radio.setAutoAck(1); // Ensure autoACK is enabled
//radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openWritingPipe(addresse);
pinMode(PIN_SWITCH,INPUT);
}
void loop()
{
int batt = analogRead(0);
batt = map(batt,0,1023,0,3300);
batt = map(batt,1000,3000,0,100);
String msg = genTopic;
msg+=String(“batt1/”);
msg+=String(batt);
//Serial.println(msg);
send(msg);
enterSleep(5);

String val=“0”;
if(digitalRead(PIN_SWITCH)){ val=“1”;}
msg = genTopic;
msg+=String(“porte1/”);
msg+=String(val);
//Serial.println(msg);
send(msg);
//delay(500);

for (int i=0; i < 10; i++){enterSleep(9);} //Veille pour 10x8 secondes
}

sans regarder le code, as tu laissé un peu de temps au nrf24l pour se "reveiller"

en regardant le code
ne devrais tu pas autoriser les interruptions avant de partir dormir?

interrupts ();

Bonjour et merci pour ta réponse,

J'ai essayé de rajouter un delay avant l'envoi du message, ca ne change rien.
Idem si je rejoute interrupts() avant le sleep_cpu(), de toute façon il me semble bien que attachInterrupt à le même effet ?

:frowning: Je n'y comprend plus grand chose

hello peux tu regarder ce code puis le tester

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

RF24 radio(9,10);
#define PIN_SWITCH 2 

byte addresse[]  = { 0x19,0x03,0x55,0x02,0x02 }; //relai NRF/Ethernet
String genTopic="porte1/";
boolean demande_envoi=false;int z;
// Watchdog Interrupt Service est exécité lors d'un timeout du WDT
ISR (WDT_vect){wdt_disable();} //désactive le watchdog
void ISR_door(){sleep_disable();demande_envoi=true;z=11;}

void enterSleep(int ii) {// paramètre : 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9=8 sec
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;

  // Clear the reset flag
  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);

  wdt_reset();
  ADCSRA = 0; //désactive ADC
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS);
 
 
  sleep_cpu();
  //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  //ZZZ  pour 8 s car ii = 9  ZZZ
  //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  sleep_disable(); 
}

void send(String msg)
{
  radio.powerUp();
  byte packet[32]; //Packet envoyé par RF
  //msg.toCharArray(packet,32);
  radio.write(&packet,32,1); //avec ACK
  radio.powerDown();
}
void setup()
{
   Serial.begin(115200);
   radio.begin();                          // Start up the radio
   //radio.setAutoAck(1);                    // Ensure autoACK is enabled
   //radio.setRetries(15,15);                // Max delay between retries & number of retries
   radio.openWritingPipe(addresse); 
   pinMode(PIN_SWITCH,INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(PIN_SWITCH),ISR_door,CHANGE);
}
void loop()
{Serial.println("debut loop");Serial.flush();
   int batt = analogRead(0);
   batt = map(batt,0,1023,0,3300);
   batt = map(batt,1000,3000,0,100);
   String msg = genTopic;
   msg+=String("batt1/");
   msg+=String(batt);
   Serial.println(msg);Serial.flush();
   //send(msg);
   //enterSleep(5);

   String val="0";
   //if(digitalRead(PIN_SWITCH)){ val="1";}
   if(demande_envoi==true)
   { val="1";
  // msg = genTopic;
  // msg+=String("porte1/");
   msg+=String(val);
   Serial.println(msg);Serial.flush();
   //send(msg);
   //delay(500);
  
 Serial.println("fin loop");Serial.flush();
 }
   interrupts ();
   for (z=0; z < 10; z++){enterSleep(9);Serial.print("sommeil = ");Serial.println(8*z);Serial.flush();} //Veille pour 10x8 secondes
   
   noInterrupts ();
}

Bonjour dfgh

J'ai essayé ton code mais ca ne marche pas :frowning:

Je pense que je vais traiter le problème différament avec un réveil toute les seconde ou demi-seconde et un check de l'état de la porte. Sauf si tu as une autre idée ?

Merci pour ton aide en tout cas :slight_smile:

hello
le code fonctionne. je l'avais testé avant de te le poster et je viens de le télécharger depuis ce post et de le tester à nouveau. il est ok
tu le charges, tu ouvres le moniteur en 115200 et tu regardes
tu verras :
"debut loop
port1/batt1/25
sommeil = 0
sommeil = 8
sommeil = 16
sommeil = 24
...
sommeil = 72
debut loop
porte1/...

tu constates bien que la µpasse en sommeil pour 10 fois 8 secondes et qu'il l'affiche à chaque reveil.

maintenant si tu attends qu'il parte en sommeil et que tu portes D2 à GND, tu constates une sortie immédiate du sommeil
à ce moment, il y a retour dans la boucle et dans isr de d2, j'ai forcé z à 11.
si bien que sur un retour par d2 le prg sort immédiatement de la boucle for avec un affichage de sommeil = 88

donc oui, la sortie du sommeil fonctionne sur une interruption par D2

ton switch de porte est il bien raccordé sur D2
l'entrée étant déclarée avec un pull up, le switch doit ramener le GND sur l'entrée D2

c'est toi qui es sur place et qui peux trouver ce qui ne va pas.
mais le prg est opérationnel

OK je suis un gros boulet… Je surveillais l’arrivée de la trame NRF mais pas le serial… :-[

Du coup ca marche super ! Merci merci !

Petite curiosité par rapport à ton code :
la variable “demande_envoi” ne repasse jamais à False ? Le seul endroit du code où elle pourrait le faire c’est au début, mais cette partie n’est pas re-executer après la mise sous tension ?

Merci encore en tout cas !

Avec ces quelques modif c’est bon :

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

RF24 radio(9,10);
#define PIN_SWITCH 2

byte addresse[]  = { 0x19,0x03,0x55,0x02,0x02 }; //relai NRF/Ethernet
String genTopic="porte1/";
boolean demande_envoi=false;int z;
// Watchdog Interrupt Service est exécité lors d'un timeout du WDT
ISR (WDT_vect){wdt_disable();} //désactive le watchdog
void ISR_door(){sleep_disable();demande_envoi=true;z=11;}

void enterSleep(int ii) {// paramètre : 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9=8 sec
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;

  // Clear the reset flag
  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);

  wdt_reset();
  ADCSRA = 0; //désactive ADC
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS);
 
 
  sleep_cpu();
  //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  //ZZZ  pour 8 s car ii = 9  ZZZ
  //ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
  sleep_disable();
}

void send(String msg)
{
  radio.powerUp();
  byte packet[32]; //Packet envoyé par RF
  msg.toCharArray(packet,32);
  radio.write(&packet,32,1); //avec ACK
  radio.powerDown();
}
void setup()
{
   //Serial.begin(115200);
   radio.begin();                          // Start up the radio
   //radio.setAutoAck(1);                    // Ensure autoACK is enabled
   //radio.setRetries(15,15);                // Max delay between retries & number of retries
   radio.openWritingPipe(addresse);
   pinMode(PIN_SWITCH,INPUT_PULLUP);
   attachInterrupt(digitalPinToInterrupt(PIN_SWITCH),ISR_door,CHANGE);
}
void loop()
{//Serial.println("debut loop");Serial.flush();
   int batt = analogRead(0);
   batt = map(batt,0,1023,0,3300);
   batt = map(batt,1000,3000,0,100);
   String msg = genTopic;
   msg+=String("batt1/");
   msg+=String(batt);
  // Serial.println(msg);Serial.flush();
   send(msg);
   interrupts ();
   enterSleep(5);
   noInterrupts ();

   String val="0";
   if(digitalRead(PIN_SWITCH)){ val="1";}else{val="0";};

   msg = genTopic;
   msg+=String("porte1/");
   msg+=String(val);
  // Serial.println(msg);Serial.flush();
   send(msg);
   //delay(500);
 
 Serial.println("fin loop");Serial.flush();
 
   interrupts ();
   for (z=0; z < 10; z++){enterSleep(9);/*Serial.print("sommeil = ");Serial.println(8*z);Serial.flush();*/} //Veille pour 10x8 secondes
   
   noInterrupts ();
}

Un dernier mystère cependant : si je commente toutes les lignes Serial, ca ne marche plus… Même si je rajoute un delay(100) à la place. Etrange non ?