délai radio.powerDown Nrf24L01

Bonjour à tous,

J'ai réalisé une mini station météo avec :

  • Un arduino pro mini,
  • Un NRF24L01
  • Une sonde BME280 (T°, humidité, pression)
  • Une sonde DS18b20 (t° extérieure)

Pour ce faire, je me suis inspiré de ce site :

Tout fonctionne mais je n'arrive pas à régler le délai de radio.powerDown à 60 secondes avec la boucle proposée ligne 122 de mon code et reproduite ci dessous :

for (int i = 0; i < 8; i++)//mise en veille pendant 64 secondes

Il me semble avoir lu quelque part qu'il faut que la boucle For exécute quelque chose pour que ça prenne du temps machine.

Est-il préférable d'utiliser delay ou, quel moyen élégant utiliser pour obtenir un délai d'attente précis (60 s par exemple!)?

Ci dessous, le code émetteur :

//source :https://itechnofrance.wordpress.com/2014/04/01/sonde-de-temprature-et-transmission-rf-avec-des-modules-nrf24l01/
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <RF24.h>
#include <Wire.h>
#include "SparkFunBME280.h"
#include "cactus_io_DS18B20.h"

#define DS18B20_POWER 3
#define BME280_POWER 5 //alimentation du capteur BME280
BME280 capteur;
float   t = 0 ;
float   h = 0 ;
float   p = 0;
float tDs18b20 = 0;

DS18B20 ds(DS18B20_POWER); // on digital pin 3

RF24 radio(9, 10); //création instance radio (pin ce,csn)

ISR (WDT_vect)
{
  wdt_disable(); //désactive le watchdog
}

void mywatchdogenable()
{
  MCUSR = 0;
  WDTCSR = _BV (WDCE) | _BV (WDE);
  WDTCSR = _BV (WDIE) | _BV (WDP3) | _BV (WDP0); //délai de 8 secondes
  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();
  sleep_disable();
}

void setup()
{
  Serial.begin(115200);
  pinMode(BME280_POWER, OUTPUT);
  pinMode(DS18B20_POWER, OUTPUT);
  digitalWrite(BME280_POWER, HIGH); //alimente le capteur BME280
  digitalWrite(DS18B20_POWER, HIGH);
  delay(3000);
  Serial.println("test1");
  //configuration du capteur
  capteur.settings.commInterface = I2C_MODE;
  capteur.settings.I2CAddress = 0x76;
  capteur.settings.runMode = 3;
  capteur.settings.tStandby = 0;
  capteur.settings.filter = 0;
  capteur.settings.tempOverSample = 1 ;
  capteur.settings.pressOverSample = 1;
  capteur.settings.humidOverSample = 1;

  Serial.println("Starting BME280... ");
  delay(10);  // attente de la mise en route du capteur. 2 ms minimum
  // chargement de la configuration du capteur
  capteur.begin();
  delay(10);  // attente de la mise en route du capteur. 2 ms minimum
  ds.readSensor();
  delay(3000); // allow 3 seconds for sensor to settle down
  ds.readSensor(); // read again to avoid weird values for defaults


  radio.begin();
  radio.setPALevel(RF24_PA_LOW); //puissance minimum
  radio.setChannel(0x20); //canal 32
  radio.setDataRate(RF24_1MBPS);
  radio.openWritingPipe(0xF0F0F0F0F0LL);
  radio.enableDynamicPayloads();
  radio.setAutoAck(1);
  radio.setRetries(15, 15);
}//fin setup

void loop ()
{
  digitalWrite(BME280_POWER, HIGH); //alimente le capteur BME280
  digitalWrite(DS18B20_POWER, HIGH);
  radio.powerUp(); //alimente le module nrf24l01+
  delay(3000); //attente 3 secondes avant d’effectuer une mesure du capteur BME280

  float txbuffer[4] = {0, 0, 0, 0};

  t = (capteur.readTempC());
  t = (t - 1);
  h = (capteur.readFloatHumidity());
  p = (capteur.readFloatPressure()) / 100;
  ds.readSensor();
  delay(3000); // allow 3 seconds for sensor to settle down
  ds.readSensor(); // read again to avoid weird values for defaults
  tDs18b20 = ds.getTemperature_C();

  Serial.print(F("Temperature : "));
  Serial.print((t), 2);
  Serial.print(" °C");
  Serial.print(F("\tPression : "));
  Serial.print((p), 2);
  Serial.print(" HPa");
  Serial.print (F("\tHumidite : "));
  Serial.print((h), 2);
  Serial.print(" %");
  Serial.print(F("\tTemperature Ext : "));
  Serial.print((tDs18b20), 2);
  Serial.println(" °C");  
  delay(1000);

  txbuffer[0] = t;
  txbuffer[1] = h;
  txbuffer[2] = p;
  txbuffer[3] = tDs18b20;
  radio.write(&txbuffer, sizeof(txbuffer));
  delay(500);

  digitalWrite(BME280_POWER, LOW); //arrêt de l’alimentation du BME280
  digitalWrite(DS18B20_POWER, LOW);
  radio.powerDown(); //arrêt de l’alimentation du module nrf24l01+
  for (int i = 0; i < 8; i++)//mise en veille pendant 64 secondes

    mywatchdogenable();
}

En effet, le but des lignes

  for (int i = 0; i < 8; i++)//mise en veille pendant 64 secondes

    mywatchdogenable();

est de faire 8 fois une mise en sommeil de 8 secondes, soit 64 secondes au total. Pour régler le délai à 60 secondes, il te faut faire 7 boucles de 8 secondes et une de 4 secondes. Tu dois donc créer un autre fonction qui met en sommeil pendant 4 secondes; disons que tu l'appelles mywatchdogenable4.

Tu feras alors :

for (int i = 0; i < ; i++) mywatchdogenable();//mise en veille pendant 56 secondes
mywatchdogenable4(); // 4 secondes de plus pour la route !

Reste à faire cette fonction :

void mywatchdogenable4()
{
  MCUSR = 0;
  WDTCSR = _BV (WDCE) | _BV (WDE);
  WDTCSR = _BV (WDIE) | _BV (WDP3); //délai de 4 secondes
  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();
  sleep_disable();
}

A tester...

Merci lesept pour ta réponse,

En fait, j'ai mal formulé ma question.

Les 64 secondes de délai me vont très bien mais je ne les obtient pas avec la boucle :

for (int i = 0; i < 8; i++)//mise en veille pendant 64 secondes
mywatchdogenable();

Que je mette la variable i à 3, 4 ou 8, j'obtiens toujours 30 s de délai.

Je sèche !

C'est bizarre, et si tu remplaces la boucle par :

    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();
    mywatchdogenable();

Avec un seul appel tu as bien 8 secondes ?

Le problème est abordé et résolu ici. Le code proposé :

// Example of sleeping and saving power
// 
// Author: Nick Gammon
// Date:   25 May 2011

#include <avr/sleep.h>
#include <avr/wdt.h>

#define LED 13

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

void myWatchdogEnable(const byte interval) 
  {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  } 

void setup()
{
pinMode (LED, OUTPUT);
}  // end of setup

void loop()
{
  digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

  // sleep for a total of 20 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100000);  // 4 seconds

}  // end ofloop

// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001

et pour une durée de 240 secondes (30 * 8 ) :

  // sleep for a total of 240 seconds
  for (int i = 0; i <30; i++)
  {  
    myWatchdogEnable (0b100001);  // 8 seconds
  }

Bonsoir lesept,

Merci pour l"aide.

Je vais étudier l'exemple et tester mon programme.

Je te tiens au courant.

Fitness04

Bonjour lesept, bonjour à tous,

J'ai modifié le watchdog suivant l'exemple de Nick Gammon et, ainsi, je maîtrise mieux le temps de mise en veille.

J'ai programmé un temps de (4+2)x 8 = 48 s et avec les différends delay j'arrive à 63 s entre chaque envoi à ThingSpeak, ce qui me va très bien.

Toutefois, j'ai mis un "mouchard" pour compter le temps de mise en veille et il ne m'indique que 7580 à 7590 ms.

Ai-je bien écris ce bout de code de calcul du temps ?

Voici le programme :

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <RF24.h>
#include <Wire.h>
#include "SparkFunBME280.h"
#include "cactus_io_DS18B20.h"

#define DS18B20_POWER 3
#define BME280_POWER 5 //alimentation du capteur BME280
BME280 capteur;
float   t = 0 ;
float   h = 0 ;
float   p = 0;
float tDs18b20 = 0;
unsigned long dateDernierChangement = 0;

DS18B20 ds(DS18B20_POWER); // on digital pin 3

RF24 radio(9, 10); //création instance radio (pin ce,csn)

ISR (WDT_vect)
{
  wdt_disable(); //désactive le watchdog
}

void myWatchdogEnable(const byte interval)
{
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  sleep_mode();            // now goes to Sleep and waits for the interrupt
}
// sleep bit patterns:
//  1 second:  0b000110
//  2 seconds: 0b000111
//  4 seconds: 0b100000
//  8 seconds: 0b100001

void setup()
{
  Serial.begin(115200);
  pinMode(BME280_POWER, OUTPUT);
  pinMode(DS18B20_POWER, OUTPUT);
  digitalWrite(BME280_POWER, HIGH); //alimente le capteur BME280
  digitalWrite(DS18B20_POWER, HIGH);
  delay(3000);
  Serial.println("test1");
  //configuration du capteur
  capteur.settings.commInterface = I2C_MODE;
  capteur.settings.I2CAddress = 0x76;
  capteur.settings.runMode = 3;
  capteur.settings.tStandby = 0;
  capteur.settings.filter = 0;
  capteur.settings.tempOverSample = 1 ;
  capteur.settings.pressOverSample = 1;
  capteur.settings.humidOverSample = 1;

  Serial.println("Starting BME280... ");
  delay(10);  // attente de la mise en route du capteur. 2 ms minimum
  // chargement de la configuration du capteur
  capteur.begin();
  delay(10);  // attente de la mise en route du capteur. 2 ms minimum
  ds.readSensor();
  delay(3000); // allow 3 seconds for sensor to settle down
  ds.readSensor(); // read again to avoid weird values for defaults


  radio.begin();
  radio.setPALevel(RF24_PA_LOW); //puissance minimum
  radio.setChannel(0x20); //canal 32
  radio.setDataRate(RF24_1MBPS);
  radio.openWritingPipe(0xF0F0F0F0F0LL);
  radio.enableDynamicPayloads();
  radio.setAutoAck(1);
  radio.setRetries(15, 15);
}//fin setup

void loop ()
{
  digitalWrite(BME280_POWER, HIGH); //alimente le capteur BME280
  digitalWrite(DS18B20_POWER, HIGH);
  radio.powerUp(); //alimente le module nrf24l01+
  delay(3000); //attente 3 secondes avant d’effectuer une mesure du capteur BME280

  float txbuffer[4] = {0, 0, 0, 0};

  t = (capteur.readTempC());
  t = (t - 1);
  h = (capteur.readFloatHumidity());
  p = (capteur.readFloatPressure()) / 100;
  ds.readSensor();
  delay(3000); // allow 3 seconds for sensor to settle down
  ds.readSensor(); // read again to avoid weird values for defaults
  tDs18b20 = ds.getTemperature_C();

  Serial.print(F("Temperature : "));
  Serial.print((t), 2);
  Serial.print(" °C");
  Serial.print(F("\tPression : "));
  Serial.print((p), 2);
  Serial.print(" HPa");
  Serial.print (F("\tHumidite : "));
  Serial.print((h), 2);
  Serial.print(" %");
  Serial.print(F("\tTemperature Ext : "));
  Serial.print((tDs18b20), 2);
  Serial.println(" °C");
  delay(1000);

  txbuffer[0] = t;
  txbuffer[1] = h;
  txbuffer[2] = p;
  txbuffer[3] = tDs18b20;
  radio.write(&txbuffer, sizeof(txbuffer));
  delay(500);
  unsigned long dateCourante = millis();
  unsigned long intervalle = dateCourante - dateDernierChangement;

  digitalWrite(BME280_POWER, LOW); //arrêt de l’alimentation du BME280
  digitalWrite(DS18B20_POWER, LOW);

  radio.powerDown(); //arrêt de l’alimentation du module nrf24l01+
  for (int i = 0; i < 8; i++) //mise en veille pendant 48 secondes
  {
    myWatchdogEnable (0b100000);  // 4 seconds
    myWatchdogEnable (0b000111);  // 2 seconds
  }
  Serial.print("Temps mise en veille (ms): ");
  Serial.println(intervalle);
  dateDernierChangement = dateCourante;
}

Merci d'avance

Après lecture rapide, je pense qu'il faut changer
  dateDernierChangement = dateCourante;par  dateDernierChangement = millis();