Calibrage sonde température deux fils - Arduino Nano thermomètre [Résolu]

Bonjour tout le monde,
J'ai récupéré il y a un moment une sonde de température à deux fils (noir et blanc) sans savoir quel est le modèle ni ses spécifications. Je ne sais donc rien du tout de ce capteur.

Ne sachant pas trop comment m'y prendre et après m'être un peu documenté je me suis dit que j'allais l'étalonner moi-même à l'aide de la sortie 5V de mon arduino nano, d'une résistance 10KOhm et d'un thermomètre trouvé dans la cuisine !

1. Le branchement de la sonde sur l'Arduino Nano :

En branchant la sonde sur le 5V de l'arduino et en comparant la tension de sortie avec la valeur du thermomètre, je me suis dit que j'allais trouver une formule qui allait calibrer la température en fonction de la tension de sortie du capteur, séparée de GND par une résistance 10KOhm:

Le fil blanc est celui de l'entrée de la sonde, le noir sa sortie. Le jaune connecte le pin A0 à la sortie du capteur et avant la résistance 10kOhm

Je ne sais pas du tout si ma méthode est bonne, je débute, tâtonne et je recherche la critique :sweat_smile:

2. Script d'acquisition

Pour pouvoir faire un graphique qui va corréler la tension enregistré par le pin A0 et la température que j'enregistre manuellement avec mon thermomètre, j'ai fait un petit script qui ressort les valeurs désirées et permet de construire son tableur.

J'ai laissé mes essais de formule de transformation de la tension en température pour mieux décrire mes péripéties :man_scientist:

 //On se branche sur le pin analogique 0
 int mesure = A0;

 void setup () {

  Serial.begin (9600);
  Serial.println("LABEL,Temps,Tension sortie (V), Valeur sortie (CAN), Temperature"); 
 }

void loop () {

  const int valeur = analogRead(mesure);
  // Calcul de la tension, division par 1024 car le pin renvoie un signal 0<1024
  const float tension = (valeur * 5.0) / 1024;

  //Test température
  const float TempTEST = 2.6961*sq(tension) + (9.4328*tension) - 16.68;  // Le polynôme de l'impossible !!

  //Test température2
  const float TempTEST2 = (23.768*tension)-33.247;  // La non SOLUTION (eq linéaire) ??!!
  
  // Suivi des données
  Serial.print(" Tension : ");
  Serial.print(tension);
  Serial.print(" V , Valeur A0 : ");
  Serial.print(valeur);
  Serial.print(" CAN , Température 1 : ");
  Serial.print(TempTEST);
  Serial.print("°C , Température 2 : ");
  Serial.print(TempTEST2);
  Serial.println("°C ,");

  // On attend 5 secondes entre chaque mesure
  delay(5000); 

}

3. L'étalonnage !

Après ça c'est parti ! Pour me lancer j'ai réaliser deux séries de mesure avec de l'eau chaude (de 60°C à 25°C) et froide avec un montage ultra sophistiqué comprenant un thermos et des pinces à linge :grinning:

Je les immerges dans l'eau car je me dis que c'est ma seule solution pour pouvoir mesurer une température à peu près constante et uniforme.

L'idée à partir de la est de réaliser un graphique dans Excel est de lui faire calculer la courbe de tendance qui me permettra de déduire la température de la tension. Car en effet on peut demander à excel de nous donner l'équation qui permet le calcul de cette courbe de tendance, pratique !

Au début je pensais que cette équation serait linéaire de type f(x)=155y+12, c'est ce que j'avais lu dans la plupart des autres tutos mais non ! La courbe n'est pas linéaire du tout. La solution est donc un polynôme de second degré, de type y = ax 2 + bx + c. ou Y est la température et X la tension.

Pour pouvoir déduire la température de la tension enregistré par le pin A0 je dois donc faire les opérations successives :
Calcul de la tension (je ne suis même pas vraiment sûr du pourquoi du comment de la division par 1024), puis résolution de l'équation donnée par Excel :

 const int valeur = analogRead(mesure);
  // Calcul de la tension, division par 1024 car le pin renvoie un signal 0<1024
  const float tension = (valeur * 5.0) / 1024;

  //Test température
  const float TempTEST = 2.6961*sq(tension) + (9.4328*tension) - 16.68;

Je n'ai pas encore pris les mesures du froid, le chaud met un moment avant d'aller à 25°C dans mon petit thermos mais jusque la je crois que j'avance bien !

Une photo de la sonde :

Après passage à l'eau froide (de 1°C à 17°C) j'ai finalement pu déduire la température du polynôme suivant :

Voila mon code :

  //Test température
  int puissance = 1.5451*pow(tension, 4);
  int puissance2 = 15.688*pow(tension, 3);
  const float TempTEST = puissance - puissance2 + 59.95*sq(tension) - (78.755*tension) + 30.943; 

Mais la je me dis que c'est trop compliqué je passe à côté d'un truc non ?

Sinon je pense que la sonde est plutôt précise sur l'intervalle 0°/60°C mais il me faudrait un meilleur élément de comparaison :sweat_smile:

Si la sonde est une thermistance sont équation est une exponentielle.
Ton approximation polynomiale est tout à fait adaptée.

Les sondes linéaires sont des composants électroniques dont la courbe à été "linéarisée" avec une circuiterie adaptée.

A l'ohmmètre à température ambiante (25 °C) tu trouves combien ?
Si c'est bien une thermistance ce devrait être une valeur proche de 10k ou de 5k ou de 1k qui sont les valeurs les plus courantes pour des thermistances.

1 Like

A 20K je trouve 253 ça le ferait ?

Le 17 août 2021: Petite mise à jour pour vous montrer le projet à peu près fini !

Le côté hardware est définitif :smile: :




En tout il y a donc un petit écran lcd 128*32, relié au nano sur une carte upesy double face plutôt pratique, plusieurs borniers pratiques pour enlever et monter les fils quand ma boîte sera terminée.

Je voudrais un panneau transparent sur le dessus pour qu'on voit le nano et que le "capteur" de luminosité prenne la lumière. L'écran serait aussi sur le dessus. Sur le côté je ferais un petit trou pour laisser passer un câble usb et une alimentation 12v vers 5v que j'ai bricolée :

Côté logiciel je n'ai pas encore terminé mais je n'ai plus qu'à écrire la partie affichage et une boucle du genre while(mon bouton=off) alors affichage normal (température + luminosité) et while(mon bouton=on) alors affichage des valeurs brutes pour debug.

Je ferais bien sûr un update de ce post pour ultimement vous montrer mon humble thermomètre :sweat_smile:

< mode humour>

20 kelvins cela fait un peu froid -253 °C, brrrr.

< Mode sérieux>
C'est fortement possible.
Recherches sur thermistance, il y a beaucoup de documentation sur l'équation qui les caractérise.
Une recherche sur ce forum "thermistance" devrait donner pas mal de réponse, les premières en français.

Je n'ai pas réussi à trouver l'équation adaptée à cette thermistance précise mais l'équation que j'ai trouvée va bien pour -5°C à environ 60°C.
J'ai tenté de faire un jeu de trois équation en fonction de la température :
-5°C < 60°C < Max 100°C
Mais impossible d'obtenir des résultats cohérents plus je voulais complexifier l'affaire, j'en reste donc au plus simple (pour le jardin ce sera bien...)

Merci en tout cas !

Et voici donc mon code définitif :

/* ____  __ __  _____  _____  __  __  _____  ____  _____  _____  _____    _____  _____  _____  _____ 
/    \/  |  \/   __\/  _  \/  \/  \/  _  \/    \/  _  \/  _  \/  _  \  /  _  \/  _  \/  _  \/  _  \
\-  -/|  _  ||   __||  _  <|  \/  ||  |  |\-  -/|  _  <|  |  ||  |  |  >-<_  <|  |  ||  |  ||  |  |
 |__| \__|__/\_____/\__|\_/\__ \__/\_____/ |__| \__|\_/\_____/\__|__/  \_____/\_____/\_____/\_____/
Arduino Nano + Thermistance + photorésistance + écran 128*32 SSD1306 + bouton */

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // Largeur de l'écran, en pixel
#define SCREEN_HEIGHT 32 // Hauteur de l'écran, en pixel
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2
#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16

static const unsigned char PROGMEM logo_bmp[] =
{ 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x0f, 0x98, 0x1f, 0x0c, 0x3e, 0x0c, 0x3f, 0x06, 0x3b, 0x86, 
  0x01, 0xc6, 0x00, 0xee, 0x00, 0x7c, 0x1e, 0x3c, 0x3f, 0xfc, 0x71, 0xfe, 0xe0, 0x07, 0xc0, 0x03
  };

// Pin
int mesure = A0; // Pin du thermomètre
int photocellPin = A1; // Pin de la photorésistance
int photocellReading; // La lecture analogique de la photorésistance
int bouton= 3; // Bouton
int etatbouton = 0; // Etat du bouton (low ou high)

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

  // On prépare le bouton
  pinMode(bouton, INPUT);
  etatbouton = digitalRead(bouton);
  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen -- Affichage du buffer sur l'écran
  // the library initializes this with an Adafruit splash screen. -- Vous pouvez modifier l'écran splash initial en modifiant le fichier splash de la librairie SSD1306 
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Message d'accueil
  // Paramètre
  display.drawPixel(10, 10, SSD1306_WHITE);
  delay(500);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);

  // On dessine un rectange autour du message
  display.drawRect(0, 0, 126, 28, WHITE);
  
  // Affichage du message
  display.setCursor(5, 5);
  display.println("- THERMOTRON 3000 - ");
  display.println("   Bonjour, Maitre ");
  display.display();
  delay(2000);
  display.clearDisplay();
  
  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawbitmap();    // Affiche une image bitmap

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

}
  //On appelle logo_bmp avant de démarrer le loop
void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
} 

void loop () {

  // Définition des paramètres principaux
  // On définit la valeur CAN pour la mesure brute renvoyée par la sonde de température
  const int valeur = analogRead(mesure);
  
  // Calcul de la tension : multiplication par 5.0 V, division par 1024 (plage de donnée du pin analogique)
  const float tension = ((valeur * 5.0) / 1024);
   
  // Calcul de la température avec la fonctiond déduite du tableur excel
  int puissance = 0.537*pow(tension, 3);
  const float Temp = puissance - 1.6528*sq(tension) + (20.839*tension) - 26.451;

  // On paramètre la lecture de la photorésistance
  photocellReading = analogRead(photocellPin);

  //Affichage par le port série
  Serial.print(" Tension : ");
  Serial.print(tension);
  Serial.print(" V , Valeur A0 : ");
  Serial.print(valeur);
  Serial.print(" CAN , Température : ");
  Serial.print(Temp);
  Serial.println(" °C .");  Serial.print("Lumière = ");
  Serial.print(photocellReading); // Lecture brute de la photorésistance
      
  // Si le bouton n'est pas pressé alors on affiche simplement la température et la luminosité
  etatbouton = digitalRead(bouton);
  if (etatbouton == LOW) 
  {

   //Affichage écran lcd
   display.clearDisplay();
   // On dessine un rectange autour du message
   display.drawRect(0, 0, 120, 32, WHITE);    
   display.setTextSize(2);
   display.setTextColor(WHITE);
   display.setCursor(20, 5);

   display.print(Temp);
   display.println(" C");
   display.setCursor(18, 22);
   display.setTextSize(1);
   display.print(photocellReading);
   // En fonction de la lecture brute du capteur on commente la mesure
      if (photocellReading < 10) {
          display.println(" - Noir");
        } else if (photocellReading < 200) {
          display.println(" - Sombre");
        } else if (photocellReading < 500) {
          display.println(" - Lumiere");
        } else if (photocellReading < 800) {
          display.println(" - Lumineux");
        } else {
          display.println(" - Plein Jour");
        }
   display.display();
   delay(2000); // Délai d'attente avant de rafraîchir la mesure
   display.clearDisplay();

// Si le bouton est activé (HIGH) alors affichage de plus de détail
  }
else
  {
  
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  // Display static text
  display.println(" - THERMOTRON DEBUG - ");
  display.setCursor(0, 8);
  display.print(tension); display.print(" V. "); display.print(valeur); display.println(" CAN");
  display.print("Temperature = "); display.println(Temp);
  display.print(photocellReading);   display.print(" Luminosite.");
  display.display();
  delay(1000);
  display.clearDisplay();
  }
}

Je suis assez content c'est pas fou mais ça fait apprendre !


Afficheur normal


Avec le bouton pressé