[AIDE] Capteur 18B20 (module) plusieurs actions

Bonjour à tous !

Premiers post pour premiers pas en programmation :slight_smile:
Donc merci de me lire avec mes mots n'ayant, pour l'instant, pas tout assimilé.

J'ai donc un projet simple : Arrosage automatique

Matériel :

1 x ARDUINO R3
1 x Module capteur **18B20 **arduinosensors.nl - arduinosensors Resources and Information.
1 x Ecran LCD 16x2

Le VRAI projet :

  • Arroser une surface afin de la maintenir à 25°C

Le fonctionnement :

  • Enclenchement de l'arrosage lorsque <25°C et couper une fois atteinte.
  • Affichage sur LCD 16x2 en direct (température et action)

Mon souhait :

  • Lire en continue la température MÊME une fois l'arrosage enclenché (Relay; HIGH)

Maintenant voici mon problème :

Suivant le code ci-joint et comme je ne sais pas mettre plusieurs actions (je débute) et ce sont des bouts de codes pompés sur le net et un peu de moi (quand même :slight_smile: ...)
Je ne sais pas faire en sorte que le relais s’enclenche à <25°C et EN MÊME TEMPS que la lecture du capteur continue (ainsi que les actions d'affichage sur le LCD) ceci afin qu'une fois les >25°C, le relais coupe.

Suivant mon code (qui est loin d'être propre, j'en conviens) TOUT s'arrête lorsque le relais est sur HIGH.
Donc plus de lecture, plus de continuité sur le LCD etc... (enfin je pense car pas encore branché LCD).

en définitive mes actions sont BLOQUANTES et il me faut donc des NON BLOQUANTES (c'est bien ca ?)

J'ai un lien sympa sur le sujet : Multitâches
Mais comment l'intégrer dans mon code, si toutefois c'est bien la solution...

Ma demande peut vous paraître simple mais pour un débutant, c'a l'est moins.

En vous remerciant pour votre aide.

#include <OneWire.h> // Inclusion de la librairie OneWire
#define DS18B20 0x28     // Adresse 1-Wire du DS18B20
#define BROCHE_ONEWIRE A0 // Broche utilisée pour le bus 1-Wire

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 boolean unefois = false;
 boolean unefois1 = false;

OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds
//KY019 5V relay module
int relay = 7; // relay turns trigger signal - active high;

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp) {
  byte data[9], addr[8];
  // data : Données lues depuis le scratchpad
  // addr : adresse du module 1-Wire détecté

  if (!ds.search(addr)) { // Recherche un module 1-Wire
    ds.reset_search();    // Réinitialise la recherche de module
    return false;         // Retourne une erreur
  }

  if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
    return false;                        // Si le message est corrompu on retourne une erreur

  if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
    return false;         // Si ce n'est pas le cas on retourne une erreur

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20

  ds.write(0x44, 1);      // On lance une prise de mesure de température
  delay(800);             // Et on attend la fin de la mesure

  ds.reset();             // On reset le bus 1-Wire
  ds.select(addr);        // On sélectionne le DS18B20
  ds.write(0xBE);         // On envoie une demande de lecture du scratchpad

  for (byte i = 0; i < 9; i++) // On lit le scratchpad
    data[i] = ds.read();       // Et on stock les octets reçus

  // Calcul de la température en degré Celsius
  *temp = ((data[1] << 8) | data[0]) * 0.0625;

  // Pas d'erreur
  return true;
}

// setup()
void setup() {
  Serial.begin(9600); // Initialisation du port série
  lcd.begin(16, 2); //Taille LCD
  pinMode(12, OUTPUT); // LED VERTE
  pinMode(13, OUTPUT); // LED ROUGE
  pinMode(relay, OUTPUT); // Relais sortie
}

// loop()
void loop() {

  if(!unefois){
        //Affichage TEXTE (Nom du produit) une seule fois
    lcd.setCursor(0,0);
    lcd.print("  * X-Fresh *");
    lcd.setCursor(0,1);
    lcd.print(" Version : 1.0");
    delay(4000);
    lcd.clear();
    unefois = true;
  }
    
  if(!unefois1){
            //Affichage TEXTE (Démarrage) une seule fois
    lcd.setCursor(0,0);
    lcd.print("Bonjour !");
    lcd.setCursor(0,1);
    lcd.print("    Demarrage...");
    delay(1000);
    lcd.clear();
    unefois1 = true;
  }
  
  float temp;
  
  // Lit la température ambiante à ~1Hz
  if (getTemperature(&temp)) {

    // Affiche la température
    Serial.print("Temperature : ");
    Serial.print(temp);
    Serial.write(176); // caractère °
    Serial.write('C');
    Serial.println();
  }

  
 // Action au-dela de 25°C enclanche relais
  if (temp > 25) {

    lcd.setCursor(0,0);
    lcd.write("Arrosage actif");
    lcd.setCursor(0,1);
    lcd.print(temp); //Température mesurée réelle
    lcd.print(" C  [====]"); //Pompe enclenchée
    digitalWrite(12,LOW); //  VERTE ETEINTE
    digitalWrite(13,HIGH); //  ROUGE ALLUMEE
    digitalWrite(relay, HIGH); //  MOTEUR ALLUME
    delay(2000);


  }

  else {

    digitalWrite(relay, LOW); //  MOTEUR ETEINT
    digitalWrite(12, HIGH); // VERTE ALLUMEE
    digitalWrite(13, LOW); // ROUGE ETEINTE
    noTone(13);
  }
}

bonjour,
je ne pige pas trop

Le VRAI projet :

  • Arroser une surface afin de la maintenir à 25°C

Le fonctionnement :

  • Enclenchement de l'arrosage lorsque <25°C et couper une fois atteinte.

et dans ton code

if (temp > 25)

déjà au lieu de te faire chi.. avec des

if(!unefois)
*****
if(!unefois1)

si t veux afficher qu'une fois, tu mets le tout dans le setup
sans if(!unefois1) et if(!unefois)

après, tu peux mettre la fonction getTemperature dans un void à part
et faire l'affichage sur le lcd dedans

vire les delay aussi qui sont bloquant, pas besoin ou alors pour le ds18B20 un delay(500), ca lui suffira suivant la précision que tu désire

Bonjour,

La mesure de température se fait tout le temps. Il suffit que tu mettes aussi l'affichage de température dans le else final.
Tu peux enlever le delay(2000); La lecture de la température prend déjà un certain temps.

Merci pour votre aide.

infobarquee : erreur de ma part, je voulais dire >25°C !
Ok pour l'astuce, je mets tous dans le setup.

kamill : Ok pour l'astuce de mettre dans le else final.
Par contre si je vire le delay(2000) le relais ne s'enclenche jamais, en gros mon programme ne fonctionne pas.
Pourquoi ?

Quoiqu'il en soit je fais les essais entre 12h et 14h et je reviens donner les résultats

Encore merci.

Je ne sais pas si c'est la source du problème, mais dans ton programme tu testes si la valeur retournée par if getTemperature() est valide

if (getTemperature(&temp)) {

ce qui est bien.

Par contre si la température est invalide, tu fais quand même ton traitement, il faudrait faire le traitement uniquement si la température est valide.

Il y a autre chose qui me parait bizarre, la led verte utilise la même pin (12) que le lcd.

kamill:
Je ne sais pas si c'est la source du problème, mais dans ton programme tu testes si la valeur retournée par if getTemperature() est valide

if (getTemperature(&temp)) {

ce qui est bien.

Par contre si la température est invalide, tu fais quand même ton traitement, il faudrait faire le traitement uniquement si la température est valide.

Il y a autre chose qui me parait bizarre, la led verte utilise la même pin (12) que le lcd.

Je vais m'y pencher sérieusement en reprenant le code du début...
Effectivement la pin 12 (erreur de ma part) car j'ai modifié 10 fois le code en faisant des copier/coller...

Pour un débutant c'est assez compliqué.
Je prends d'ici et de là, j'essai d'assimiler les fonctions, un peu tout en même temps...

Je me sert de : Ce Site pour débuter...

Voyez que j'en suis au début !

Merci.

Bon j'ai éclairci le code, je met ici qu'à partir du void loop jusqu'à la fin :

void loop() {
  float temp;
  
  // Lit la température ambiante à ~1Hz
  if (getTemperature(&temp)) {

    // Affiche la température
    Serial.print("Temperature : ");
    Serial.print(temp);
    Serial.write(176); // caractère °
    Serial.write('C');
    Serial.println();
  }

  
 // Action au-dela de 25°C enclanche relais
  if (temp > 25) {

    lcd.setCursor(0,0);
    lcd.write("Arrosage actif");
    lcd.print(" C  [====]"); //Pompe enclenchée
    digitalWrite(8,LOW); //  VERTE ETEINTE
    digitalWrite(6,HIGH); //  ROUGE ALLUMEE
    digitalWrite(relay, HIGH); //  MOTEUR ALLUME

  }
  else {
    lcd.setCursor(0,0);
    lcd.write("Temperature");
    lcd.print(temp);
    lcd.print("        C "); //Pompe enclenchée
    digitalWrite(8,HIGH); //  VERTE ETEINTE
    digitalWrite(6,LOW); //  ROUGE ALLUMEE
    digitalWrite(relay, LOW); //  MOTEUR ALLUME
  }
  
}

Donc codé comme ca, résultat passé 25°C le relais ne fais que cliquer ON-OFF-ON-OFF-ON..........
Video : Clic Clac
Il clique à la même fréquence d'affichage de la température sur le moniteur série.

Donc si j'ajoute un delay genre (2000) il reste enclenché ce temps et ce coupe ensuite, pui se ré-enclenche si la température est toujours à + de 25° sinon non. (en gros j'allonge la fréquence de clignotement c'tout...)

Comment faire pour que le relais soit ON et le reste jusqu'à ce que la température descende en dessous de 25°C ?

Je sais que ca parait simple pour vous, moi j'apprends...

J'ai aussi du mal avec les void, je n'arrive pas à en créer, la base quoi.

Merci.

Dans ton programme, il n'y a pas d'affichage de la température dans le cas ou l'arrosage est actif. Il faut l'afficher dans tous les cas pour analyser ce qui se passe
Il faut que tu gère une hystéresis car dans le cas ou tu es environ à 25° tu vas basculer en permanence des que tu auras une variation de température de 1 millionième de degré (j'exagère un peu).

Super, merci beaucoup de ton aide.
Donc si j'ai bien compris, pour l'affichage en arrosage de la température dans le moniteur, je fais comme ceci :

void loop() {
  float temp;
  
  // Lit la température ambiante à ~1Hz
  if (getTemperature(&temp)) {

    // Affiche la température
    Serial.print("Temperature : ");
    Serial.print(temp);
    Serial.write(176); // caractère °
    Serial.write('C');
    Serial.println();
  }

  
 // Action au-dela de 25°C enclanche relais
  if (temp > 25) {

    lcd.setCursor(0,0);
    lcd.write("Arrosage actif");
    lcd.print(" C  [====]"); //Pompe enclenchée
    digitalWrite(8,LOW); //  VERTE ETEINTE
    digitalWrite(6,HIGH); //  ROUGE ALLUMEE
    digitalWrite(relay, HIGH); //  MOTEUR ALLUME
// Affiche la température
    Serial.print("Temperature : ");
    Serial.print(temp);
    Serial.write(176); // caractère °
    Serial.write('C');
    Serial.println();
  }
  else {
    lcd.setCursor(0,0);
    lcd.write("Temperature");
    lcd.print(temp);
    lcd.print("        C "); //Pompe enclenchée
    digitalWrite(8,HIGH); //  VERTE ALLUME
    digitalWrite(6,LOW); //  ROUGE ETEINTE
    digitalWrite(relay, LOW); //  MOTEUR ALLUME
  }
  
}

Par contre, pour l'hystéresis, je découvre le mot et avec une recherche rapide j'ai compris le principe.
Le plus long ca va être d'assimiler correctement et de coder... ce qui n'est pas gagné.

Mais quand tu parles d'une variation de température, tu veux dire que ce serai cette variation qui créée le clignotement du relais ? Car si c'était une variation de 25,00° à 24,99°C je comprendrais, mais la non.

Merci.

Tu es sur que ton programme donne un affichage exploitable?
Affiches la température de manière similaire dans les 2 cas

 // Action au-dela de 25°C enclanche relais
 if (temp > 25) {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage actif  ");
   lcd.setCursor(0, 1);
   lcd.print(temp); //Température mesurée réelle
   lcd.print(" C  [====]"); //Pompe enclenchée

   digitalWrite(8, LOW); //  VERTE ETEINTE
   digitalWrite(6, HIGH); //  ROUGE ALLUMEE
   digitalWrite(relay, HIGH); //  MOTEUR ALLUME
 }
 else {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage inactif");
   lcd.setCursor(0, 1);
   lcd.print(temp); //Température mesurée réelle
   lcd.print(" C        "); //Pompe aretée

   digitalWrite(relay, LOW); //  MOTEUR ETEINT
   digitalWrite(8, HIGH); // VERTE ALLUMEE
   digitalWrite(6, LOW); // ROUGE ETEINTE
 }

Ensuite d'après ton programme si le relais bagotte c'est FORCEMENT pars ce que la température varie.
Ou alors tu utilises aussi la pin relais pour autre chose.

Et bien... pour l'affichage correct je ne sais pas, je n'ai pas encore branché l'écran.

Ce serai un autre problème une fois le clignotement réglé.
Et puis je l'ai remis pour répondre à

kamill:
Dans ton programme, il n'y a pas d'affichage de la température dans le cas ou l'arrosage est actif. Il faut l'afficher dans tous les cas pour analyser ce qui se passe...

Donc je ne dois visiblement pas le mettre là ?
-> Tu parles de l'affichage sur le LCD ou le moniteur série ?

Pour le Relais, sur le code il n'y à que le pin 7 utilisé pour lui et physiquement sur la carte, si tu regardes la vidéo : IDEM uniquement le relais connecté dessus.

Petit à petit j'avance, doucement mais surement. Mais si toutefois quelqu'un peut tester le code sur une carte ? Honnêtement je vois pas pourquoi il clignote...

Afin de me rassurer, peux-tu me confirmer que lorsque l'ont ne mets pas de : delay(xxxx) il est censé resté ON ?

De la même manière si je met

digitalWrite(8, HIGH);

Elle dois rester HIGH ?

Merci.

Je parles de l'affichage sur la moniteur série le lcd.
Oui les sorties doivent rester à l'état ou on les a commander.

Essaies avec un hysteresis de 0.5° comme ceci

 float temp;

 // Lit la température ambiante à ~1Hz
 if (getTemperature(&temp)) {

   // Affiche la température
   Serial.print("Temperature : ");
   Serial.print(temp);
   Serial.write(176); // caractère °
   Serial.write('C');
   Serial.println();
 }
 // Action au-dela de 25°C enclanche relais
 const float consigne=25;
 const float hysteresis=0.5;

 lcd.setCursor(0, 1);
 lcd.print(temp); //Température mesurée réelle
 lcd.print(" C");
 
 if (temp >= consigne+hysteresis) {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage actif  ");

   digitalWrite(8, LOW); //  VERTE ETEINTE
   digitalWrite(6, HIGH); //  ROUGE ALLUMEE
   digitalWrite(relay, HIGH); //  MOTEUR ALLUME
 }
 if (temp <= consigne+hysteresis) {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage inactif");

   digitalWrite(relay, LOW); //  MOTEUR ETEINT
   digitalWrite(8, HIGH); // VERTE ALLUMEE
   digitalWrite(6, LOW); // ROUGE ETEINTE
 }

Merci kamill.

J'ai donc remplacer ta partie de code et le problème reste le même.
La seule différence c'est qu'il déclenche à partir de 25,50°C au lieu de 25°C

J'ai aussi essayer de retirer le delay(800); dans la partie lecture du capteur et le relais clac a une fréquence de folie, je dirais 30 ou 40 fois à la seconde :confused:

Donc toujours le même problème, le relais ne reste pas HIGH.

J'ai donc remarqué, et ca confirme bien, qu'en définitive il réagi comme s'il était synchronisé à la commande de lecture du capteur :o

Relais : LOW -> Lecture du capteur si température >25 = Relais : HIGH....
et ca recommence... tous ca en 30 - 40 fois à la seconde...

Alors une première idée me vient, une méthode brute j'en convient, mais je me dis qu'après tout si le résultat est celui désiré, pourquoi pas mettre un condensateur de lissage aux bornes du relais, pour compenser et enlever ce clicclac ?

Biensur j'aimerai trouver la vraie solution puisque visiblement ce n'est pas normal :frowning:

En te remerciant de m'aider une fois de plus.

C'est hallucinant ton histoire!
Essaie de changer la pin du relais

il me semble que l’hystérésis n'est pas bien utilisé

if (temp >= consigne+hysteresis) {
  ...
   digitalWrite(relay, HIGH); //  MOTEUR ALLUME
 }
 if (temp <= consigne+hysteresis) {
   ...
   digitalWrite(relay, LOW); //  MOTEUR ETEINT
   ...
 }

on a une mitraillette lorsque la mesure = consigne + hystérésis
il faudrait mettre
if (temp <= consigne) { ...

Bonjour;

JE viens de prendre le sujet a la volé !
Pour mettre au claire sur L'hystérésis

L'hystérésis est une plage de fonctionnement qui définit deux seuils d’état fonctionnement = MARCHE et ARRÊT.
Pour une consigne de température à 25° = Mise en fonction d'un système X. => Définir une consigne d’arrêt du système X à 21°. ++> Cela nous donne un hystérésis de 4°.

Petit question ?

Pourquoi utilise tu la broche A0 pour la lecture de ton capteur 18B20?

La méthode de lecture de ton 18b20 me semble étrange.

// Fonction récupérant la température depuis le DS18B20
// Retourne true si tout va bien, ou false en cas d'erreur
boolean getTemperature(float *temp) {
byte data[9], addr[8];

Peut importe de contrôler le capteur en lui même car un code CRC permet déjà de savoir si la transmission de com est bonne. Et en plus le capteur peut être paramétré pour des seuil de température d'alarme et envoyer un code de défaut.

Comme tu fait des effort de programmation par toi meme voici ce que je te propose.
C'est une fonction pour la lecture de la sonde. Essais de comprendre le fonctionnement et de reprendre les variable a ton gout.
Note tu devra recrée tes propre variable ou utiliser celle qui sont présente.

/*Fonction de gestion des capteurs 18DSB20. */

void mesure() {

  //----- Déclaration des variables fonctionnel locale -----//
  byte data[12];// Tableau de 12 octets pour lecture des 9 registres de RAM et des 3 registres d'EEPROM du capteur One Wire
  const float offset = -2; //Correction de la température sur valeurs de réference.
  //-------------------------------------------------------//

  //----- Code d'instruction du capteur -----//
  while (capteur.search(adresse) == true) { //Contrôle de la présence des capteurs.
    const int lancerMesure = 0x44; //Code hexa.=> Datasheat => Initialise et lance une mesure de la température.
    const int modeLecture = 0xBE; //Code hexa.=> Datasheat => lecture des neuf registres (scratchpad) du capteur transmis après initialistion.

    //----- Lancer une mesure INITIALISATION. -----//
    capteur.reset();// initialise le bus 1-wire avant la communication avec un capteur donné.
    capteur.select(adresse);// sélectionne le capteur ayant l'adresse 64 bits contenue dans le tableau envoyé à la fonction.
    capteur.write(lancerMesure, 1); // lance la mesure et alimente le capteur par la broche de donnée.

    //----- Pause -----//
    delay(760);// au moins 750 ms 
    /*(+ il faudrait mettre une instruction capteur.depower ici, mais le reset va le faire)*/

    //----- Passer en mode LECTURE. -----//
    capteur.reset();// initialise le bus 1-wire avant la communication avec un capteur donné
    capteur.select(adresse);// sélectionne le capteur ayant l'adresse 64 bits contenue dans le tableau envoyé à la fonction
    capteur.write(modeLecture, 1); // passe en mode lecture de la RAM du capteur

    //----- Les 9 octets de la RAM (appelé Scratchpad) -----//
    for ( int i = 0; i < 9; i++) {// Decomposition des bits des 9 octets reçu.
      data[i] = capteur.read();// lecture de l'octet de rang i stocké dans tableau data
    }//for

    //----- Test de validité des valeurs reçues par contrôle du code CRC -----//
    /*le dernier (9ème) octet de la RAM est un code de contrôle CRC à l'aide de la fonction crc8 on peut vérifier si ce code est valide */
    if (capteur.crc8( data, 8) != data[8]) {
      //Serial.print("-!! CRC non valide !!-");//Validation du code CRC.
      break;
    }//if

    //----- Conversion de la valeur brut -----//
    int16_t brut = (data[1] << 8) | data[0];//"brut" retour valeur.
    brut = brut << 3;// 9 bit de resolution par defaut. => voir pour l'augmenter.(datasheet)
    float celcius = ((float)brut / 16.0) + offset;

    //----- Ecriture dans fichier -----//
    DataFichier.print(celcius);  DataFichier.print("; "); //Inscription de la valeur de température.
    //Serial.print("ecriture SD "); Serial.print(celcius); Serial.print(";"); // mesure + saut de ligne*/
    //Serial.print("mesure "); Serial.print(celcius); Serial.print(";");  // mesure + saut de ligne*/

  }//While
  //Serial.println();
}

Pour l’hystérésis je propose plutôt cela.
Je reprends ce que Kamil a fait et je retire l'hystérésis dans la condition de mise en service.

if (temp >= consigne) { //Conditionnement de mise en service.
   digitalWrite(relay, HIGH); // Marche pompe.
 }
 if (temp <= consigne+hysteresis) { //Conditionnement de mise hors service.
   digitalWrite(relay, LOW); // Arrêt pompe.
 }

rjnc38:
il me semble que l’hystérésis n'est pas bien utilisé

if (temp >= consigne+hysteresis) {

...
  digitalWrite(relay, HIGH); //  MOTEUR ALLUME
}
if (temp <= consigne+hysteresis) {
  ...
  digitalWrite(relay, LOW); //  MOTEUR ETEINT
  ...
}



on a une mitraillette lorsque la mesure = consigne + hystérésis
il faudrait mettre 
if (temp <= consigne) { ...

Bonjour les gens !

Déjà levé que je teste une nouvelle fois suivant vos consignes.
Voici donc le code modifié :

 const float consigne=25;
 const float hysteresis=0.5;

 lcd.setCursor(0, 1);
 lcd.print(temp); //Température mesurée réelle
 lcd.print(" C");
 
  if (temp >= consigne) {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage actif  ");

   digitalWrite(8, LOW); //  VERTE ETEINTE
   digitalWrite(6, HIGH); //  ROUGE ALLUMEE
   digitalWrite(relay, HIGH); //  MOTEUR ALLUME
 }
  if (temp <= consigne) {
   lcd.setCursor(0, 0);
   lcd.write("Arrosage inactif");

   digitalWrite(relay, LOW); //  MOTEUR ETEINT
   digitalWrite(8, HIGH); // VERTE ALLUMEE
   digitalWrite(6, LOW); // ROUGE ETEINTE
 }

Verdict ?.................................... IDEM, aucun changement, sauf qu'il déclanche à 25,00°C pile poil comme avant, mais c'est tout :frowning:

Donc j'ai changé de pin > A5 (pour vraiment changer) mais pareil...
LA Pin 1 est inexploitable car toujours HIGH (mais je crois que c'est normal...)