[Non résolu] Conception d'un relai pour pompe de piscine, problème de conditions

Bonjour à tous,
En ces temps caniculaires, je désire faire plaisir à la famille et j'ai créé un petit système me permettant d'activer la pompe de ma piscine durant 2 minutes toutes les 30min afin de faire chauffer de l'eau dans un circuit de tuyaux et de réinjecter cette eau dans la piscine pour la faire chauffer.

J'ai donc créé une fonction toute bête qui déclenche un relai toutes les 30min.
Cependant, la nuit, ce système est inutile et il serait cool que la pompe fonctionne en continu pour qu'elle filtre l'eau plus efficacement.

J'ai alors créé une autre fonction me permettant de laisser la pompe allumée. C'est là que les choses se corsent. Je désire mettre un bouton pour pouvoir choisir entre les deux modes :

Mode 0 : Réchauffement
Mode 1 : Filtrage continu

Ce que je fais, c'est que je branche un bouton poussoir sur une des entrées avec une résistance pullup. Je check l'état de cette entrée en permanence. Lorsque je détecte un changement d'état, j'incrémente un compteur. Comme je n'ai besoin que de deux modes, je fais un modulo de 2 sur ce compteur. Si le modulo est de 0 (c'est-à-dire que le compteur a un nombre pair), j'enclenche le mode 0.Si le modulo est de 1, j’enclenche le mode1.

Sur le papier, cela ne me parait pas mauvais, mais lorsque j'écris mon code, je n'arrive pas à passer d'une fonction à l'autre. Que je sois dans le mode 1 ou dans le mode 0, c'est la même fonction qui s'enclenche...

J'ai également essayé en mettant la variable mode booléenne, mais rien n'y fait...

int InBouton;
int sortie;
int compteur; //compteur d'appuies
int mode; //mode, determine en fonction de la parite du compteur

void setup() {
  Serial.begin(9600);
  sortie=9;
  InBouton=10;
  pinMode(sortie, OUTPUT);
  pinMode(InBouton, INPUT_PULLUP);
  compteur = 0;
  mode = 0;

}

void loop() {
  
  boolean etat=digitalRead(InBouton);
  
  if(etat == 0)
  {
    compteur ++;
    Serial.print("Compteur ");
    Serial.println(compteur);
    
    //On regarde si le nombre de fois ou on a appuie est pair ou impaire
    mode = compteur % 2;
    
    Serial.print("Mode ");
    Serial.println(mode);  
    
    //Selon la partie, on met un mode ou l'autre
    if (mode = 0)
    {
     pompe_rechauffement();
     Serial.println("pompe_rechauffement");
    } 
    else
    {
      pompe_continu();
      Serial.println("pompe_continu");
    }
    delay(1000);
  }
}


void pompe_rechauffement() {
  digitalWrite(sortie, HIGH);
  delay(120000);
  digitalWrite(sortie,LOW);
  delay(1680000); 
}

void pompe_continu() {
  digitalWrite(sortie, HIGH);
}

J’espère ne pas trop avoir mis d'aberrations dans mon code, n'hésitez pas à me corriger !

Dans l'attente de vos conseils, merci beaucoup !

Bonjour,

Le problème se situe ici

   if (mode = 0)

Tu mets 0 dans mode au lieu de le tester, la comparaison c'est ==

   if (mode == 0)

Remarque: il faut que tu reorganises ton programme en utilisant millis() à la place de delay(), sinon pour être sûr de passer du mode 0 au mode 1 tu vas devoir appuyer sur le bouton pendant 32 minutes.

Bonjour,
Lorsque je rajoute un "=", le programme se bloque a partir du second appui. Dans le moniteur, j'ai :

Compteur 1
Mode 1
pompe_continu
Compteur 2
Mode 0

Edit : Après tests, c'est effectivement la fonction pompe_réchauffement qui gèle le programme. J'ai essayé de mettre la fonction millis, mais je ne peux pas lui entrer d'arguments.

millis() ne donne-t-il pas juste le temps depuis lequel l'arduino tourne ? Je veux effectivement pouvoir changer de mode immédiatement.

Il faut que tu enlève le traitement de la pompe du traitement de l'appui sur le bouton.

Quand tu appuies sur le bouton et que tu passes en mode réchauffement tu mémorises le temps de début du mode (mllis()).
Ensuite après le traitement du bouton
si mode 0
temps_courant = millis()
si temps_courant- temps_debut < duree_marche
alors mettre le moteur en marche
sinon si temps_courant- temps_debut < duree_marche+duree_arret
alors arrêter le moteur
sinon
réinitialiser le cycle -> mémoriser le nouveau temps_debut
sinon // mode 1
mettre le moteur en marche

Ton code est parfait, mais le delay que tu as mis à la fin de la fonction pompe_rechauffement dure 28 minutes, c'est ce qui te donne l'impression que le code s'arrête.
Voici une version nettoyée :

int InBouton = 10;
int sortie = 9;
int compteur = 0; //compteur d'appuies
int mode = 0; //mode, determine en fonction de la parite du compteur

void setup() {
  Serial.begin(9600);
  pinMode(sortie, OUTPUT);
  pinMode(InBouton, INPUT_PULLUP);
}

void loop() {
  boolean etat = digitalRead(InBouton);
  if (etat == 0)
  {
    compteur ++;
    Serial.print("Compteur "); Serial.println(compteur);
    //On regarde si le nombre de fois ou on a appuie est pair ou impaire
    mode = compteur % 2;
    Serial.print("Mode "); Serial.println(mode);
    //Selon la partie, on met un mode ou l'autre
    if (mode == 0)
    {
      Serial.println("pompe_rechauffement");
      pompe_rechauffement();
    }
    else
    {
      Serial.println("pompe_continu");
      pompe_continu();
    }
    delay(1000);
  }
}

void pompe_rechauffement() {
  digitalWrite(sortie, HIGH);
  delay(120000);    // 2 minutes
  digitalWrite(sortie, LOW);
  delay(1680000);   // 28 minutes !!!
}

void pompe_continu() {
  digitalWrite(sortie, HIGH);
}

J'ai juste mis les print avant les appels des fonctions. Si tu veux le tester, mets des delays plus courts (2000 ou 5000 par exemple). Lorsque tu auras validé ton code, tu remettras les bonnes valeurs.
Tu peux aussi jouer avec le LED de ton arduino (a priori la sortie 13) : tu l'allumes au début de la fonction qui te semble bloquer et tu l'éteins à la fin.

EDIT : Si ton problème est de passer d'un mode à l'autre pendant le fonctionnement de la pompe, alors la solution de kamill est la bonne.

Bonjour,
Je n'ai pas eu le temps de répondre avant.

J'ai essayé au mieux de suivre vos indications mais cela ne marche toujours pas. En effet, lorsque je passe au mode de réchauffement, le système se met en marche mais ne vérifié qu'une fois la condition. J'ai essayé avec un while, mais je n'ai jamais réussi...

int InBouton;
int sortie;
int compteur; //compteur d'appuies
int mode; //mode, determine en fonction de la parite du compteur
int temps_courant;
int duree_arret;
int duree_marche;
int temps_entree;


void setup() {
  Serial.begin(9600);
  sortie=9;
  InBouton=10;
  pinMode(sortie, OUTPUT);
  pinMode(InBouton, INPUT_PULLUP);
  compteur = 0;
  mode = 0;

  //Initialisation des temps de marche et d'arret
  duree_arret = 2000;//1680000; //28min
  duree_marche = 1000;//120000; //2min
}

void loop() {
  
  boolean etat=digitalRead(InBouton);
  
  if(etat == 0)
  {
    compteur ++;
    Serial.print("Compteur ");
    Serial.println(compteur);
    
    //On regarde si le nombre de fois ou on a appuie est pair ou impaire
    mode = compteur % 2;
    
    Serial.print("Mode ");
    Serial.println(mode);  
    
    //Selon la partie, on met un mode ou l'autre
    if (mode == 0)
    {
     Serial.println("pompe_rechauffement");
     temps_entree = millis(); // On prend le temps à l'entree dans la fonction
     pompe_rechauffement();
    } 
    else
    {
      Serial.println("pompe_continu");
      pompe_continu();
      
    }
    delay(1000);
  }
}


void pompe_rechauffement() {
  temps_courant = millis();
  if(temps_courant - temps_entree < duree_marche)
  {
    Serial.println("MARCHE");
    digitalWrite(sortie, HIGH); 
  }
  else if(temps_courant - temps_entree < duree_marche+duree_arret)
  {
    Serial.println("STOP");
    digitalWrite(sortie, LOW);
  }
  else
  {
    temps_entree = millis();
  }
  Serial.println("SORTIE DE IF");
}

void pompe_continu() {
  digitalWrite(sortie, HIGH);
}

Merci d'avance !

Bonjour,
voici une version vite fait sur le gaz

const byte InBouton = 10;
const byte sortie = 9;
const unsigned long debounceTime = 10; // temps d'anti-rebonds

byte oldSwitchState = HIGH;
byte rechauffe = 0;

int mode = 0; //mode

unsigned long duree_arret;
unsigned long duree_marche;
unsigned long temps_entree;
unsigned long switchPressTime;

void setup() {
  Serial.begin(9600);
  pinMode(sortie, OUTPUT);
  pinMode(InBouton, INPUT_PULLUP);
  //Initialisation des temps de marche et d'arret
  duree_arret = 10000;//1680000; //28min
  duree_marche = 5000;//120000; //2min
}

void loop() {
  byte switchState = digitalRead(InBouton);              //
  if (switchState != oldSwitchState) {                   //
    if (millis () - switchPressTime >= debounceTime) {   //  Anti-rebond du bouton
      switchPressTime = millis ();                       //
      oldSwitchState =  switchState;                     //
      if (switchState == LOW) {
        mode = !mode; // A chaque action sur le bouton inversion état mode (0 ou 1)
      }
    }
  }

  Serial.print("Mode ");
  Serial.println(mode);

  switch (mode) {
    case 0:
      digitalWrite(sortie, HIGH);      // mode par défaut pompe en continu
      Serial.println("Pompe continue");
      rechauffe = 0;
      break;
    case 1:
      if (rechauffe == 0) {            // mode pompe en réchauffement
        rechauffe = 1;
        temps_entree = millis();
      }
      break;
  }

  if (rechauffe == 1) {
    Serial.println("Pompe rechauffement");
    if (millis() - temps_entree < duree_marche) {
      Serial.println("MARCHE");
      digitalWrite(sortie, HIGH);
    }
    else if (millis() - temps_entree < duree_marche + duree_arret) {
      Serial.println("STOP");
      digitalWrite(sortie, LOW);
    }
    else {
      rechauffe = 0;
    }
  }

  delay(200); // tempo pour éviter de spammer la liaison série (à retirer si suppression des Serial.print)
}

Bonjour,
Merci beaucoup, c'est très gentil ! J'aimerai néanmoins savoir ce qui ne va pas dans mon code, merci

Une fonction n'est pas une boucle (sauf loop) il est donc normal que son contenu ne soit exécuté qu'une fois (sauf si on écrit une boucle à l'intérieur)

De plus temps_entree prend la valeur de millis() avant chaque appel de la fonction pompe_rechauffement, ce qui fait que temps_courant - temps_entree a toujours la même valeur (le temps d'éxecution du code jusqu'au test)

Il faut donc utiliser un "drapeau" qui indique le premier appel à la fonction (drapeau qui sera remis à zéro lorsque la condition de fin est remplie)

hello
je t'avais préparé ce code

/*but: 
 * pendant un temps"delai de chauffe",le soleil va chauffer l'eau qui se trouve dans un tuyau sur la pelouse
 * une fois l'eau estimée chaude, une electrovanne va devier le flux de la pompe vers le tuyau.
 * pendant un temps"delai de vidange",celui ci va vider l'eau chaude qu'il contient dans la piscine et se remplir d'eau froide.
 * puis on attends à nouveau que l'eau dans le tuyau soit chaude.
 * 
 * on part du principe que la pompe fonctionne en permanence.
 * un relais commande une electrovanne deux voies.
 * une voie vers la piscine qui sera donc en circuit fermé
 * une voie vers le tuyau sur la pelouse
 */

#define InBouton 10
//#define sortie 9
#define sortie 13 //pour debug
int compteur = 0; //compteur d'appuis
byte mode = 0; //mode, determine en fonction de la parite du compteur
unsigned long deb_vidange=0;
unsigned long deb_chauffe=0;

unsigned long delai_de_chauffe=10000;//l'eau chauffe dans le tuyau
unsigned long delai_de_vidange=5000;//l'eau retourne dans la piscine
boolean etat;
 #define ON  HIGH
 #define OFF  LOW

void setup() {
  Serial.begin(115200);
  pinMode(sortie, OUTPUT);
  pinMode(InBouton, INPUT_PULLUP);
  deb_vidange=millis();
  deb_chauffe=millis();
}

void loop() 
{
  etat=digitalRead(InBouton);delay(1000); 
  
  if(etat == 0)
  {
    compteur ++;
    Serial.print("Compteur ");Serial.println(compteur);
    //On regarde si le nombre de fois ou on a appuie est pair ou impaire
    mode = compteur % 2;
    Serial.print("Mode ");Serial.println(mode);  
    }
    switch (mode)
    {
    case 0:
           if ((millis()-deb_chauffe)<=delai_de_chauffe)//l'eau chauffe, donc on circule en attendant
           {
            deb_vidange=millis();Serial.print("  de l'eau froide est dans le tuyau, on attend qu elle chauffe depuis   ");Serial.print((millis()-deb_chauffe)/1000); Serial.print(" secondes"); 
            relais(OFF);Serial.println("  et l'eau_de la piscine circule_en_continu");
           }
           else
           {
           if ((millis()-deb_vidange)<=delai_de_vidange)
           {
            relais(ON);Serial.print("  l'eau chaude est en cours devacuation dans la piscine  ");Serial.print((millis()-deb_vidange)/1000);Serial.println(" secondes"); 
           }
           else
           {
            deb_chauffe=millis();Serial.println("  de l'eau froide est arrivee dans le tuyau, on recommence à chauffer"); 
            }
           }
    break;
    case 1:
            { 
              relais(OFF);
              Serial.println(" c'est la nuit l'eau_de la piscine circule_en_continu");
            }
    break;   
    } 
}    

void relais(int ON_OFF) 
{
  digitalWrite(sortie, ON_OFF);  
}

Je vois et je comprends mieux. Merci !

Merci pour ce second code, je vais également l'étudier afin de m'améliorer !