Commande de pompe de recyclage en aquaponie

Bonjour à tous. J'ai 74 ans et Je débute avec Arduino-Uno.
J'ai fabriqué un système de bacs / bassin à poissons pour aquaponie avec un système à marée. Ça fonctionne. Mais je veux contrôler le cycle de marées avec un Arduino qui contrôle une pompe électrique de 5 m3 /Heure.
Voici le sketch qui présente un curieux défaut sur ma paillasse.
Le cycle se lance mais ente deux durées, il y a une commutation courte et aléatoire du relais . Je sèche la-dessus depuis deux mois! Si quelqu'un avait une idée?

/**
 * 
 * modifié pour etre remplacé par un relais avec transistor : etat 1: la pompe tourne
 * etat 0 la pompe s'arrete
 * 
 * 
 */

// Déclaration des variables globales

int pinPompe            = 4;     // Broche de sortie du signal de contrôle pompe
int bp                   = 2;     // Broche d'entrée du bouton poussoir
int duree                = 5;     // Nombre de sec pendant lesquelles la pompe va tourner pour un recyclage de l'eau : à adapter empiriquement selon la capacité du Bac (200l) et du débit pompe
unsigned long dureeCycle = 30; // Nombre de sec séparant 2 recyclages, équivaut ici à 1h, 3600 secondes 
// la pompe est remplacée provisoirement par une ampoule de 60 watt.   la duree et la durée cycle sont reduites pour le temps de la mise au point. La pompe fait 1Kw pour 4600l/heure

void setup() {

 pinMode(pinPompe, OUTPUT);
 pinMode(bp, INPUT);

    // L'interruption int.0 écoute la broche 2 de l'Arduino Uno

// Déclenche une interruption lorsque le signal bp est à l'état BAS (bouton poussoir appuyé)
    attachInterrupt(0, startPompe, HIGH);
// Initialise la commande Pompe
    digitalWrite(pinPompe, LOW);
}

/**
 * Boucle principale
 */
void loop() {
 
 digitalWrite(pinPompe, HIGH);

 attendre(duree);
 
 digitalWrite(pinPompe, LOW);

attendre(dureeCycle);
//

actionnePompe();

//
}


/**
 * * Pompage pendant la duree en millisecondes
 */
void actionnePompe()
{
 digitalWrite(pinPompe,HIGH);
 attendre(duree);
 digitalWrite(pinPompe,LOW); 
}






/**
 * Actionne la pompe et l'arrête si le bouton poussoir est relâché
 */
void startPompe()
{
       digitalWrite(pinPompe, LOW);
// Si on arrête d'appuyer sur le bouton
    if (digitalRead(bp) == LOW) {
        digitalWrite(pinPompe, HIGH);
    }
}

/**
 * Attendre n secondes
 * @param unsigned long duree : nombre de secondes à attendre
 * @return void
 */
void attendre(int duree)
{
    int loops;
    int count = 30;
int reste = (duree%count);

    loops = floor(duree/count);

   for (int i=0; i < loops; i++) {
      delay(count*1000);


    //  delay(duree);
   }

   delay(reste*1000);
}saisissez ou collez du code ici

:warning:
Post mis dans la mauvaise section, on parle anglais dans les forums généraux. déplacé vers le forum francophone.

Merci de prendre en compte les recommandations listées dans Les bonnes pratiques du Forum Francophone

Google translate:

A la fin de la fonction boucle, la fonction actionnePompe met la pompe en marche pendant un certain temps puis s'éteint. La fonction de boucle est ensuite appelée à nouveau et remet immédiatement la pompe en marche quelques microsecondes plus tard. C'est peut-être la raison pour laquelle vous voyez des effets étranges.

merci pour cette reponse!
toutefois, je ne vois pas comment corriger cela!

Je pense que tu n'as pas besoin d'une interruption pour gérer un bouton. Tu devrais écrire ton code comme une machine à états, il s'y prête bien.

Par contre, en lisant le code, j'ai du mal à voir l'enchainement des états et les causes de changements d'états. Peux-tu faire un schéma (sur papier) qui montre mieux ça ?

Par exemple, la loop fait :

 digitalWrite(pinPompe, HIGH);
 attendre(duree);
 digitalWrite(pinPompe, LOW);

puis elle fait
actionnePompe();
qui contient exactement les mêmes instructions : est-ce que tu veux le faire 2 fois de suite ?

Un schéma aiderait à mieux comprendre...

J'ai essayé ceci (mais j'ai peut-être mal compris les tâches du code) :

/**

   modifié pour etre remplacé par un relais avec transistor : etat 1: la pompe tourne
   etat 0 la pompe s'arrete


*/

// Déclaration des variables globales

int pinPompe             = 4;     // Broche de sortie du signal de contrôle pompe
int bp                   = 2;     // Broche d'entrée du bouton poussoir
unsigned long duree      = 5;     // Nombre de sec pendant lesquelles la pompe va tourner pour un recyclage de l'eau : à adapter empiriquement selon la capacité du Bac (200l) et du débit pompe
unsigned long dureeCycle = 30; // Nombre de sec séparant 2 recyclages, équivaut ici à 1h, 3600 secondes
// la pompe est remplacée provisoirement par une ampoule de 60 watt.   la duree et la durée cycle sont reduites pour le temps de la mise au point. La pompe fait 1Kw pour 4600l/heure
byte state = 0;
byte prevState;
unsigned long duration;
unsigned long chrono = 0;

void setup() {
  pinMode(pinPompe, OUTPUT);
  pinMode(bp, INPUT_PULLUP); // cablage : bp - bouton - GND
  // Initialise la commande Pompe
  digitalWrite(pinPompe, LOW);
  duration = duree;
}

/**
   Boucle principale
*/
void loop() {
  switch (state) {
    case 0: // Attente durée
      digitalWrite(pinPompe, HIGH);
      if (millis() - chrono > duration) {
        duration = dureeCycle;
        chrono = millis();
        state = 1;
      }
      if (digitalRead(bp) == LOW) {
        digitalWrite(pinPompe, LOW);
        prevState = 0;
        state = 2;
      }
      break;
    case 1: // Attente dureeCycle
      digitalWrite(pinPompe, LOW);
      if (millis() - chrono > duration) {
        duration = duree;
        chrono = millis();
        state = 0;
      }
      if (digitalRead(bp) == LOW) {
        digitalWrite(pinPompe, LOW);
        prevState = 1;
        state = 2;
      }
      break;
    case 2: // Attente bouton relâché
      if (digitalRead(bp) == HIGH) {
        digitalWrite(pinPompe, HIGH);
        state = prevState;
      }
      break;
  }
}

Pas compilé, pas testé...


voilà le chronogramme.... pendant thêta, la pompe tourne (en fonctionnement normal thêta devrait durer 30 minutes, l’opération se répète toutes les 6 heures, le temps du remplissage plus le temps du vidage par siphon automatique). l'interruption étant là pour l’amorçage initial de la pompe par adjonction d'eau en cas de désamorçage ou de mise en route initiale...

Ok, si je comprends bien, on a une période de 40 secondes pendant laquelle la pompe tourne 7 secondes et reste arrêtée 33 secondes. Et pendant cette période, on peut relancer la pompe en gardant le bouton appuyé (un certain temps).

Je pense que c'est ce que j'avais compris et tenté de programmer : j'ai mis 3 états

  • 0 : correspond aux 7 premières secondes (5 dans le code) pendant lesquelles la pompe tourne
  • 1 : les 33 autres secondes (30 dans le code) pendant lesquelles la pompe est arrêtée
  • 2 : on a appuyé sur le bouton, la pompe est lancée, et on attend que le bouton soit relâché.

Il y a juste une petite modification à faire (un LOW qui passe en HIGH) :

/**

   modifié pour etre remplacé par un relais avec transistor : etat 1: la pompe tourne
   etat 0 la pompe s'arrete


*/

// Déclaration des variables globales

int pinPompe             = 4;     // Broche de sortie du signal de contrôle pompe
int bp                   = 2;     // Broche d'entrée du bouton poussoir
unsigned long duree      = 7;     // Nombre de sec pendant lesquelles la pompe va tourner pour un recyclage de l'eau : à adapter empiriquement selon la capacité du Bac (200l) et du débit pompe
unsigned long dureeCycle = 33; // Nombre de sec séparant 2 recyclages, équivaut ici à 1h, 3600 secondes
// la pompe est remplacée provisoirement par une ampoule de 60 watt.   la duree et la durée cycle sont reduites pour le temps de la mise au point. La pompe fait 1Kw pour 4600l/heure
byte state = 0;
byte prevState;
unsigned long duration;
unsigned long chrono = 0;

void setup() {
  pinMode(pinPompe, OUTPUT);
  pinMode(bp, INPUT_PULLUP); // cablage : bp - bouton - GND
  // Initialise la commande Pompe
  digitalWrite(pinPompe, LOW);
  duration = duree;
}

/**
   Boucle principale
*/
void loop() {
  switch (state) {
    case 0: // Attente durée
      digitalWrite(pinPompe, HIGH);
      if (millis() - chrono > duration) {
        duration = dureeCycle;
        chrono = millis();
        state = 1;
      }
      if (digitalRead(bp) == LOW) {
//        digitalWrite(pinPompe, HIGH);
        prevState = 0;
        state = 2;
      }
      break;
    case 1: // Attente dureeCycle
      digitalWrite(pinPompe, LOW);
      if (millis() - chrono > duration) {
        duration = duree;
        chrono = millis();
        state = 0;
      }
      if (digitalRead(bp) == LOW) {
        digitalWrite(pinPompe, HIGH);
        prevState = 1;
        state = 2;
      }
      break;
    case 2: // Attente bouton relâché
      if (digitalRead(bp) == HIGH) {
        digitalWrite(pinPompe, LOW);
        state = prevState;
      }
      break;
  }
}

Les blocs case sont un peu longs, il faut peut-être les mettre entre accolades si ça ne fonctionne pas correctement.

bonsoir,
Merci pour votre attention et pour le sketch.
Pour le chronogramme, si j'ai mis des secondes (durée : 5 à 7 secondes(en fonction une trentaine de minutes!), périodicité 40 secondes (en fonction ce seront des heures jusqu'à 6 heures!) c'est pour essayer les boucles en me servant de la fonction "serial begin()" pour vérifier les durées car attendre jusqu'à 4 heures c'est perdre du temps! ces valeurs ont leur importance car les variables devront etre déclarées en "unsigned long" et pas en "integer"
bon, pour le sketch que vous proposez si il passe sans erreur à la compil, à l’exécution, on observe un bouclage très rapide. je ne trouve pas l'origine du problème...
donc je cherche et je teste encore et encore...

Au temps pour moi, tout est en millisecondes. Essaye de multiplier les valeurs par 1000 :

unsigned long duree      = 7000;     // Nombre de sec pendant lesquelles la pompe va tourner pour un recyclage de l'eau : à adapter empiriquement selon la capacité du Bac (200l) et du débit pompe
unsigned long dureeCycle = 33000; // Nombre de sec séparant 2 recyclages, équivaut ici à 1h, 3600 secondes

Bonjour!
Effectivement , il s'agit d'exprimer les valeurs durée et durée cycle en millisecondes!
Compil effectuée et binaire transféré , ça fonctionne comme prévu. Cependant, le bouton poussoir est sans effet: et Je ne voit pas bien pourquoi. Dans ma version avec l'utilisation d'une interruption , ça fonctionne. mais j'ai une commutation parasite dont je ne trouve pas l'origine....

(en fait ce sketch sur arduino est destiné à remplacer un minuteur 24h heures "theben timer" , lequel se programment par intervalles de 1/4 heure, ce qui convient pas))

As-tu bien câblé le bouton comme je l'ai indiqué en INPUT_PULLUP ?

Le circuit va de la pin 2 au bouton puis au GND

pas tout à fait comme ton câblage.
J'ai un inter à bascule à microswitch d'alternat radio (origine aéronautique). Point commun sur le 2 , point travail sur le ground, et l'autre repos sur un +. Ce qui fait que quand j'appuie dessus j'ai la mise de l'entréee 2 à la masse sinon on est au +.
J'ai remplacé par un fil dupont. et à la mise au ground de l'entrée 2 . Il y a une commutation mais avec une boucle du proghramme. Et la durée de commutation correspond à la durée de 7 secondes.
Ce n'est pas ce que je veux avoir car ce que je recherche c'est une commutation, tant que le contacts reste etabli. contact qui peut aller de 1seconde jusqu'à plusieurs minutes. ce que j'obtiens avec mon propre sketch avec la fonction interruption(0)

en faisant comme tu l'indiques, j'observe un très faible allumage de la led témoin du relais. le temps de commutation est trop faible pour exciter convenablement le relais

Désolé, mais je ne connais pas cet interrupteur. Mon code suppose un bouton poussoir : il détecte un appui sur le bouton poussoir et allume la led tant que le BP est enfoncé.

C'est ce qui est écrit dans ton code tout en haut :

Si l'inter fonctionne autrement, c'est normal que tu n'obtiennes pas ce que tu attends...

c'est équivalent! voici ce à quoi ça ressemble!
on appuie sur la palette dans le bon sens et le microswitch établit le contact tant que le doigt reste appuyé!
ce type d'interrupteur de tres haute qualité et peu courant est utilisé sur avions pour la radio , pour des intervallomètres pour photo aérienne, etc!

dans ce qui nous concerne, lors de l'appui, le contact entre le
et le ground fait apparaître un très faible allumage de la led du relais sans déclenchement de celui ci... problème de boucle, de temporisation ? de millis()? bref c'est pas ca! : ca devrait rester allumé tant que le contact reste etabli avant de repartir dans le cycle normal de service au relachement du contact!

Peux-tu vérifier avec un petit sketch tout simple si l'interrupteur renvoie bien LOW quand il est activé et HIGH sinon ?

pas de pb, le switch est ok!

Modifie comme ceci, ça peut venir d'un problème de rebond :smiley:

      if (digitalRead(bp) == LOW) {
        digitalWrite(pinPompe, HIGH);
        delay(30);
        prevState = 1;
        state = 2;
      }
      break;
    case 2: // Attente bouton relâché
      if (digitalRead(bp) == HIGH) {
        digitalWrite(pinPompe, LOW);
        delay(30);

Salut,
pas du tout convaincu! ce n'est pas une question de bruit du a un contact transitoire mais une question de bouclage sans prise de contrôle par appui sur un quelconque contact!
je pense que la solution initiale par utilisation d'une interruption est plus adaptée...