Help code d'une jauge sur esp32 à adapter sur uno et shield tft

j'ai le code suivant qui fonctionne bien sur un xiao esp32s3 , il permet l'accès à une page html pour modifier les valeurs de remapage d'une jauge de citerne ou autre et les socker dans eeprom , très pratique pour les cuves avec des formes non linéaires , on peux entrer les valeurs de plusieurs paliers,
mais là j'en ai marre de batailler avec l'ADC des esp , c'est pourquoi je cherche à le faire tourner sur mon uno avec shield tft tactile ili9341 , si une ame charitable veux bien jeter un oeil....
voici le code avec page html et access point

#include <WiFi.h>
#include <WebServer.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
#include <ESPmDNS.h>
#include <Adafruit_ADS1X15.h>  // Inclure la bibliothèque ADS1115

const char *ssid = "jauge";
const char *password = "";

WebServer server(80);

const int maxValues = 10;
int numValues = 2;
int inValues[maxValues];
int outValues[maxValues];

const int windowSize = 50;
int sensorValues[windowSize];
int currentIndex = 0;
int runningTotal = 0;

LiquidCrystal_I2C lcd(0x27, 20, 4);

const int bufferSize = 600;
int remappedBuffer[bufferSize];
unsigned long previousMillis = 0;
float flowRate = 0.0;

bool simplifiedMode = false;

#define EEPROM_ADDR_MODE 100

Adafruit_ADS1115 ads;  // Déclaration de l'objet ADS1115

unsigned long wifiStartTime = 0;
bool wifiEnabled = true;

void loadValuesFromEEPROM() {
  EEPROM.get(0, numValues);
  for (int i = 0; i < numValues; i++) {
    EEPROM.get(sizeof(int) * (i + 1), inValues[i]);
    EEPROM.get(sizeof(int) * (i + 1 + numValues), outValues[i]);
  }
}

void saveValuesToEEPROM() {
  EEPROM.put(0, numValues);
  for (int i = 0; i < numValues; i++) {
    EEPROM.put(sizeof(int) * (i + 1), inValues[i]);
    EEPROM.put(sizeof(int) * (i + 1 + numValues), outValues[i]);
  }
  EEPROM.commit();
}

void handleRoot() {
  String html = "<!DOCTYPE html><html lang='fr'><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>Tableaux de valeurs de remappage</title><style>table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid black; padding: 8px; text-align: center; } th { background-color: #f2f2f2; } .submit-btns { text-align: center; margin-top: 10px; } .reset-btn { background-color: #ff6666; width: 25%; } .reset-btn:hover { background-color: #ff3333; } .save-btn { background-color: #66ff66; width: 72%; } .save-btn:hover { background-color: #33ff33; } input[type='text'] { width: 100%; box-sizing: border-box; } </style></head><body><h1>Tableaux de valeurs de remappage</h1><form action='/update' method='post'><label for='numValues'>Nombre de valeurs (numValues): </label><input type='number' id='numValues' name='numValues' value='" + String(numValues) + "' min='1' max='10'><br><br><table><tr><th>Index</th><th>Entrée</th><th>Sortie</th></tr>";
  for (int i = 0; i < numValues; i++) {
    html += "<tr><td>" + String(i) + "</td><td><input type='text' name='entrée" + String(i) + "' value='" + String(inValues[i]) + "'></td><td><input type='text' name='sortie" + String(i) + "' value='" + String(outValues[i]) + "'></td></tr>";
  }
  html += "</table><div class='submit-btns'><form action='/reset' method='post' style='display: inline-block; margin-right: 10px;'><input type='submit' value='Reset EEPROM' class='reset-btn'></form><input type='submit' value='Save' class='save-btn'></div></form>";

  // Ajout des boutons pour choisir entre l'affichage complet et l'affichage simplifié
  html += "<br><br><button id='btnNormal' onclick='updateDisplayMode(\"normal\");' style='background-color: ";
  html += (simplifiedMode) ? "#FFFFFF" : "#4CAF50";  // Couleur verte pour le mode normal
  html += "'>Affichage complet</button>";
  html += "<button id='btnSimplified' onclick='updateDisplayMode(\"simplified\");' style='background-color: ";
  html += (simplifiedMode) ? "#4CAF50" : "#FFFFFF";  // Couleur verte pour le mode simplifié
  html += "'>Affichage simplifié</button><br><br>";

  // Script JavaScript pour envoyer les mises à jour de l'état du bouton au serveur
  html += "<script>function updateDisplayMode(mode) { var xhr = new XMLHttpRequest(); xhr.open('GET', '/display-mode?mode=' + mode); xhr.send(); document.getElementById('btnNormal').style.backgroundColor = (mode === 'normal') ? '#4CAF50' : '#FFFFFF'; document.getElementById('btnSimplified').style.backgroundColor = (mode === 'simplified') ? '#4CAF50' : '#FFFFFF'; }</script>";

  html += "</body></html>";

  server.send(200, "text/html", html);
}

void handleUpdate() {
  numValues = server.arg("numValues").toInt();
  for (int i = 0; i < numValues; i++) {
    inValues[i] = server.arg("entrée" + String(i)).toInt();
    outValues[i] = server.arg("sortie" + String(i)).toInt();
  }
  saveValuesToEEPROM();
  server.sendHeader("Location", "/");
  server.send(302, "text/plain", "");
}

void handleReset() {
  for (int i = 0; i < 512; i++) {
    EEPROM.write(i, 0);
  }
  EEPROM.commit();
  server.sendHeader("Location", "/");
  server.send(302, "text/plain", "");
}

void loadDisplayModeFromEEPROM() {
  // Chargement du mode d'affichage depuis l'EEPROM
  byte modeValue = EEPROM.read(EEPROM_ADDR_MODE);
  simplifiedMode = (modeValue == 1);
}

void handleDisplayMode() {
  String mode = server.arg("mode");
  if (mode == "simplified") {
    simplifiedMode = true;
  } else if (mode == "normal") {
    simplifiedMode = false;
  }
  EEPROM.write(EEPROM_ADDR_MODE, simplifiedMode ? 1 : 0); // Écrire le mode dans l'EEPROM
  EEPROM.commit();
  server.send(200, "text/plain", "");
}

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

  // Ajouter un délai pour permettre à la carte de s'initialiser correctement
  delay(2000);

  // Configuration du point d'accès WiFi
  Serial.println("Configuration du point d'accès...");
  WiFi.softAP(ssid, password);

  // Enregistrer l'heure de démarrage du WiFi
  wifiStartTime = millis();

  // Configuration statique IP (facultatif, mais peut aider)
  IPAddress local_ip(192,168,4,1);
  IPAddress gateway(192,168,4,1);
  IPAddress subnet(255,255,255,0);
  WiFi.softAPConfig(local_ip, gateway, subnet);

  // Vérification de l'état de la connexion WiFi
  if(WiFi.softAP(ssid, password)) {
    Serial.println("Point d'accès WiFi configuré avec succès.");
  } else {
    Serial.println("Erreur de configuration du point d'accès WiFi.");
  }

  EEPROM.begin(512);
  loadValuesFromEEPROM();
  loadDisplayModeFromEEPROM();

  if (!MDNS.begin("jauge")) {
    Serial.println("Erreur lors de l'initialisation mDNS");
    while (1);
  }
  MDNS.addService("http", "tcp", 80);

  server.on("/", handleRoot);
  server.on("/update", handleUpdate);
  server.on("/reset", handleReset);
  server.on("/display-mode", HTTP_GET, handleDisplayMode);
  server.begin();

  // Initialisation de l'écran LCD
  lcd.init();
  lcd.backlight();

  // Affichage "**jauge pulve**" sur la ligne 1 pendant 3 secondes
  lcd.setCursor(2, 1);
  lcd.print("**jauge pulve**");
  delay(3000);
  lcd.clear();

  // Initialisation de l'ADS1115
  ads.begin();  // Démarre la communication avec l'ADS1115
  ads.setGain(GAIN_TWOTHIRDS);  // Définit le gain à 2/3x +/- 6.144V
  //ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 0.125mV
 // ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV
  // Configurer le taux d'échantillonnage à 8 SPS
  ads.setDataRate(RATE_ADS1115_8SPS);

}

void updateFlowRate(int remappedValue) {
  for (int i = bufferSize - 1; i > 0; i--) {
    remappedBuffer[i] = remappedBuffer[i - 1];
  }
  remappedBuffer[0] = remappedValue;

  if (millis() - previousMillis >= 600000) {
    flowRate = float(remappedBuffer[bufferSize - 1] - remappedBuffer[0]) / 10;
    previousMillis = millis();
  }
}

float calculateFlowRate() {
  return flowRate;
}



void updateProgressBar(int sensorDiff) {
  int numBlocks = 0;
   // Calculer le nombre de blocs à afficher en fonction de la valeur absolue de sensorDiff
  sensorDiff = abs(sensorDiff);
  
  // Calculer le nombre de blocs à afficher en fonction de sensorDiff
  if (sensorDiff >= 0 && sensorDiff < 15000) {
    numBlocks = 1;
  }  if (sensorDiff >= 0 && sensorDiff < 11110) {
    numBlocks = 2;
  }  if (sensorDiff >= 0 && sensorDiff < 8228) {
    numBlocks = 3;
  }  if (sensorDiff >= 0 && sensorDiff < 6094) {
    numBlocks = 4;
  } if (sensorDiff >= 0 && sensorDiff < 4514) {
    numBlocks = 5;
  }  if (sensorDiff >= 0 && sensorDiff < 3343) {
    numBlocks = 6;
  }  if (sensorDiff >= 0 && sensorDiff < 2476) {
    numBlocks = 7;
  } if (sensorDiff >= 0 && sensorDiff < 1834) {
    numBlocks = 8;
  }  if (sensorDiff >= 0 && sensorDiff < 1358) {
    numBlocks = 9;
  }  if (sensorDiff >= 0 && sensorDiff < 1006) {
    numBlocks = 10;
  }  if (sensorDiff >= 0 && sensorDiff < 745) {
    numBlocks = 11;
  }  if (sensorDiff >= 0 && sensorDiff < 552) {
    numBlocks = 12;
  }  if (sensorDiff >= 0 && sensorDiff < 408) {
    numBlocks = 13;
  }  if (sensorDiff >= 0 && sensorDiff < 302) {
    numBlocks = 14;
  }  if (sensorDiff >= 0 && sensorDiff < 224) {
    numBlocks = 15;
  }  if (sensorDiff >= 0 && sensorDiff < 166) {
    numBlocks = 16;
  }  if (sensorDiff >= 0 && sensorDiff < 123) {
    numBlocks = 17;
  }  if (sensorDiff >= 0 && sensorDiff < 91) {
    numBlocks = 18;
  }  if (sensorDiff >= 0 && sensorDiff < 67) {
    numBlocks = 19;
  }  if (sensorDiff >= 0 && sensorDiff < 50) {
    numBlocks = 20;
  }

  // Afficher les blocs sur la ligne 3
  for (int i = 0; i < 20; i++) {
    lcd.setCursor(i, 3);
    if (i < numBlocks) {
      lcd.write(byte(255));  // Caractère rempli pour créer le bloc
    } else {
      lcd.write(' ');  // Espaces pour les blocs non utilisés
    }
  }
}











void loop() {
  static unsigned long chrono = 0;
  server.handleClient();

  // Désactiver l'AP après 5 minutes si aucun client ne s'est connecté
  if (wifiEnabled && millis() - wifiStartTime >= 300000) { // 300000 ms = 5 minutes
    if (WiFi.softAPgetStationNum() == 0) {
      Serial.println("Aucun client connecté. Désactivation du WiFi.");
      WiFi.softAPdisconnect(true);
      wifiEnabled = false;
    }
  }

  if (millis() - chrono >= 1000) {
    chrono = millis();

    // Lecture de la valeur analogique depuis AIN3 de l'ADS1115
   // int16_t adc3 = ads.readADC_SingleEnded(3);
    int16_t adc3 = ads.readADC_Differential_2_3();
    //float volts3 = ads.computeVolts(adc3);

    int sensorValue = adc3;

    runningTotal -= sensorValues[currentIndex];
    sensorValues[currentIndex] = sensorValue;
    runningTotal += sensorValue;
    int movingAverage = runningTotal / windowSize;

    int remappedValue = movingAverage;
    if (movingAverage <= inValues[0]) {
      remappedValue = outValues[0];
    } else if (movingAverage >= inValues[numValues - 1]) {
      remappedValue = outValues[numValues - 1];
    } else {
      for (int i = 0; i < numValues - 1; i++) {
        if (movingAverage >= inValues[i] && movingAverage <= inValues[i + 1]) {
          remappedValue = map(movingAverage, inValues[i], inValues[i + 1], outValues[i], outValues[i + 1]);
          break;
        }
      }
    }

    updateFlowRate(remappedValue);
    float currentFlowRate = calculateFlowRate();

    // Affichage des informations sur le port série
    Serial.print("Valeur brute : ");
    Serial.print(sensorValue);
    Serial.print(", Moyenne mobile : ");
    Serial.print(movingAverage);
    Serial.print(", Remappée : ");
    Serial.print(remappedValue);
    Serial.print(", Débit : ");
    Serial.println(currentFlowRate);

    // Affichage sur l'écran LCD
    lcd.clear();
    if (simplifiedMode) {
      lcd.setCursor(4, 1);
      lcd.print((int)round(remappedValue / 10.0) * 10);
      lcd.setCursor(9, 1);
      lcd.print("Litres");
      // Mettre à jour la barre de progression
      updateProgressBar(abs(sensorValue - movingAverage));

    } else {
      lcd.setCursor(0, 0);
      lcd.print("        ");
      lcd.setCursor(15, 3);
      lcd.print((int)round(remappedValue / 10.0) * 10);
      lcd.setCursor(14, 2);
      lcd.print("volume");

      lcd.setCursor(10, 0);
      if (currentFlowRate >= 10) {
        lcd.print(int(currentFlowRate));
      } else {
        lcd.print(currentFlowRate, 1);
      }
      lcd.setCursor(14, 0);
      lcd.print("l/mn");

      lcd.setCursor(0, 3);
      lcd.print("        ");
      lcd.setCursor(0, 3);
      lcd.print(movingAverage);
      lcd.setCursor(5, 3);
      lcd.print("lisse");

      lcd.setCursor(0, 1);
      lcd.print("        ");
      lcd.setCursor(0, 1);
      lcd.print(sensorValue);
      lcd.setCursor(5, 1);
      lcd.print("brut");
    }

    currentIndex = (currentIndex + 1) % windowSize;
  }
}

Pourquoi revenir en arrière avec une Uno dont l’ADC a aussi des problèmes, peu etre moins pénalisant que ceux de l’ESp mais réels ( bruyant) .

Pourquoi ne pas utiliser un petit module ADC spécialisé qui sera de bien meilleure qualité, pour 1 ou 2 €.
Il en existe en liaison I2C, il doit en exister en SPI.
Et garder l’essentiel du programme que tu as déjà écrit.

Je me pose la même question car on voit que le code semble utiliser un ADS1115

comme vous l'avez vu dans le code j'avais aussi testé avec un ads1115 , en i2c mais bcp de bruit aussi et en plus une derive dans le temps, et l'i2c semblait causer des problèmes à la connexion wifi, certe moins de bits avec un uno mais très stable , avec un petit lissage c'est amplement suffisant puis il est en 5v comme mon capteur de pression

par contre j'ai rencontré des problèmes pour stocker les valeurs dans le uno (eeprom) mais vu qu'il y a un emplacement sd sur le shield tft , je me dis qu'il y a possibilité, mais là ça me dépasse , pour creer les menus aussi, c'est pourquoi j'ai sollicité votre aide.

L'eeprom sur un microcontroleur a une durée de vie limitée en nombre d'enregistrement.

Il existe des eeprom en liaison I2C.

Attention au càblage entre l'ADC et le point à mesurer. Les fils signal et masse doivent être torsadés.
Super important : le fil de masse lié au fil signal ne doit pas servir de fil d'alimention.

Si le câblage n'est pas fait au petits oignons n'importe quel ADC même performant paraîtra bruyant.
Le câblage est un composant comme un autre.

Dans le cas de l'UNO le bruit est créé à l'intérieur de la carte circuit imprimé.
Un condensateur de 100 nF soudé au verso de la carte entre les pin du micro Aref et Gnd, il ne s'agit pas des pins de la carte mais de celle au verso du support, améliore fortement.

comme ceci entre gnd et aref ? il faut que j'utilise aref dans le code


aussi ?

apparemment il y a déjà un 100nF intégré dans le UNO

ou plutot ici d'après ce que j'ai vu dans un autre de tes post


mais là faut des mains de chirurgien

Oui il y a déjà un condensateur, mais en bord de carte, comme celui que tu as placé.
Il ne sert à rien la perturbation se fait après, dans la carte.
Ce condensateur doit être au plus près des pins du micro, c'est ce que j'ai écrit.

Note importante : je parlais d'une carte UNO pas d'un des nombreux clones.
La carte Uno originale utilise un atmega328P en boîtier DIP. Ce boitier est inséré dans un support aux pins traversantes.
Exemple :


Le condensateur est un CMS 0805, format idéal pour être soudé entre deux broches au pas de 2,54 mm.

La carte dont tu montres la photo du verso n'est pas une vraie UNO. A 99,99% elle incorpore à un atmega328P en boitier CMS.
Avec ce boitier CMS la possibilité d'ajouter un condensateur est quasi nulle.

Il faut surtout du matériel qu'un amateur ne possède pas.


oui ce modèle alors

Parfaitement.

J'ai édité mon message précédent.
Entre temps, j'ai retrouvé la photo du condensateur que j'avais prise.

Note : le format CMS est le meilleur, mais si tu n'as que le modèle de ta photo, c'est toujours jouable.
Mais avec des fils très courts !

je vais commander ce qu'il faut, mais je dois utiliser aref dans le code et connecter le 5v à aref ?

en fait, ce que j'aimerais savoir , c'est si l'ajout du condensateur va améliorer la stabilité de l'adc , même si je n'utilise pas aref dans le code.
j'ai vu que par défaut aref utilise le 5v de la carte, qui est suffisamment stable chez moi, 5.00 ou au pire 4.99

Aref est la référence de tension pour l’ADC. Si cette référence n’est stable ou si elle est bruitée, les mesures ne seront pas stables ou elle seront bruitées.

Je parle bien évidemment du Aref à l’intérieur de la puce micro, c’est désolant qu’Arduino ait semé la confusion en appelant Aref sa connectique de bord de carte.

Par défaut la référence de tension pour l’ADC est le Vcc du micro.
Si le micro est alimenté par l’USB Vcc fera 5V +/- 5% , ce qui est la norme de l’USB.
Si le micro est alimenté par le régulateur de tension Vcc sera égal a ce que donne le régulateur.

Pour etre indépendant du mode d’alimenttation on peut choisir de se servir d’une référence de tension de précision que l’on applique sur Aref bord de carte.
Ces références de tension ont des valeurs normalisées.

Une référence de tension ”du pauvre”, mais qui assure l’indépendance vis a vis de l’origine de la source d’alimention, est la sortie du régulateur 3,3 V interne aux cartes microcontroleur.

Ca c’était pour le côté stabilité de la tension de reference.

Le bruit :
La ”piste aref” est parallèle a des pistes numériques, au lieu de les croiser a angle droit, elle est même prise en sandwich.
Alors que si Aref avait été sorti par le bas de la carte, au lieu d’être sorti par le haut la polution aurait quasiment disparue.
Avec le plan de brochage Arduino Il se produira une pollution par diaphonie qui dépendra directement de l’activité du microcontroleur.

Dans le cas general l’activité du microcontrleur est non prédictive, elle est dite aléatoire.
Dans ce cas de figure un moyennage convient parfaitement pour ”nettoyer ” la mesure. Le moyennage impose quand même un retard et une charge au micro.

Si la pertubation est due a un phénomène récurent la perturbation ne sera plus aléatoire mais systématique, le moyenage ne peut plus supprimer le bruit, il peut juste diminuer son influence.
L’efficacité du moyennege dépendra de la bonne connaissance de la perturbation et des choix retenus pour configurer le moyenage.

Quelle différence alors entre moyenage et condensateur ?
En matière de rapidité et d’efficacité l’électronique pure surpasse la programmation.

Voilà, tu connais l’essentiel, tu peux faire TON propre choix.

ok , je vais essayer dans un premier tps de souder le condensateur sur le micro et laisser aref utiliser le vin qui est stable chez moi .

Euh, tu veux faire quoi avec Vin ?
Vin c'est l'entrée de la source de tension externe qui doit faire entre 7 et 12 V, 9V recommandé.
La stabilité, c'est le régulateur qui la donne.

Pour alimenter tu disposes de :

  • USB → 5 V ± 5%
  • Régulateur 5 V interne à la carte → alimenté par Vin

En tension de référence pour Aref tu disposes de :

  • Par construction, au démarrage du micro, Aref est relié à Vcc.
    Vcc peut provenir soit de l'USB, soit du régulateur interne.
  • Pin Aref. Tu peux y connecter une tension entre 1,1 V et Vcc.
    Un bon plan est d'y connecter la sortie du régulateur 3,3 V et bien sûr de limiter les tensions à mesurer inférieures à 3,3 V.
  • la référence interne de 1,1 V. Attention, elle est donnée à ± 10 %.

Question :
Tu veux améliorer parce que c'est nécessaire ou pour avoir le mieux sans savoir si ce que tu as convient ?
Je t'ai signalé cette possibilité de souder un condensateur parce que tu parlais d'une carte UNO et que sur la vraie carte UNO la modif du condensateur est très facile à faire.
Comme c'est facile, ce serait dommage de s'en passer.

Dans le cours de la discussion tu nous apprends que tu n'as pas une UNO mais un clone avec un micro en boîtier CMS.
Si j'avais eu connaissance de ce fait, je ne t'aurais pas proposé cette modification.

Souder un condensateur sur un boitier cms est une opération périlleuse, réfléchis bien avant d'opérer. As tu vraiment besoin de cette opération ?

Le principal conseil que j'ai reçu, jeune technicien qui voulait toujours améliorer son travail, est : "Le mieux est l'ennemi du bien".

désolé je voulais dire vcc , j'alimente la carte par vin avec un 9v stable et j'ai un 5v après le régulateur très stable (5.00 ou 4.99) ,
j'ai commandé la vraie uno et le condensateur que tu m'as conseillé , je vais pas me risqué à la soudure sur le CMS.
je ne vais pas utlisiser le 3.3 ou 1.1 car j'ai besoin de la pleine échelle pour mon capteur de pression 0-5v