dimanche 1 juillet 2012

Thermistance, température et entrées analogiques.

Ce week-end, jeux avec l'entrée analogique de l'Arduino et test de la thermistance (mesure de température).

Une termistance et un afficheur simplifié
de la température avec 5 LEDs.
Très facile a mettre en œuvre, il suffit de suivre quelques tutoriels très simples pour avoir les premières mesures : Brancher la thermistance sur l'alim 5 volts, avec une résistance vers la masse et une ligne vers une entrée analogique. Et hop voilà on a des mesures qui varient avec la température.
Bien, mais il s'agit d'aller plus loin et de comprendre ce qui se passe et surtout d'avoir des mesures en °C et non pas des valeurs abstraites...



La thermistance (thermistor en anglais)

C'est un composant simple qui est une résistance variable et dont la résistance varie avec la température.
La thermistance livré avec mon kit de base a comme seule caractéristique connue sa résistance à 25°C : 4,7 kΩ.
Pour pouvoir en déduire une température exprimé sous forme de °C, il faut avoir plus de données, car la réponse des thermistances n'est pas linéaire.
Pour traduire cette résistance en température il faudra passer par plusieurs étapes :
  • Convertir en tension, en utilisant un circuit diviseur de tension
  • Convertir en température, en utilisant la relation de Steinhart-Hart.
  • Calibrer la thermistance (déterminer plusieurs équivalences température-résistance)

Circuit diviseur de tension

Mes connaissances en électronique étant proche de Zéro, j'ai pris le parti de comprendre comment marche ce petit circuit. Bien m'en a pris. J'ai découvert le circuit "diviseur de tension". Assez simple mais qui permet de bien appréhender la mesure analogique.
Il s'agit d'un circuit avec une alimentation en tension constante et de 2 résistances en série. Ce circuit permet d'obtenir une tension aux bornes de la 2ème résistance réduite par rapport à la tension fournie, d'ou son nom : diviseur de tension.

L'intérêt survient lorsque l'on sait que les entrées analogiques de l'Arduino mesurent une tension et fournissent donc une valeur numérique entre 0 et 1023 (1024 valeurs, soit 10 bits) proportionnelle à la tension de référence. Ainsi si la tension de référence est de 5 volts, avec une mesure de 2 volts, Arduino fournit une valeur numérique de 409 (soit 1024*2.0/5.0-1).
La thermistance fournissant une réponse à la température sous forme de résistance variable, le circuit diviseur de tension va permettre de convertir cette résistance variable en tension variable et donc numérisable par les entrées analogiques de l'Arduino. Ce circuit est donc fondamental pour la mesure de résistance.

Ce circuit est régie par la loi d'Ohm (U=RI) d'ou on déduit :
  • Uout=Uin*R2/(R1+R2), soit que la tension de sortie (aux bornes de R2) est un multiple de la tension d'alimentation (U) par un coefficient : R2/(R1+R2). Cela en fait une relation simple mais non linéaire lorsque R1 ou R2 varie (c'est le cas avec une thermistance).
  • Sur l'Arduino on n'obtient pas directement une tension comme mesure sur les entrées analogiques mais une valeur comprise entre 0 et 1023 qui est proportionnelle à la tension de référence (Uin). Soit A0 la valeur numérique mesurée sur l'entrée analogique n°0, on a : A0=1024*Uout/Uin-1
  • Ce qui permet de ré-écrire l'équation de notre diviseur (vu par le logiciel de l'Arduino) : A0=1024*(Uin*R1/(R1+R2))/Uin-1, ou plus simple : A0=1024*R1/(R1+R2)-1, il est indépendant de la tension fournie.
  • Le logiciel Arduino peut donc calculer la résistance de la thermistance (R1) à partir de la mesure analogique (A0) de la tension (Uout) aux bornes de celle-ci et donc la réponse de la thermistance à la température.
J'ai pas mal butée sur les équations pendant un moment jusqu'à ce que je me rende compte que j'avais branché la thermistance sur R1 alors que je croyais l'avoir fais sur R2... Cela change la mesure et la manière de calculer la température...
En savoir plus sur le circuit diviseur de tension : je me suis servi des cours de E.J.Mastascusa à l'université de Bucknell (USA).

Tension de référence

Ce simple circuit permet donc de convertir une résistance R1 variable en une tension U1 mesurable par une entrée analogique de l'Arduino. Et cela de manière indépendante de la tension d'alimentation du circuit.
Le plus simple est d'utiliser la tension 5 volts de l'Arduino (qui provient soit de l'USB, soit d'une alimentation externe). Les entrées analogiques sont par défaut régler sur cette tension de référence.
Toutefois il semble que cette tension ne soit pas toujours bien régulée et qu'elle puisse varier. Il semble préférable (pour fiabiliser les mesures) d'utiliser plutôt le 3,3 volts fournis par l'Arduino qui est régulé à partir du 5 volts. Pour cela il convient de brancher aussi ce 3,3 volts sur la broche ARef et de configurer les entrées analogiques avec la tension ARef comme référence.

Choisir la résistance R1

La résistance fixe R1 de notre circuit diviseur de tension doit être déterminer. On peut a priori prendre un peu n'importe laquelle pour peu que l'on pense a intégrer sa valeur R1 dans les calculs nécessaire sur l'Arduino. Toutefois selon l'équation qui régit le circuit diviseur de tension cette résistance va influer sur la plage de mesure. Il est donc préférable de choisir la résistance qui corresponde à la résistance de la thermistance à la température médiane de l'expérience.
Dans mon cas désirant mesurer la température ambiante d'une pièce je vais choisir R1 comme égal à la valeur de la thermistance à 25°C, soit 4700 Ω ce qui fera de cette température le centre des valeurs numériques (la moitié de 1024, soit 512 correspondra à 25°C).

Relation de Steinhart-Hart

La réponse de la thermistance à la température est sa résistance, qui varie avec la température (de manière inverse) : plus la température monte, plus la résistance diminue. La correspondance température/résistance est régie par la relation de Steinhart-Hart.
Cette relation établie une équation qui permet d'obtenir la température (en Kelvin) à partir de la résistance mesurée et de 3 coefficients spécifiques a chaque thermistance : a, b et c.
Le problème dans la réalité c'est que ces 3 coefficients ne sont pas forcément fournis par la fabricant sur la fiche technique et que dans mon cas présent je n'ai même pas la fiche technique... Juste la donnée de base : résistance de 4.7 kΩ à 25°C.
Pour trouver les 3 coefficients on doit effectuer des 3 mesures étalonnées (connaitre la température réelle et la valeur de résistance correspondante) avec le plus grand écart possible pour améliorer la fiabilité. On peut ensuite résoudre l'équation de Steinhart-Hart (on trouve des feuilles de calculs toute faites qui font ça très bien).
Souvent les fiches techniques (datasheets) fournissent un tableau Température/résistance qui pourra servir à déterminer les coefficients, dans mon cas pas de fiche technique, donc étalonnage manuel.

Calibrer la thermistance

Le montage avec le thermomètre de référence
pour calibration
Pour étalonner ma thermistance il me faut établir 3 mesures précises de résistance a 3 températures différentes.
Pour se faire je dispose de... pas grand chose... Heureusement j'ai un petit thermomètre numérique de cuisine (acheté pour ma fabrication de bière) qui sera ma mesure précise de température. Ensuite ne disposant de rien d'autre je vais profiter du temps de samedi et mesurer la température ambiante de mon bureau au petit matin, a midi et en fin de journée. Cela m'a permis d'avoir les températures suivantes :
  • 16,7°C à 6h30, mesure A0=418, soit 6814 Ω
  • 21,0 °C vers 12h30, mesure A0=465, soit 5650 Ω
  • 25,5°C vers 18h, mesure A0=516, soit 4627 Ω

Rendre autonome le circuit

Le système fonctionne bien et régit vite. Toutefois il nécessite d'être brancher sur l'ordinateur pour voir le résultat de la mesure (dialogue via le port USB avec la librairie Serial).
J'en profite pour mettre en place un système simple de visualisation de la température via des LEDs (4 au début puis 5) qui permettent de visualiser les mesures entre 15 et 30°C. Pour se faire je branche les 5 LEDs sur 5 sorties PWM (qui permettent de piloter la luminosité de la LED) et j'élabore un petit bout de code qui gère l'ensemble (permet pas simple paramétrage de passer à n LEDs, limité au nombre de sortie PWM de l'Arduino).
Là encore ça réagit super bien, dès que je touche la thermistance avec les doigts les LEDs indiquent le changement de température...

Les éléments du circuit

Le schéma électrique (réalisé avec Fritzing)
Le code source (logiciel Arduino) :
// Temperature
// using external temperature sensor and display with LEDs
//
// PAD, 1/07/2012
 
int sensor_temp=0;  // analog input for sensor
#define NB_LED  5  // define nb and output PWM output for LEDs
int led[NB_LED]={3,5,6,9,10};
int nb_read=10;    // nb of measure to smooth results
unsigned long t0;  // next time to send result to computer via Serial
void setup() {
  // Initialize Serial Communication
  Serial.begin(9600);
  Serial.println("Temperature monitor (external thermistor");

  // Set-up Input-Output
  analogReference(EXTERNAL);  // use external ARef for analog inputs
  for (int i=0;i<NB_LED;i++) {  // config LEDs pins to output
    pinMode(led[i],OUTPUT);
    digitalWrite(led[i],HIGH);
  }
  // Initialize previous state global variables
  t0=0;
  // Wait until Serial is OK
  while (!Serial) {
    ; }
}
 
void loop() {
  int i;
  long m;  // must be long to support many additions
  unsigned long t1;
  double t;
  // measure many times and mean the result
  m=0;
  for (i=0;i<nb_read;i++)
    m=m+analogRead(sensor_temp);
  m=m/nb_read;

  // set the LED state to reflect measure
  SetLED(m,400,600);
  // every 2 seconds, display data
  t1=millis();
  if (t1>t0) {
     t=Thermister(m);
     t0=t1+5000;
  }
}

// Use Steinhart-hart relation to compute temperature from analog input
// See http://en.wikipedia.org/wiki/Thermistor for explanation of formula
double Thermister(int RawADC) {
  double R,LnR,Temp;
  double A,B,C,R1;
  // experimantal data for Steinhart-hart relation
  A=-0.022847889;
  B=0.004495497;
  C=-0.00001954317;
  // Actual resistance R1 for the tension divider
  R1=4400;

  R=((1024.0*R1/RawADC) - R1); // Converter ADC to Resistance value
  Temp = log(R);    // compute its log to optimize next computation
  Temp = 1 / (A + (B * Temp) + (C * Temp * Temp * Temp)); // steinhart-hart relation
  Temp = Temp - 273.15;    // Convert Kelvin to Celcius
  // print detail results
  #ifDEF DETAIL
  Serial.print("\tADC: "); Serial.print(RawADC); Serial.print("/1024 - ");
  Serial.print("\tResistance: "); Serial.print(R); Serial.println(" ohms");
  #endif
  Serial.print("Temperature: "); Serial.print(Temp); Serial.println(" oC");

  return Temp;
}
 
// Display RawADC data using some LEDs
// minADC and MaxADC indicate min, max value to be displayed (first and last LEDs)
// then interpolate value for each LED and output it
// LED must be plug into PWM compatible pins
void SetLED(int RawADC,int minADC,int maxADC) {
  double v,v0,offset;
  int vl[NB_LED];

  v=1.0*(RawADC-minADC)/(maxADC-minADC);
  offset=0.0;
  for (int i=0;i<NB_LED;i++) {
    v0=-1.0*(NB_LED-1)*abs(v+offset)+1.0;
    if (v0<0.0) v0=0.0;
    if (v0>1.0) v0=1.0;
    vl[i]=(int)(255*v0);
    analogWrite(led[i],vl[i]);
    offset-=1.0/(NB_LED-1);
  }

  #ifdef _DEBUG_
  Serial.print("LED: ");
  Serial.print(v,3);
  Serial.print(" G: ");
  Serial.print(vl[0]);
  Serial.print(" Y: ");
  Serial.print(vl[1]);
  Serial.print(" O: ");
  Serial.print(vl[2]);
  Serial.print(" R: ");
  Serial.println(vl[3]);
  #endif
}



3 commentaires:

  1. Bien je viens de lire avec beaucoup d'intérêt... un petit conseil de frigoriste je me sers de températures de référence sures...
    le l'eau mélangée avec des glacons... 0°C... et de l'eau en ébullition (verre dans le micro onde) 100°C si tu n'es pas trop en altitude! (1 atmosphère)
    dans ces extrèmes il faut lire vite car l'eau descend vite à 98°C et remuée sans cesse l'eau glacée.

    RépondreSupprimer