Sleep mode sur une Nano Every ?

Bonjour à tous,

Encore moi, pour ceux qui m'ont aidé ces derniers jours à démarrer !
Merci encore.

Mon projet a pris la forme que j'espérais, et je suis très content du résultat.

J'utilise un capteur de luminosité pour piloter un servo moteur.

Le contrôle de luminosité n'a besoin d'être fait qu'à des intervalles assez espacés (15 minutes suffiront).

Comme un gros malin, je me suis dit, que pour préparer mon coup d'après, j'allais optimiser la conso en prévision d'un alimentation sur batterie voire petit panneau solaire. Sauf que je me rends compte que la librairie Low Power n'est pas dispo pour un ATMega4809...

Existe-t-il un moyen de contourner ceci ?

mon idée était simplement de faire un
LowPower.sleep(xxx);

au lieu de
delay(xxx);

Merci,
Louis

Bonjour @lto

peut être des pistes dans ce fil de discussion

I gave up on the Every because of lack of support. I am still using the original Nano which I would recommend if there is enough code space on it. Be careful if you are near the maximum code space. It will appear to compile and run, but then starts to do crazy things after a while.

I am now using the ESP8266 (ESP-12F) It is costs less than the Nano and has built in WiFi. The libraries allow you to "publish" and "subscribe" to an MQTT broker. The downside is that it uses much more power than the Nano, but has a sleep state that works well. Voltage 3.0V ~ 3.6V

Good luck on your project!

OSD

Thanks you all for the support.

Looks much more complex than i was expecting. I will keep using the delay() function as long as it works on a sector power supply :stuck_out_tongue_winking_eye:

Regards,
Louis

@OldSurferDude @lto

Merci d'utiliser , dans les échanges, la langue française sur ce forum !

@al1fch

The thread referenced a question that I had and I am very interested in a solution.

That said,

J'aimerais pouvoir lire, parler et écrire le français, mais mes efforts, notamment en rédaction technique, sont loin d'être suffisants. C'est pourquoi j'utilise les services de traduction de Google. Même là, avec mon français très faible, je constate que la traduction n'est pas exacte. Par conséquent, je recommande d’écrire dans la langue dans laquelle on est le meilleur, puis de laisser le lecteur effectuer la traduction.

Quelle que soit la langue, j'aime apprendre et partager le peu de connaissances que je possède. J'espère sincèrement que nous continuerons à communiquer.

cordialement

OSD

Avec plaisir !!
ici en français ou en anglais dans la bonne section du forum anglophone !

je recommande d’écrire dans la langue dans laquelle on est le meilleur, puis de laisser le lecteur effectuer la traduction.

Ceci ne correspond pas au fonctionnement de ce forum francophone, ni d'ailleurs à celui des diverses sections linguistiques du forum Arduino. C'est au posteur de traduire dans la langue du forum pour que tous les visiteurs comprennent d'emblée de quoi il s'agit.

Un jour peut être une section 'Babel' du Forum Arduino hébergera des messages dans une multitude de langues et d'écritures qui vont avec.
Je doute dans ce cas de l'efficacité des échanges :wink:

Pour échanger en anglais avec @Ito ouvrez un fil de discussion dans la langue de votre choix sur le bon forum, , par exemple la section dédiée à la carte Nano Every pour le sujet évoqué ici

શુભ રાત્રી ... pardon .....Bonne soirée

Si la traduction ne semble pas fidèle, je suggère de mettre le texte original et la traduction.

If the translation does not seem accurate I propose to put both the original text and its translation

1 Like

Bonjour à tous,

Donc voilà, mon projet de portier de poulailler fonctionne bien avec une porte battante, entraînée par un servo.
Cela fonctionne depuis maintenant plusieurs mois sans problème, avec une alimentation secteur.

Voici le code actuel :

#include <Servo.h>

// --- CONSTANTS
// Validation constants
const long DELAY_CHECK = 900000; // The delay between each status check (ms) when not validated
const long DELAY_RECHECK = 180000; // The delay between each status check (ms) when validated
const int VALIDATIONS_NUMBER = 3; // Number of checks to be validated before moving the door

// LED  constants
const int LED = 9; // The pin the LED is attached to
const int LED_FADE_DELAY = 30; // Delay betwing each fading step
const int LED_FADE_STEP = 5; // Step for fading the LED
const int LED_BLINK_SHORT = 30; // Short blink duration
const int LED_BLINK_LONG = 850; // Long blink duration
const int LED_BLINK_MAX = 1000; // Max blink duration

// Servo constants
const int SERVO = 10; // The pin the servo is attached to
const int SERVO_MOVE_DELAY = 60; // Delay to move the door slowly

// Light sensor constants
const int LIGHT_SENSOR = A0; // The pin the light sensor is attached to
const int LIGHT_THRESHOLD_HIGH = 65; // Threshold for door opening
const int LIGHT_THRESHOLD_LOW = 30; // Threshold for door closing

// --- OBJECTS
Servo servoDoor;  // Servo for the door opening and closing

// --- VARIABLES
unsigned int iValidatedChecks; // The counter of validated checks
bool bStatus; // Door status : 0 = closed ; 1 = open
int iLightValue; // Value of the light sensor [0;800]

void setup() {
// --- DBG ---
//Serial.begin(9600);

  // Outputs
  pinMode(LED, OUTPUT); // Pin of the LED
  pinMode(SERVO, OUTPUT); // Pin of the LED
  servoDoor.attach(SERVO); // Pin of the servo

  // Inputs 
  pinMode(LIGHT_SENSOR, INPUT); // Pin of the light sensor

  // Variables initialization
  iValidatedChecks = 0;

  // Start by opening the door
  openDoor();
}

void loop() {
  // LED fading : cycle start
  fadeLed(LED, 1);

  // Get the light value
  iLightValue = analogRead(A0);

// --- DBG --- indicate light value away from computer
//int iLightValueC = (int)(iLightValue / 100);
//int iLightValueD = (int)((iLightValue - 100 * iLightValueC) / 10);
//int iLightValueI = iLightValue - 100 * iLightValueC - 10 * iLightValueD;
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueC);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueD);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueI);
//blinkLed(LED, LED_BLINK_LONG, 2);

  // If the door is closed
  if (bStatus == 0) {
    // If the light is upper than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue > LIGHT_THRESHOLD_HIGH) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, open the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      openDoor();
      iValidatedChecks = 0;
    }
  }

  // If the door is open
  else if (bStatus == 1) {
    // If the light is lower than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue < LIGHT_THRESHOLD_LOW) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, close the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      closeDoor();
      iValidatedChecks = 0;
    }
  }

// --- DBG ---
//String sDbg = "Luminosité : " + String(iLightValue) + "\nEtat : " + String(bStatus) + "\nContrôles validés : " + String(iValidatedChecks) + "\n";
//Serial.println(sDbg);

  // Delay before next status check
  if (iValidatedChecks > 0) delay(DELAY_RECHECK);
  else delay(DELAY_CHECK);
}

void fadeLed(int iLed, int iFadeNumber){
  for (int iIncrement = 1; iIncrement <= iFadeNumber; iIncrement++) {
    for (int iLedFadeBrihtness = 0; iLedFadeBrihtness <=255; iLedFadeBrihtness += LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }

    for (int iLedFadeBrihtness = 255; iLedFadeBrihtness >=0; iLedFadeBrihtness -= LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }
  }
}

void blinkLed(int iLed, int iDelay, int iBlinkNumber) {
  for (int iIncrement = 1; iIncrement <= iBlinkNumber; iIncrement++) {
    digitalWrite(iLed, LOW);
    delay(LED_BLINK_MAX - iDelay);
    digitalWrite(iLed, HIGH);
    delay(iDelay);
  }
  digitalWrite(iLed, LOW);
  delay(LED_BLINK_MAX - iDelay);
}

void openDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 0; iAngle <=180; iAngle ++){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 1;
}

void closeDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 180; iAngle >=0; iAngle --){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 0;
}

Il me faudrait maintenant supprimer la rallonge qui traîne par terre, et j'ai installé un panneau solaire avec un régulateur et une batterie.
Je pensais avoir dimensionné largement mon installation, par rapport à un courant mesuré de l'ordre de 40 mA. Mais au bout de quelques jours, la batterie est à plat. La charge se fait bien en journée, mais je perds un peu de tension chaque jour...
J'aimerais éviter de racheter panneau solaire et batterie, pour au final arriver à un coût d'installation démesuré.

Il me faut maintenant trouver un moyen de réduire largement ma consommation. Et donc j'en reviens à ce post que j'avais initié lorsque j'en étais au début de mon projet. Mon idée : lorsque la porte s'ouvre ou se ferme, il n'y a a priori pas besoin de faire quoi que ce soit avant 7 heures, et donc chaque mouvement de porte pourrait être suivi d'une mise en veille prolongée de 7 heures.

Le fait que je sois parti sur un Arduino Nano Every me prive des librairies habituelles pour ceci.
J'ai donc épluché le post proposé plus haut par al1fch : Help needed sleeping the Atmega4809 Arduino Nano Every
Mais je tombe soit sur des exemples basés sur des "interruptions" (je comprends que c'est pour un réveil "manuel", avec un bouton sur une broche), soit sur des exemples permettant de définir un délai, mais utilisant alors les librairies non disponibles avec mon atmega4809.
Et j'ai trouvé la librairie RocketScream_LowPowerAVRZero, mais je ne parviens pas à comprendre comment elle fonctionne avec un délai.

Je me fais peut-être des nœuds au cerveau avec ces histoires d'interruptions... Quelqu'un pourrait-il m'aiguiller sur la bonne voie ?

Merci,
Louis

EDIT :
J'ai trouvé cet exemple sur la librairie citée plus haut :

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>

/* Example on a 32-pin ATMega4808, LED on pin D7, using internal ULP OSC32K */
const uint8_t unusedPins[] = {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13,
                              14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
                              
void setup()
{
  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++)
  {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  /* true: external 32.768 kHz crystal */
  /* false: internal 32.768 kHz ULP oscillator */
  RTCAVRZero.begin(false);
  /* Time in seconds, true: repeat, false: once */
  RTCAVRZero.enableAlarm(5, true);
  RTCAVRZero.attachInterrupt(toggle);  
}

void loop()
{
  /* RTC works down to standby mode only. In power down, PIT is required */
  LowPower.standby();
}

void toggle(void)
{
  digitalWrite(LED_BUILTIN, CHANGE);
}

Je ne comprends pas à quoi servent ces commandes :

void setup()
{
[...]
  RTCAVRZero.attachInterrupt(toggle);  
}

[...]

void toggle(void)
{
  digitalWrite(LED_BUILTIN, CHANGE);
}

Ce serait une fonction à appeler au réveil ?

Cela sert à faire changer d'état la LED builtin à chaque réveil, autant dire que c'est inutile dans ton cas.

40mA c'est beaucoup, et ton panneau (dont tu ne dis rien) ne suffit peut être pas.
Je pense que mettre en veille l'ARDUINO ne suffira peut être pas. Le servo consomme quelques mA lui aussi.
Essaie de toutes façons la mise en veille et indique nous la consommation. Donne également plus de précisions :

  • panneau solaire
  • chargeur
  • etc.

Pour te donner un ordre d'idée, mon mécanisme de porte de poulailler consomme 1mA en veille, et se réveille toutes les 8 secondes. La consommation de 1mA est due principalement au module DS3231 que j'utilise (présence d'une EEPROM AT24C32).
La batterie de 2000mAH est rechargée par un panneau de 12V 4W, suivi d'un MP1584 5V et d'un TP4056.
Actuellement, après plusieurs jours de mauvais temps, ma batterie est à 85% de charge.
Il arrive qu'en février je tombe en panne de batterie.

1 Like

Merci pour toutes ces précisions.

En effet, je n'ai rien dit sur mon panneau et ma batterie.
Les 40 mA, c'est en pic, quand le servo est en mouvement. En général, je suis plutôt autour de 25 mA.

Pour dimensionner mon besoin, j'avais arrondi à 50 mA, soit soit 0,25 w.
J'avais ensuite considéré un rendement de mon panneau de 20% sur 3h par jour, soit un besoin de puissance de 10w.
Le panneau 12v que j'ai pris fait 20w en nominal, avec une batterie 12v et 8Ah. J'ai un petit régulateur de charge qui a un port USB et sur lequel je branche mon arduino.

Franchement, au niveau du panneau, je pense que c'est largement suffisant. C'est une bonne marque, ainsi que la batterie.
Je soupçonne mon régulateur de charge d'être aussi un peu gourmand, ce que je n'avais pas pris en compte. C'est une chinoiserie avec un affichage digital, que j'avais déjà en stock, et qui avait dû me coûter moins de 10€.

Et en effet, sous mes latitudes, le soleil n'est pas dingo...

Si j'arrive à mettre en place une mise en veille efficace, je pense que ça suffira.

Tu parles de la consommation du servo. En effet, j'avais pris un sevo assez puissant pour manœuvrer la porte...
Ceci me fait poser une question à laquelle je n'avais pas pensé : quel sera l'impact d'une mise en veille sur le servo ?

Encore une question sur l'exemple de code :

  for (index = 0; index < sizeof(unusedPins); index++)
  {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

Ceci sert à désactiver les pins non utilisés ?
En veille ? hors veille ?

EDIT:
Voici le code revu que je pense mettre en place

#include <Servo.h>

//****************************************************************************************************************
#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>

/* Example on a 32-pin ATMega4808, LED on pin D7, using internal ULP OSC32K */
const uint8_t unusedPins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
//****************************************************************************************************************

// --- CONSTANTS
// Validation constants
const long DELAY_CHECK = 900000; // The delay between each status check (ms) when not validated
const long DELAY_RECHECK = 180000; // The delay between each status check (ms) when validated
const int VALIDATIONS_NUMBER = 3; // Number of checks to be validated before moving the door

// LED  constants
const int LED = 9; // The pin the LED is attached to
const int LED_FADE_DELAY = 30; // Delay betwing each fading step
const int LED_FADE_STEP = 5; // Step for fading the LED
const int LED_BLINK_SHORT = 30; // Short blink duration
const int LED_BLINK_LONG = 850; // Long blink duration
const int LED_BLINK_MAX = 1000; // Max blink duration

// Servo constants
const int SERVO = 10; // The pin the servo is attached to
const int SERVO_MOVE_DELAY = 60; // Delay to move the door slowly

// Light sensor constants
const int LIGHT_SENSOR = A0; // The pin the light sensor is attached to
const int LIGHT_THRESHOLD_HIGH = 65; // Threshold for door opening
const int LIGHT_THRESHOLD_LOW = 30; // Threshold for door closing

// --- OBJECTS
Servo servoDoor;  // Servo for the door opening and closing

// --- VARIABLES
unsigned int iValidatedChecks; // The counter of validated checks
bool bStatus; // Door status : 0 = closed ; 1 = open
int iLightValue; // Value of the light sensor [0;800]

void setup() {
// --- DBG ---
//Serial.begin(9600);

//****************************************************************************************************************
  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }
//****************************************************************************************************************

  // Outputs
  pinMode(LED, OUTPUT); // Pin of the LED
  pinMode(SERVO, OUTPUT); // Pin of the LED
  servoDoor.attach(SERVO); // Pin of the servo

  // Inputs 
  pinMode(LIGHT_SENSOR, INPUT); // Pin of the light sensor

  // Variables initialization
  iValidatedChecks = 0;

//****************************************************************************************************************
  /* true: external 32.768 kHz crystal */
  /* false: internal 32.768 kHz ULP oscillator */
  RTCAVRZero.begin(false);
  /* Time in seconds, true: repeat, false: once */
  RTCAVRZero.enableAlarm(DELAY_CHECK/1000, true);
//****************************************************************************************************************

  // Start by opening the door
  openDoor();
}

void loop() {
  // LED fading : cycle start
  fadeLed(LED, 1);

  // Get the light value
  iLightValue = analogRead(A0);

// --- DBG --- indicate light value away from computer
//int iLightValueC = (int)(iLightValue / 100);
//int iLightValueD = (int)((iLightValue - 100 * iLightValueC) / 10);
//int iLightValueI = iLightValue - 100 * iLightValueC - 10 * iLightValueD;
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueC);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueD);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueI);
//blinkLed(LED, LED_BLINK_LONG, 2);

  // If the door is closed
  if (bStatus == 0) {
    // If the light is upper than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue > LIGHT_THRESHOLD_HIGH) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, open the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      openDoor();
      iValidatedChecks = 0;
    }
  }

  // If the door is open
  else if (bStatus == 1) {
    // If the light is lower than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue < LIGHT_THRESHOLD_LOW) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, close the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      closeDoor();
      iValidatedChecks = 0;
    }
  }

// --- DBG ---
//String sDbg = "Luminosité : " + String(iLightValue) + "\nEtat : " + String(bStatus) + "\nContrôles validés : " + String(iValidatedChecks) + "\n";
//Serial.println(sDbg);

  // Delay before next status check
  if (iValidatedChecks > 0) delay(DELAY_RECHECK);
//  else delay(DELAY_CHECK);
//****************************************************************************************************************
  else LowPower.standby();
//****************************************************************************************************************
}

void fadeLed(int iLed, int iFadeNumber){
  for (int iIncrement = 1; iIncrement <= iFadeNumber; iIncrement++) {
    for (int iLedFadeBrihtness = 0; iLedFadeBrihtness <=255; iLedFadeBrihtness += LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }

    for (int iLedFadeBrihtness = 255; iLedFadeBrihtness >=0; iLedFadeBrihtness -= LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }
  }
}

void blinkLed(int iLed, int iDelay, int iBlinkNumber) {
  for (int iIncrement = 1; iIncrement <= iBlinkNumber; iIncrement++) {
    digitalWrite(iLed, LOW);
    delay(LED_BLINK_MAX - iDelay);
    digitalWrite(iLed, HIGH);
    delay(iDelay);
  }
  digitalWrite(iLed, LOW);
  delay(LED_BLINK_MAX - iDelay);
}

void openDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 0; iAngle <=180; iAngle ++){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 1;
}

void closeDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 180; iAngle >=0; iAngle --){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 0;
}

Il va falloir que je démonte mon poulailler pour tester...

La doc est très limitée, mais oui probablement.

Ce serait un bon point pour gagner quelques mA j'imagine.

Merci en tout cas pour ton aide, je vais tester cela pendant les vacances.

I used Google translate to read your post. I share your frustration as I bought an Arduino every thinking that it would be a simple upgrade from the nano. It is a different processor so things work differently.

If you look in this post Help needed sleeping the Atmega4809 Arduino Nano Every - #2 by 6v6gt you will find a comment by 6v6gt about how to do a "binary chop". Start with the example and get that to work and then expand that example as you integrate it into your code.

Rest of luck

OSD

Merci OSD,
--- translation below ---

Le principe de cet exemple, si je le comprends bien, c'est de faire autant de veilles de 8 secondes que nécessaire, c'est bien ça ? Pourquoi ne peut-on pas mettre plus de 8 secondes par veille ?

Je vais tester les 2 solutions (la librairie RocketScream_LowPowerAVRZero couplée à RocketScream_RTCAVRZero d'une part, et cet exemple de 6v6gt d'autre part), mesurer les consommations dans les 2 cas et garder le meilleur. Je vous tiendrai au courant des résultats.

The basis principle of this example is to perform as much sleeps of 8 seconds as necessary, correct ?
Why not setting more than 8 seconds per sleep ? Is it a technical restriction (var size) ?

I will test both solutions (RocketScream_LowPowerAVRZero and RocketScream_RTCAVRZero libraries one one hand, and this example from 6v6gt on the other), measure the real current on both sides, and keep the best one of them. I'll let you know the results.

Regards,
Louis

Oui pour le principe
8s est la plus grande valeur de temporisation du Chien de garde (Watchdog) utilisé pour les temps élémentaires du deepsleep des ATmega328 (cf Figure2 du document suivant)

Si l'ATMega4809 hérite du 'Timer de Watchdog' des ATMega328 le 'temps élémentaire' de sommeil profond est également 8s

Bonjour à tous,
Et bonne année !

J'ai donc testé 2 solutions :

  1. Solution basée sur les librairies RocketScream_LowPowerAVRZero.h et RocketScream_RTCAVRZero.h :
    • mise en veille de l'arduino pendant 15 minutes entre chaque contrôle de luminosité
    • désactivation de tous les pins non utilisés
  2. Solution basée sur l'exemple proposée par OldSurferDude.
    • mise en veille de l'arduino pendant 15 minutes par cycles de 8 secondes entre chaque contrôle de luminosité

Je pense en fait que la solution 1 s'appuie sur les mêmes fonctionnalités de base que la 2 pour la partie mise en veille.
Je mets les codes plus bas.

Avant cela, j'ai refait convenablement (avec un multimètre, au lieu de me fier à la conso affichée par ma source de tension) les mesures de consommation. En effet, je ne comprenais pas pourquoi mon panneau ne suffisait pas malgré toutes les marges prises pour son dimensionnement.

Résultat :

  • Lorsque le servo est en mouvement : 60mA
  • Servo au "repos" : 45 mA

Je pense que cette énorme conso par rapport à d'autres retours d'expérience est due au servo. En effet, même au repos, il compense le moindre mouvement...

Voici les consommations mesurées :

  1. Solution 1
    • Servo en mouvement : 50 mA
    • Servo au repos et mise en veille pour 15 minutes : 25 mA
  2. Solution 2
    • Servo en mouvement : 60 mA
    • Servo au repos et mise en veille pour 15 minutes : 35 mA

Mon interprétation :

  • La désactivation des pins fait gagner 10 mA
  • La mise en veille fait gagner 10 mA
  • Ma conso élevée est due à l'utilisation d'une servomoteur, et je ne reviendrai pas dessus, donc je dois faire avec.

Les conséquences :

  • positif : ma batterie tient maintenant la charge et sa tension augmente chaque jour malgré le temps pas terrible
  • négatif : la mise en veille de l'arduino entraîne l'arrêt de la commande du servomoteur, et le moindre coup de vent referme ma porte... Je ne sais pas s'il est possible de mettre en veille tout en maintenant l'état d'une broche en sortie, mais ça m'étonnerait... S'il y a une solution (peut-être hardware ?), je suis intéressé
  • je vais donc tester en mettant simplement en place la désactivation des pins inutilisés, et voir si ça suffit à limiter suffisamment la consommation...

Les codes :

  1. Solution 1 :
#include <Servo.h>

// ***********************************   Optim Conso   ***********************************
#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>

// Example on a 32-pin ATMega4808
//const uint8_t unusedPins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};

// A0 --> Light sensor
// 9 --> LED
// 10 --> Servo
const uint8_t unusedPins[] = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};

// --- DBG ---
// 25 --> Serial output
//const uint8_t unusedPins[] = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
// *********************************   Optim Conso End   *********************************

// --- CONSTANTS
// Validation constants
const long DELAY_CHECK = 1200000; // The delay between each status check (ms) when not validated
const long DELAY_RECHECK = 120000; // The delay between each status check (ms) when validated
const int VALIDATIONS_NUMBER = 3; // Number of checks to be validated before moving the door

// LED  constants
const int LED = 9; // The pin the LED is attached to
const int LED_FADE_DELAY = 30; // Delay betwing each fading step
const int LED_FADE_STEP = 5; // Step for fading the LED
const int LED_BLINK_SHORT = 30; // Short blink duration
const int LED_BLINK_LONG = 850; // Long blink duration
const int LED_BLINK_MAX = 1000; // Max blink duration

// Servo constants
const int SERVO = 10; // The pin the servo is attached to
const int SERVO_MOVE_DELAY = 60; // Delay to move the door slowly

// Light sensor constants
const int LIGHT_SENSOR = A0; // The pin the light sensor is attached to
const int LIGHT_THRESHOLD_HIGH = 65; // Threshold for door opening
const int LIGHT_THRESHOLD_LOW = 30; // Threshold for door closing

// --- OBJECTS
Servo servoDoor;  // Servo for the door opening and closing

// --- VARIABLES
unsigned int iValidatedChecks; // The counter of validated checks
bool bStatus; // Door status : 0 = closed ; 1 = open
int iLightValue; // Value of the light sensor [0;800]

void setup() {
// --- DBG ---
//Serial.begin(9600);

// ***********************************   Optim Conso   ***********************************
  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }
// *********************************   Optim Conso End   *********************************

  // Outputs
  pinMode(LED, OUTPUT); // Pin of the LED
  pinMode(SERVO, OUTPUT); // Pin of the LED
  servoDoor.attach(SERVO); // Pin of the servo

  // Inputs 
  pinMode(LIGHT_SENSOR, INPUT); // Pin of the light sensor

  // Variables initialization
  iValidatedChecks = 0;

// ***********************************   Optim Conso   ***********************************
  /* true: external 32.768 kHz crystal */
  /* false: internal 32.768 kHz ULP oscillator */
  RTCAVRZero.begin(false);
  /* Time in seconds, true: repeat, false: once */
  RTCAVRZero.enableAlarm(DELAY_CHECK/1000, true);
// *********************************   Optim Conso End   *********************************

  // Start by opening the door
  openDoor();
}

void loop() {
  // LED fading : cycle start
  fadeLed(LED, 1);

  // Get the light value
  iLightValue = analogRead(A0);

// --- DBG --- indicate light value away from computer
//int iLightValueC = (int)(iLightValue / 100);
//int iLightValueD = (int)((iLightValue - 100 * iLightValueC) / 10);
//int iLightValueI = iLightValue - 100 * iLightValueC - 10 * iLightValueD;
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueC);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueD);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueI);
//blinkLed(LED, LED_BLINK_LONG, 2);

  // If the door is closed
  if (bStatus == 0) {
    // If the light is upper than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue > LIGHT_THRESHOLD_HIGH) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, open the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      openDoor();
      iValidatedChecks = 0;
    }
  }

  // If the door is open
  else if (bStatus == 1) {
    // If the light is lower than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue < LIGHT_THRESHOLD_LOW) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, close the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      closeDoor();
      iValidatedChecks = 0;
    }
  }

// --- DBG ---
// String sDbg = "Luminosité : " + String(iLightValue) + "\nEtat : " + String(bStatus) + "\nContrôles validés : " + String(iValidatedChecks) + "\n";
// Serial.println(sDbg); delay(1000); // For leting time to the Serial.println before LowPower.standby

  // Delay before next status check
  if (iValidatedChecks > 0) delay(DELAY_RECHECK);
// ***********************************   Optim Conso   ***********************************
//  else delay(DELAY_CHECK);
  else LowPower.standby();
// *********************************   Optim Conso End   *********************************
}

void fadeLed(int iLed, int iFadeNumber){
  for (int iIncrement = 1; iIncrement <= iFadeNumber; iIncrement++) {
    for (int iLedFadeBrihtness = 0; iLedFadeBrihtness <=255; iLedFadeBrihtness += LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }

    for (int iLedFadeBrihtness = 255; iLedFadeBrihtness >=0; iLedFadeBrihtness -= LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }
  }
}

void blinkLed(int iLed, int iDelay, int iBlinkNumber) {
  for (int iIncrement = 1; iIncrement <= iBlinkNumber; iIncrement++) {
    digitalWrite(iLed, LOW);
    delay(LED_BLINK_MAX - iDelay);
    digitalWrite(iLed, HIGH);
    delay(iDelay);
  }
  digitalWrite(iLed, LOW);
  delay(LED_BLINK_MAX - iDelay);
}

void openDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 0; iAngle <=180; iAngle ++){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 1;
}

void closeDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 180; iAngle >=0; iAngle --){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the door slowly
  }

  bStatus = 0;
}
  1. Solution 2 :
#include <Servo.h>

// ******************************   Optim Conso   ******************************
#include <avr/sleep.h>
// ****************************   Optim Conso End   ****************************

// --- CONSTANTS
// Validation constants
const long DELAY_CHECK = 1200000; // The delay between each status check (ms) when not validated
const long DELAY_RECHECK = 120000; // The delay between each status check (ms) when validated
const int VALIDATIONS_NUMBER = 3; // Number of checks to be validated before moving the door

// LED  constants
const int LED = 9; // The pin the LED is attached to
const int LED_FADE_DELAY = 30; // Delay betwing each fading step
const int LED_FADE_STEP = 5; // Step for fading the LED
const int LED_BLINK_SHORT = 30; // Short blink duration
const int LED_BLINK_LONG = 850; // Long blink duration
const int LED_BLINK_MAX = 1000; // Max blink duration

// Servo constants
const int SERVO = 10; // The pin the servo is attached to
const int SERVO_MOVE_DELAY = 60; // Delay to move the door slowly

// Light sensor constants
const int LIGHT_SENSOR = A0; // The pin the light sensor is attached to
const int LIGHT_THRESHOLD_HIGH = 65; // Threshold for door opening
const int LIGHT_THRESHOLD_LOW = 30; // Threshold for door closing

// --- OBJECTS
Servo servoDoor;  // Servo for the door opening and closing

// --- VARIABLES
unsigned int iValidatedChecks; // The counter of validated checks
bool bStatus; // Door status : 0 = closed ; 1 = open
int iLightValue; // Value of the light sensor [0;800]

void setup() {
// --- DBG ---
//Serial.begin(9600);

  // Outputs
  pinMode(LED, OUTPUT); // Pin of the LED
  pinMode(SERVO, OUTPUT); // Pin of the LED
  servoDoor.attach(SERVO); // Pin of the servo

  // Inputs 
  pinMode(LIGHT_SENSOR, INPUT); // Pin of the light sensor

// ******************************   Optim Conso   ******************************
  RTC_init();   
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // Set sleep mode to POWER DOWN mode 
  sleep_enable();                       // Enable sleep mode, but not going to sleep yet 
// ****************************   Optim Conso End   ****************************

  // Variables initialization
  iValidatedChecks = 0;

  // Start by opening the door
  openDoor();
}

void loop() {
  // LED fading : cycle start
  fadeLed(LED, 1);

  // Get the light value
  iLightValue = analogRead(A0);

// --- DBG --- indicate light value away from computer
//int iLightValueC = (int)(iLightValue / 100);
//int iLightValueD = (int)((iLightValue - 100 * iLightValueC) / 10);
//int iLightValueI = iLightValue - 100 * iLightValueC - 10 * iLightValueD;
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueC);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueD);
//blinkLed(LED, LED_BLINK_LONG, 2);
//blinkLed(LED, LED_BLINK_SHORT, iLightValueI);
//blinkLed(LED, LED_BLINK_LONG, 2);

  // If the door is closed
  if (bStatus == 0) {
    // If the light is upper than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue > LIGHT_THRESHOLD_HIGH) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, open the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      openDoor();
      iValidatedChecks = 0;
    }
  }

  // If the door is open
  else if (bStatus == 1) {
    // If the light is lower than the threshold, increment the number of validated checks. Othewise, set back the number of validated checks to 0
    if (iLightValue < LIGHT_THRESHOLD_LOW) iValidatedChecks++;
    else iValidatedChecks = 0;

    // Indicate the number of validated checks
    blinkLed(LED, LED_BLINK_SHORT, iValidatedChecks);

    // If the number of validated checks is sufficient, close the door
    if (iValidatedChecks == VALIDATIONS_NUMBER) {
      closeDoor();
      iValidatedChecks = 0;
    }
  }

// --- DBG ---
//String sDbg = "Luminosité : " + String(iLightValue) + "\nEtat : " + String(bStatus) + "\nContrôles validés : " + String(iValidatedChecks) + "\n";
//Serial.println(sDbg); delay(1000); // in order to let time to the Serial.println before the DeepSleep()

  // Delay before next status check
  if (iValidatedChecks > 0) delay(DELAY_RECHECK);
// ******************************   Optim Conso   ******************************
//  else delay(DELAY_CHECK);
  else DeepSleep();
// ****************************   Optim Conso End   ****************************
}

void fadeLed(int iLed, int iFadeNumber){
  for (int iIncrement = 1; iIncrement <= iFadeNumber; iIncrement++) {
    for (int iLedFadeBrihtness = 0; iLedFadeBrihtness <=255; iLedFadeBrihtness += LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }

    for (int iLedFadeBrihtness = 255; iLedFadeBrihtness >=0; iLedFadeBrihtness -= LED_FADE_STEP) {
        analogWrite(iLed, iLedFadeBrihtness);
        delay(LED_FADE_DELAY);
      }
  }
}

void blinkLed(int iLed, int iDelay, int iBlinkNumber) {
  for (int iIncrement = 1; iIncrement <= iBlinkNumber; iIncrement++) {
    digitalWrite(iLed, LOW);
    delay(LED_BLINK_MAX - iDelay);
    digitalWrite(iLed, HIGH);
    delay(iDelay);
  }
  digitalWrite(iLed, LOW);
  delay(LED_BLINK_MAX - iDelay);
}

void openDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 0; iAngle <=180; iAngle ++){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the dorr slowly
  }

  bStatus = 1;
}

void closeDoor() {
  blinkLed(LED, LED_BLINK_LONG, 1);

  for (int iAngle = 180; iAngle >=0; iAngle --){
      servoDoor.write(iAngle);
      delay(SERVO_MOVE_DELAY); // Delay to move the dorr slowly
  }

  bStatus = 0;
}

// ******************************   Optim Conso   ******************************
void RTC_init(void)
{
  while (RTC.STATUS > 0) ;    /* Wait for all register to be synchronized */
 
  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;        // Run low power oscillator (OSCULP32K) at 1024Hz for long term sleep
  RTC.PITINTCTRL = RTC_PI_bm;              // PIT Interrupt: enabled */

  RTC.PITCTRLA = RTC_PERIOD_CYC8192_gc | RTC_PITEN_bm;     // Set period 8 seconds (see data sheet) and enable PIC                      
}

ISR(RTC_PIT_vect)
{
  RTC.PITINTFLAGS = RTC_PI_bm;          // Clear interrupt flag by writing '1' (required) 
}

void DeepSleep() {
  for (int iLoops = 1; iLoops <= DELAY_CHECK / 8000; iLoops++){
    sleep_cpu();
  }
}
// ****************************   Optim Conso End   ****************************

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.