Optimisation de code

Bonjour,

J'ai trouvé sur le net un code pour effectuer une vérification de l'état de ma cuve (3500l) qui fonctionne très bien. Mais, le résultat est avec des leds. Je souhaite en fonction de l'état des entrées Analogiques mettre sur un ecran lcd le % de ma cuve.
voici mon code :

void loop() 

{       
    // Lecture et Affichage A0
    ADC_Val=analogRead(Level0Pin);
    Serial.print(ADC_Val);  Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level0LED);
    delay(100);
    
    // Lecture et Affichage A1
    ADC_Val=analogRead(Level1Pin);
    Serial.print(ADC_Val); Serial.print("\t");
    SetStateLevel(ADC_Val, Seuil_0, Level1LED);
    delay(100);

    // Lecture et Affichage A2
    ADC_Val=analogRead(Level2Pin);
    Serial.print(ADC_Val); Serial.print("\t"); 
    SetStateLevel(ADC_Val, Seuil_0, Level2LED);

    // Lecture et Affichage A3
    ADC_Val=analogRead(Level3Pin);
    Serial.print(ADC_Val); Serial.print("\t"); 
    SetStateLevel(ADC_Val, Seuil_0, Level3LED);
    delay(10000);
  int tab1 [4] {Level0LED, Level1LED, Level2LED, Level3LED}; 

}

void SetStateLevel(int ADCVal, int Seuil, int LED_Pin)

{

  
  if(ADCVal > Seuil)
    {
      digitalWrite(LED_Pin, HIGH);
    }
    else
    {
      digitalWrite(LED_Pin, LOW);
    }
  if(Level0LED == HIGH)
      {
      lcd.setCursor(0, 1);
      lcd.print("25%");
      }
  else if (Level1LED == 1)
     lcd.setCursor(0,1);
     lcd.print ("50%")
  

etc .... etc....
  {
  }
}

J'ai comme objectif de mettre beaucoup plus d'entrée Analogique pour avoir un relevé plus précis. Je trouve ça donc lourd comme code. Je pense donc qu'il y a un moyen plus simple de faire la meme chose.

Une idée svp ?

Merci

Ça dépend du nombre de capteurs que tu veux. Un Mega dispose de 16 entrées analogiques. Tu peux monter à 18 avec un ESP32.

Pour le code, tu dois utiliser des tableaux et des boucles for pour scruter toutes tes entrées

Quel est ton capteur ?
Permet-il de mesurer le niveau sur les 3500L ?

Peut être que peux mettre à l'échelle les données que tu reçois sur l'entrée analogique :

5/3500 = 0.001425... -> tension pour 1L.

(1/3500)*100 = 0.02857... -> % pour 1 L .

Et donc : valeurA0*((1/3500)*100)/(5/3500)= % de remplissage de la cuve.

En supposant que le niveau de remplissage de la cuve est linéaire...

Cela peut-il t'aider ?
Comme je ne connais pas ton matériel je suis peut-être a côté de la plaque.

En fait, j'ai un tuyau de en pvc avec 4 vis raccordées sur les entrées analogiques A0 A1 A2 et A3. Si A0 est dans l'eau la led 0 s'allume etc... via une valeur de seuil en fonctionne de la réistance de l'eau.

Pour plus de lisibilité, je veux rajouter un écran lcd. Avec 4 entrées anogique c'est simple:

si A0 up = 25%
si A0 et A1 up = 50%
si A0 et A2 et A2 = 75%
si A0 et A1 et A2 et A3 = 100%

On peut aussi mettre uniquement d'une entrée au final, vu que la position A3 et le plus haut, donc si A3 et HIGH le reste des positions le sont aussi logiquement! (cela fonctionne aussi avec A2 et A1!)

Mais je souhaite pour plus de précision mettre un arduino mega (16 analogiques) pour affiner au max. Ainsi je vais pouvoir mettre une vis tous les 2-3cm.

Mais la je trouve le code ultra lourd :
Si A0 = 6.25%
si A0 et A1= 12.5%
etc etc...

Je ne suis pas forcement super en code (pour le moment j'espere :slight_smile: ). C'est mon 1er projet. J'ai donc du mal à bien utilisé le "for"

Mais merci pour vos réponses!

D'accord je comprends mieux ton problème.

Je te propose une solution :

-Mettre les valeurs HIGH ou LOW dans un tableau comme tu l'as fait
-Parcourir le tableau pour vérifier a quel niveau on se trouve ( c'est la que la boucle for intervient ).
-> adapter la valeur en fonction des variables à HIGH dans le tableau

Pour cela :

int tab1 [16] {Level0LED, Level1LED, Level2LED, Level3LED,...,Level15LED}; 
float step = 6.25;
float level=0.0;

for (int i=0;i<tab1.length();i++){

if(tab1[i]==HIGH){
level=tab1[i+1]*step;
}

}

La boucle for va donc parcourir les variables du tableau une à une et vérifier leur état. Si on a un état HIGH on va multiplier le numéro de la variable (+1 car ça commence à 0) par 6.25.
La variable level va donc prendre la dernière valeur où il y a un HIGH. Il n'y a plus qu'a l'afficher.

C'est possible d'avoir un schéma du système ?

Je verrais bien un truc comme ça : pas besoin de tableau. Il suffit de compter les vis immergées. Si on suppose qu'une vis immergée renvoie un signal supérieur à un seuil donné (choisi ici à 127), il suffit de compter les pins qui renvoient une valeur supérieure à ce seuil.

const int NBPINSANA = 16; // Nombre de pins analogiques scannées
const byte seuil = 127; // Mettre ici la valeur du seuil de détection

void setup() {
  Serial.begin(115200);
}

void loop() {
  byte sum = 0;
  for (byte i = 0; i < NBPINSANA; i++) sum + = (analogRead(i) < seuil ? 0 : 1);
  float level = sum * 100.0 / NBPINSANA;
  Serial.print ("Niveau = ");
  Serial.print(level, 2);
  Serial.println("%");
}

Bien sûr, il faut estimer la valeur du seuil, mais ça ne doit pas être difficile à faire. Si la pin immergée renvoie un petit nombre, il faut changer le test en (analogRead(i) > seuil ? 0 : 1)

Note: selon le cas, il faudra prévoir un pull_up ou pull_down pour éviter de mesurer des valeurs sur des pins analogs "en l'air"

speedblood:
D'accord je comprends mieux ton problème.

Je te propose une solution :

-Mettre les valeurs HIGH ou LOW dans un tableau comme tu l'as fait
-Parcourir le tableau pour vérifier a quel niveau on se trouve ( c'est la que la boucle for intervient ).
-> adapter la valeur en fonction des variables à HIGH dans le tableau

Pour cela :

int tab1 [16] {Level0LED, Level1LED, Level2LED, Level3LED,...,Level15LED}; 

float step = 6.25;
float level=0.0;

for (int i=0;i<tab1.length();i++){

if(tab1[i]==HIGH){
level=tab1[i+1]*step;
}

}





La boucle for va donc parcourir les variables du tableau une à une et vérifier leur état. Si on a un état HIGH on va multiplier le numéro de la variable (+1 car ça commence à 0) par 6.25.
La variable level va donc prendre la dernière valeur où il y a un HIGH. Il n'y a plus qu'a l'afficher. 


C'est possible d'avoir un schéma du système ?

Pour le shéma voici ma source pour donner une idée : https://www.electronique-mixte.fr/microcontrolleurs/capteur-de-niveau-deau-avec-arduino/

Mais l'idée de récupérer l'état des pins avec les leds n'est pas utilise, elle était la surtout pour un contrôle visuel dans un 1er temps.

Il me faut juste l'état des pins analogiques avec le seuil :slight_smile:

lesept:
Je verrais bien un truc comme ça : pas besoin de tableau. Il suffit de compter les vis immergées. Si on suppose qu'une vis immergée renvoie un signal supérieur à un seuil donné (choisi ici à 127), il suffit de compter les pins qui renvoient une valeur supérieure à ce seuil.

const int NBPINSANA = 16; // Nombre de pins analogiques scannées

const byte seuil = 127; // Mettre ici la valeur du seuil de détection

void setup() {
  Serial.begin(115200);
}

void loop() {
  byte sum = 0;
  for (byte i = 0; i < NBPINSANA; i++) sum + = (analogRead(i) < seuil ? 0 : 1);
  float level = sum * 100.0 / NBPINSANA;
  Serial.print ("Niveau = ");
  Serial.print(level, 2);
  Serial.println("%");
}




Bien sûr, il faut estimer la valeur du seuil, mais ça ne doit pas être difficile à faire. Si la pin immergée renvoie un petit nombre, il faut changer le test en `(analogRead(i) > seuil ? 0 : 1)`

Note: selon le cas, il faudra prévoir un pull_up ou pull_down pour éviter de mesurer des valeurs sur des pins analogs "en l'air"

Merci ce code m’intéresse beaucoup :), je viens de le tester mais j'ai une erreur avec le "sum + = (analogRead...)

J'ai modifié avec juste un = mais j'ai l'état que d'une broche, j'ai un retour de 25% alors que j'ai bien les 4 broches à plus du seuil :frowning: voici mon code :

const int NBPINSANA = 4; // Nombre de pins analogiques scannées
const byte seuil = 800; // Mettre ici la valeur du seuil de détection
const int Level3Pin = A3;


void setup() {
Serial.begin(9600);
}

void loop() {
  byte sum = 0;
  int ADC_Val=0;
  for (byte i = 0; i < NBPINSANA; i++) sum  = (analogRead(i) < seuil ? 0 : 1);
  float level = sum * 100.0 / NBPINSANA;
  ADC_Val=analogRead(Level3Pin);
  Serial.print(ADC_Val); Serial.print("\n");
  Serial.print ("Niveau = ");
  Serial.print(level, 2);
  Serial.println("%");
  delay (1000);
}

Pour les tests, j'utilise que 4 broches (A0 à A3), et j'ai rajouté une lecture de l'état de la broche pour mettre le bon seuil :slight_smile:

Mes broches sont bien avec une résitance de pull_down pour qu'elles soient à 0

Il faut bien laisser +=
Au besoin fais
sum = sum + (analogRead...)

C'est bizarre qu'il y ait une erreur, peux-tu copier le message du compilateur en entier ?

Dans le code du post #5 il y a + = au lieu de += (sans espace)

sanstouf:
Pour le shéma voici ma source pour donner une idée : https://www.electronique-mixte.fr/microcontrolleurs/capteur-de-niveau-deau-avec-arduino/

Légèrement hors sujet, mais je pense que ce n'est pas une bonne idée de mettre la "tige du commun" directement au +5V. Cela va appliquer en permanence un courant entre les électrodes et cette tige ce qui n'est pas bon, même s'il est faible.
Je suggère de raccorder la tige du commun à un I/O et de la mettre HIGH avant chaque mesure et de la passer à LOW à la fin de la mesure. Ceci ne dispense pas d'utiliser une tige et des vis inox.

La référence arduino indique que le temps de lecture de l'ADC est de 100 microsecondes. Il faut peut-être ajouter un tout petit délai dans la boucle for pour lui laisser le temps de faire sa mesure.

for (byte i = 0; i < NBPINSANA; i++) {
   sum += (analogRead(i) < seuil ? 0 : 1);
   delay(1);
}

kamill:
Dans le code du post #5 il y a + = au lieu de += (sans espace)

Effectivement c'était ça merci !

fdufnews:
Légèrement hors sujet, mais je pense que ce n'est pas une bonne idée de mettre la "tige du commun" directement au +5V. Cela va appliquer en permanence un courant entre les électrodes et cette tige ce qui n'est pas bon, même s'il est faible.
Je suggère de raccorder la tige du commun à un I/O et de la mettre HIGH avant chaque mesure et de la passer à LOW à la fin de la mesure. Ceci ne dispense pas d'utiliser une tige et des vis inox.

Non pas hors sujet pour moi, c'est une bonne idée. J'avais eu aussi cette réflexion de l’oxydation dans le temps. La technique du I/O à 5v juste avant le test, et je vais faire un test uniquement toutes les x secondes ou minutes. Je ne sais pas si le "delay" à une valeur limite.

Merci je viens de tester mon code avec l'écran lcd.

Cela fonctionne nikel! La prochaine étape va etre d'envoyer les infos à Domoticz pour avoir une belle courbe et voir l'information de n'importe ou :slight_smile:

J'ai intégré une pin de commun (6) pour faire le test avec pour le moment un delay de 10s entre chaques tests.

const int NBPINSANA = 4; // Nombre de pins analogiques scannées
const byte seuil = 200; // Mettre ici la valeur du seuil de détection
const int Level3Pin = A3;  // Pin pour connaitre la valeur pour regler au mieux le seuil
const int Commun = 6;  // Pin du 5V pour eviter l'oxydation

//affichage
// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
    Serial.begin(9600);
    pinMode(Commun,OUTPUT);
    lcd.begin(16,2); // set up the LCD's number of columns and rows:
    lcd.print("La cuve est a:"); // Print a message to the LCD.
}

void loop() {
  digitalWrite(Commun, HIGH);
  byte sum = 0;
  int ADC_Val=0;
  for (byte i = 0; i < NBPINSANA; i++) sum  += (analogRead(i) < seuil ? 0 : 1);
  float level = sum * 100.0 / NBPINSANA;
  ADC_Val=analogRead(Level3Pin);
  Serial.print(ADC_Val); Serial.print("\n");
  Serial.print ("Niveau = ");
  Serial.print(level, 2);
  Serial.println("%");
  lcd.setCursor(6, 1);
  lcd.print(level);
  lcd.setCursor(12, 1);
  lcd.print ("%");
  delay (1000);
  digitalWrite(Commun, LOW);
  delay (10000);

Le délai d'une seconde à la fin est parfaitement inutile par contre ce serait peut-être mieux de le mettre après avoir fait le digitalWrite(Commun, HIGH); car le courant est faible le milieu moyennement conducteur et donc la tension à l'entrée de l'ADC risque de ne pas s'établir instantanément.

Autrement, je ne sais pas à quelle vitesse tu vides ou remplis ta cuve mais en 10s le niveau ne doit pas beaucoup changer si ton système fonctionne sur piles ou batteries tu dois pouvoir augmenter très largement ce temps et mettre le processeur en veille pour économiser l'énergie.

fdufnews:
Le délai d'une seconde à la fin est parfaitement inutile par contre ce serait peut-être mieux de le mettre après avoir fait le digitalWrite(Commun, HIGH); car le courant est faible le milieu moyennement conducteur et donc la tension à l'entrée de l'ADC risque de ne pas s'établir instantanément.

Autrement, je ne sais pas à quelle vitesse tu vides ou remplis ta cuve mais en 10s le niveau ne doit pas beaucoup changer si ton système fonctionne sur piles ou batteries tu dois pouvoir augmenter très largement ce temps et mettre le processeur en veille pour économiser l'énergie.

Effectivement pour le delay d'une seconde :wink:

Pour le temps de 10s il est juste la pour la forme, et faire mes tests plus facilement, quel est le temps maxi (s'il existe un temps maxi?!)

Tu parles de veille? c'est avec un delai assez gros, ou il existe vraiment une commande de vielle?