Remplacer Delay() par millis()

Bonjour et bonne année à tous,

J’ai utilisé un pro mini pour modifier une télécommande 433 Mhz sans fil qui à l’origine commute un relais à l’appui sur un unique bouton. Le relais décolle au relâché du bouton.
A partir de 30 m du récepteur, la commande est aléatoire et le relais se ferme et s’ouvre plusieurs fois sur une commande d’une durée de 2 secondes environ. Cela fonctionne ainsi jusqu’à une centaine de mètres, endroit ou je désire commander une pompe avec un appui pour marche et un autre appui pour arrêt.

Sur la carte récepteur, j’ai séparé la sortie du circuit intégré décodeur > pin2 du pro mini, du transistor commandant le relais > pin4. L’impulsion fait 5 v, donc compatible arduino.

C’est tout bête me direz-vous :wink:

En temps normal, le µp est endormie (consommation 3.5 mA).
J’ai prévu une mise en marche de la pompe au front montant de la première impulsion, suivi d’un verrouillage de l’entrée pendant 4 secondes. Le µp est sorti du mode veille en même temps.

La pompe reste en fonctionnement jusqu’au prochain appui sur le bouton de la télécommande. Ce qui arrête la pompe et retour en veille au bout de 5 secondes.

Pour simplifier le mode veille, j’utilise la librairie low-power

En cas de déclenchement involontaire, j’ai programmé un arrêt forcé avec millis() au bout de 10 mn

Par contre les temporisations de 4 et 5 secondes sont faites avec delay() que je n’arrive pas à modifier avec la commande millis().

Tout fonctionne mais je ne comprends pas comment, ni pourquoi j’ai du ajouter cette tempo de 5 secondes, sinon la mise en veille ne se fait pas après arrêt de la pompe.

#include "LowPower.h"

const byte interruptPin = 2;
const byte LED = 13;
const byte pomp = 4;
int etatPin2;
int actif = 0;
unsigned long temps1;// première impulsion de commande
unsigned long temps2;//

void pompOff() {
    digitalWrite (LED, 0);
    digitalWrite (pomp, 0);
    delay(5000);// doit être plus long que le délai de départ pompe.
    actif = 0;
    veille();
}
void wake () {
  // ne fait rien
}  // end of wake


void veille() {
  attachInterrupt(0, wake, HIGH);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  detachInterrupt(0);
}

void setup ()
{
  pinMode(LED, OUTPUT);
  pinMode(pomp, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite (interruptPin, HIGH);  // sinon se mets en veille sur front descendant
  veille();
}  // end of setup

void loop ()
{
  etatPin2 = digitalRead(interruptPin);
  if (etatPin2 == 1) {// frond montant
    //if (temps2 > 4000)pompOff(); // prochaine impulsion = arrêt pompe
    if (!actif) {// joué une fois pour mémoriser la première impulsion
      digitalWrite (LED, 1);
      digitalWrite (pomp, 1);
      temps1 = millis();
      actif = 1;
      delay(4000);
    }
   else pompOff();// nouvelle impulsion sur entrée après 4 secondes.
  }
  temps2 = millis() - temps1;
  if (temps2 > 600000) pompOff(); // arret forcé à 10 mn
} // end of loop

combien de temps la pin de la télécommande reste à HIGH sur l'entrée 2 ?

à la fin de setup() vous rentrez en veille et ne commencez la loop() que quand une interruption arrive. ça appelle wake() qui ne fait rien puis détache l'interruption et la loop() commence.

--> Du temps s'est écoulé entre l'interruption et l'arrivée dans la loop(), êtes vous toujours 100% sûr à ce moment là que la pin 2 est toujours HIGH?

en supposant que ce soit le cas vous rentrez dans le if et mettez actif à 1 et initialisez correctement temps1 puis attendez 4 secondes. --> est-ce suffisant pour que la pin 2 retombe à zéro? (que se passe-t-il si vous avez tenu la télécommande appuyée)

en supposant qu'elle était retombée à LOW, vous tournez dans la loop() soit tant que la télécommande n'est pas appuyée de nouveau, soit 600000ms (10 min). à ce moment là vous appelez pompOff()

Si vous aviez déclenché pompOff() en appuyant sur la télécommande et pas avec les 10 minutes, vous allez arrêter la pompe mais là encore vous n'êtes pas sûr de l'état de la pin 2 avant d'aller vous endormir. le

    delay(5000);// doit être plus long que le délai de départ pompe.

sert en fait d'attente active pour que le bouton de la télécommande soit relâché, sinon au moment même ou vous vous endormez la pin 2 et High et l'interruption se déclenche et vous vous réveillez.

à mon avis au lieu de faire un delay de x secondes vous feriez mieux d'attendre que la pin2 retombe à LOW avant de poursuivre et donc je mettrais un while (digitalRead(interruptPin) == LOW);à la place des 2 delay()


PS
• Utilisez un boolean plutôt qu'un int pour actif et utilisez true et false.
• De même préférez pour la lisibilité HIGH ou LOW pour les opération de digitalWrite / test sur digitalRead
• utilisez plutôt la notation 600000ul pour bien montrer que c'est un unsigned long

J-M-L:
combien de temps la pin de la télécommande reste à HIGH sur l'entrée 2 ?

Au moins 200 ms et au maximum 3 secondes.

je mettrais un

while (digitalRead(interruptPin) == LOW);

à la place des 2 delay()

J'ai besoin de verrouiller l'entrée au moins 3 secondes après le premier appui pour éviter les fausses commandes et remettre en veille après l'arrêt de la pompe.

Merci de vous être penché sur ma question, je vais continuer à réfléchir.

Vous pouvez alors conserver le délai à allumage - clairement pour celui de l'extinction à mon avis vous devez attendre le relâchement de la pin d'interruption

J'ai trouvé

#include "LowPower.h"

const byte interruptPin = 2;
const byte LED = 13;
const byte pomp = 4;
boolean etatPin2;
boolean etatPomp = 0; // etat pompe
boolean verrou = 0;// verrou entrée 2
unsigned long temps1;// première impulsion de commande
unsigned long temps2;//


void wake () {
  // ne fait rien
}  // end of wake


void veille() {
  attachInterrupt(0, wake, HIGH);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  detachInterrupt(0);
}

void setup ()
{
  pinMode(LED, OUTPUT);
  pinMode(pomp, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite (interruptPin, HIGH);  // sinon se mets en veille sur front descendant
  veille();
}  // end of setup

void loop ()
{
  etatPin2 = digitalRead(interruptPin);
 
 if (!verrou) {// entré 2 active
    if (etatPin2==1) {// première impulsion
      if (!etatPomp) {// pompe arrêtée
        digitalWrite (LED, 1);
        digitalWrite (pomp, 1);
        etatPomp=1;
      }
      else {
        digitalWrite (LED, 0);
        digitalWrite (pomp, 0);
        etatPomp=0;
      }
      temps1 = millis();
      verrou = 1;// verouille l'entrée
    }
  }

  temps2 = millis() - temps1;
 
 if (temps2 > 4000) {
    verrou = 0; // dévérouille l'entrée 2
    if(!etatPomp) veille();// besoin d'être retardée
  }

  if (temps2 > 600000) { // arret forcé à 10 mn
    digitalWrite (LED, 0);
    digitalWrite (pomp, 0);
    etatPomp = 0; 
    veille();
    verrou = 0;
  }
} // end of loop

Après la prise en compte du premier front montant de l'entrée, vérouillage 4 secondes.
L'ordre de mise en veille devant être retardé, je l'ai mis à 4 secondes également

J'ai pris l'habitude d'employer 0 et 1 pour High et LOW ou TRUE et FALSE, c'est plus simple et je n'ai plus de compte à rendre à un prof :wink: .

J'évite le while aussi, comme je suis distrait, un plantage est vite arrivé :wink:

Encore merci, J-L-M

L'ordre de mise en veille devant être retardé, je l'ai mis à 4 secondes également

oui mais en pratique le retard est jute dû au fait qu'il ne faut pas que la pin soit HIGH encore au moment où vous attachez l'interruption sinon elle déclenche! si vous tenez votre bouton de la télécommande appuyé plus de 4 secondes pour éteindre, je pense que votre code va bugger.

J'ai pris l'habitude d'employer 0 et 1 pour High et LOW ou TRUE et FALSE, c'est plus simple et je n'ai plus de compte à rendre à un prof :wink: .

:slight_smile: :slight_smile:

oui juste à vous même et jusqu'au jour où vous utiliserez un langage de programmation moins permissif qui n'autorise pas ce genre de choses. D'autre part un booléen est stocké sur un octet alors que votre variable actif était un int, donc 2 octets --> perte d'un peu de mémoire pour rien et complexification du binaire généré qui va travailler sur 16 bits au lieu de 8 (et vous êtes sur un processeur 8 bits).

donc c'est pas juste pour faire plaisir au prof, il y a une justification technique...

J-M-L:
si vous tenez votre bouton de la télécommande appuyé plus de 4 secondes pour éteindre, je pense que votre code va bugger.

Je comprends, mais seul le passage de low à high de l'entrée 2 est pris en compte dans mon dernier code (si je ne me trompe).

Mes cuves à eau de pluie sont dans une cave au fond de ma cour. La pompe remonte l'eau au jardin par 150 m de tuyau, pour remplir une petite cuve de 200 l. Comme la maison fait obstacle, à quelques cms près l'ordre de la télécommande ne passe pas, alors j'appuie tout en la déplaçant. La durée de commande est au maximum de 2 secondes. Dès que la pompe démarre ou s'arrête, le bruit s'entend au bout du tuyau.
Donc 4 secondes est une bonne sécurité, je pense.

D'autre part un booléen est stocké sur un octet alors que votre variable actif était un int, donc 2 octets --> perte d'un peu de mémoire pour rien et complexification du binaire généré qui va travailler sur 16 bits au lieu de 8 (et vous êtes sur un processeur 8 bits).

donc c'est pas juste pour faire plaisir au prof, il y a une justification technique...

Pour "boolean", je vous ai écouté :wink:

Il y a quelques années, j'aurais du faire un circuit monostable figé avec des composants. Aujourd'hui le pro mini permet de faire plein de choses beaucoup plus simplement et moins cher et sans consommer plus, si on le programme bien. :wink:

Si je mets la télécommande dans un boitier étanche , arrêter la pompe sur détection hard de cuve pleine n'est pas bien compliqué si il m'en vient l'utilité.

Je comprends, mais seul le passage de low à high de l'entrée 2 est pris en compte dans mon dernier code (si je ne me trompe).

  attachInterrupt(0, wake, HIGH);

cette ligne de code dit "dès que la pin 2 est HIGH, appeler l'interruption" - c'est vrai même si la pin est déjà HIGH au moment de l'appel.


OK sur les autres commentaires. :slight_smile:

Au fait, je n'ai rien contre les profs, c'est juste qu'à 65 balais, je ne vais plus retourner au boulot :wink:

Pompe arrêtée, entrée 2 à high maintenue : la pompe tourne et s'arrête à 4 secondes. Le circuit passe en veille au même moment et le reste aussi longtemps que l'entrée reste à high.
La consommation du circuit est même plus faible : 3,4 mA au lieu de 3.6 mA en temps normal.

Si je la passe à high maintenue alors que la pompe est en marche : elle s'arrête et le reste. La veille débute 4 secondes plus tard comme prévu et la consommation est également de 3.4 mA.

Pas de bug. :slight_smile: