Go Down

Topic: Mesure température + tension (Read 2843 times) previous topic - next topic

pro_info

Bonjour à tous,
Étant débutant, voilà quelques heures à présent que je bloque sur ceci :

J'ai pour le moment :
- 1 arduino pro mini 5V/16Mhz
- 1 écran adafruit relié en I2C,
- une sonde LM35DZ sur un pin analogique
- et 1 pont résistif (me permettant de mesurer une tension proche de 12V) sur un autre pin analogique.

J'ai été heurté au fameux problème de l'analogique ou les différentes entrées interfèrent, que j'ai résolues avec ceci :
Code: [Select]
analogRead(......);
delay(20);
second appel analogRead..........


Mon problème est la mesure de température qui n'est pas très précise sans ceci "analogReference(INTERNAL);", mais pour une mesure de tension, l'analogReference(INTERNAL); n'est pas envisageable (comme le confirment certains autres posts), celui-ci fausse toutes les mesures lors d'une mesure de tension.

Avez-vous une solution sur ce point ? N'est-il pas possible d'activer l'analogReference pour un seul pin ou l'activer juste le temps de la lecture de la sonde ?

voici mon code :
Code: [Select]

.......
float THERMO_PIN = A0;                  // Emplacement LM35DZ
int TENS_12V_PIN = A2;                  // Emplacement Pont résistif 12V
static const byte BUZZER_PIN = A1;      // Emplacement Buzzer

float thermo_temp;                      // température en degrés celcius
int tens_12V = 0;                       // lecture brute de l'entrée analogique (0 à 1024)

float tension;                          // variable intermédiaire pour le calcul des tensions

// -- Pont résistif 12V
float TENSR1_12V = 270000.0;
float TENSR2_12V = 100000.0;
// -- End

void setup()   {               
  Serial.begin(9600);
  //analogReference(INTERNAL);
  pinMode(BUZZER_PIN, OUTPUT);

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done
  display.clearDisplay();
  display.drawBitmap(0, 10,  logo, 40, 40, 1);
 
  // text display tests
  display.setTextColor(WHITE);
  display.setCursor(40,20);
  display.setTextSize(2);
  display.print("Splash");
  //display.drawLine(0, 8, display.width(), 8, WHITE);
  display.setCursor(42,35);
  display.setTextSize(1);
  display.print("Screen");
  display.display();
  delay(5000);
  display.clearDisplay();
  //tone(BUZZER_PIN, 500, 500);
}


void loop() {

  // -- mesure température
  analogRead(THERMO_PIN);
  delay(20);
  thermo_temp = analogRead(THERMO_PIN) *  (5.0 * 1000 / 1024) / 10 ;      // conversion en celcius
 
  display.setCursor(0, 0);                                                // affichage -- START
  display.setTextSize(1);
  display.print(thermo_temp,1);
  display.println("'C");
  display.setCursor(20, 15);
  display.setTextSize(2);
  display.print("Celsius");                                               // affichage -- END
  // -- End
 
  // mesure tension 12V
  analogRead(TENS_12V_PIN);
  delay(20);
  tens_12V = analogRead(TENS_12V_PIN);
 
  tension = map(tens_12V, 0, 1023, 0, 5000);               // conversion en mV
  tension = tension / 1000;                                               // conversion des mV en V
  tension = (tension / (TENSR2_12V /(TENSR1_12V + TENSR2_12V))) / 1.0152; // facteur de correction 1.0152
 
  display.setCursor(0, 35);                                               // affichage -- START
  display.setTextSize(1);
  display.print(tension);
  display.println("V (+12V)");                                           // affichage -- END
  // -- End
 
  display.display();
  delay(600);
  display.clearDisplay();

//  if (THERMO_TEMP > 25){
//    tone(BUZZER_PIN, 440, 500);
//  }
}


Merci bien !

68tjs

Ah ce fameux LM35 !

On peut faire de bonnes mesures avec à condition de bien comprendre certain points.

Tout d'abord le LM35 lui même.
1) Comme tout circuit CMOS il ne supporte pas de grandes longueur de filasse capacitive.
Il n'est pas pour autant interdit de le raccorder sur des long fils mais il faut appliquer les précautions indiquées dans la notice du LM35 (datasheet). En raccourci mettre une résistance entre 2k et 5 kohms en série entre la  sortie du LM35 et les longs fils.
2) LE LM35 DOIT ETRE SEUL SUR SON FIL de masse. 
Explication : la résistance d'un fil n'est jamais nulle, le courant d'alimentation des autres composants provoquera une petite chute de tension mais comme la sensibilité du LM35 n'est que de 10mV/C cette petite chute de tension sera suffisante pour fausser la mesure de la température.
Il faut OBLIGATOIREMENT câbler les fils de masse (0V) en  étoile . Les différents fils de masse étant tous reliés en seul point sur une carte Arduino.

Le fonctionnement du convertisseur analogique du micro-controleur.
Tout ce qui suit se trouve dans la data sheet du micro-controleur.
- Il n'y a qu'un seul ADC (Analog Digital Converter). Les différentes entrées sont connectées à l'ADC par un multiplexeur.
- Le convertisseur est sur 10 bits c'est à dire que la plus petite tension qu'il peut détecter est égale à Vreférence/1024.
Le pas de mesure sera voisin de 5 mV si la référence est à 5V et de 1mV si la référence est à 1,1 V.
Si on cherche à mesurer une tension supérieure à Vref l'ADC indiquera 1023 qu'elle que soit la valeur de cette tension.

Dans la data sheet il est indiqué qu'il ne faut JAMAIS prendre la première mesure qui suit un changement dans l'ADC.
Un changement peut être un changement de référence ou un changement dans le multiplexeur.
Ce n'est pas la peine de mettre des délais bloquants il suffit simplement de rejeter la ou les  premières mesures.

Précisions sur les références pour l'ADC.
Il est évident que la précision de mesure sera affectée par la précision de la référence de tension.
Par construction la référence de l'ADC est le Vcc de la carte Arduino.
Si la carte est alimentée par l'USB la précision sera celle de l'USB c'est à dire  +/- 5%.
Si la carte est alimentée à travers le régulateur interne la précision sera celle du régulateur. (environ +/- 1%)

La référence interne est donnée pour 1,1 V +/- 0,1 V c'est à dire +/-10%.
Point important : il est possible de mesurer exactement cette valeur  -->  quand l'ADC est configuré en référence interne la tension correspondant à cette référence est disponible sur la broche Aref. Il est possible de la mesurer avec un multimètre.
Point super important qui découle du précédent : en position Vref interne il est absolument interdit de connecter une source de tension externe sur Aref  --> mort du micro assurée.
En résumé on peut par programmation commuter comme on veut les références de tension  :
- Vcc et Vref interne
- Vcc et Aref (Vref externe)
Mais pas  Vref interne avec Aref (Vref externe).



pro_info

Merci pour ce pavé très instructif.
J'avais effectivement vu dans le datasheet les 2 points que tu cites, mon LM35 est seul sur son fil de masse. J'ai actuellement moins de 10cm de fil pour mes tests et je ne possède pour le moment pas les résistances indiquées, elles ne sont donc pas en place (elles le seront peut être après)

À propos du délai bloquant, si j'ai bien compris, il serait plus propre de rejeter les premières valeurs que d'utiliser ce délai. Or je n'ai pas trouvé d'exemple qui explique comment rejeter les 1ère mesures, si tu as plus d'infos à ce sujet, je suis preneur.

Quote
Précisions sur les références pour l'ADC.
Il est évident que la précision de mesure sera affectée par la précision de la référence de tension.
Par construction la référence de l'ADC est le Vcc de la carte Arduino.
Si la carte est alimentée par l'USB la précision sera celle de l'USB c'est à dire  +/- 5%.
Si la carte est alimentée à travers le régulateur interne la précision sera celle du régulateur. (environ +/- 1%)

Ma carte est alimentée par une alimentation stabilisée (type ATX) par le pin raw donc par le régulateur interne de l'arduino, ce qui me permettrait en théorie dans le cas le plus favorable une précision de +/- 1% comme tu le dis.

Ton dernier paragraphe est un peu flou (je crois qu'il ne s'applique pas à mon cas cependant & qu'il s'agit de la même chose que ceci) :
Quote
La référence interne est donnée pour 1,1 V +/- 0,1 V c'est à dire +/-10%.
Point important : il est possible de mesurer exactement cette valeur  -->  quand l'ADC est configuré en référence interne la tension correspondant à cette référence est disponible sur la broche Aref. Il est possible de la mesurer avec un multimètre.
Point super important qui découle du précédent : en position Vref interne il est absolument interdit de connecter une source de tension externe sur Aref  --> mort du micro assurée.
En résumé on peut par programmation commuter comme on veut les références de tension  :
- Vcc et Vref interne
- Vcc et Aref (Vref externe)
Mais pas  Vref interne avec Aref (Vref externe).

Je ne sais pas si cette info est en rapport avec ce que tu dis ci-dessus, mais l'arduino pro mini ne semble pas disposer de pin Aref, ce qui ne me permet pas d'effectuer les mesures.

Ce que j'avais compris/hypothèse, lorsque l'ADC est configuré en interne, la mesure ce fait de 0 à 1,1V ce qui me fournit plus de précision dans le relevé que lorsqu'il n'est pas défini. (Lorsqu'il n'est pas défini (DEFAULT), sa plage de mesure est de 0 à 5V ce qui me conduit à une précision moindre.)

D'où cette question, s'il n'est pas possible de définir l'ADC pour un seul pin, est-il possible de le basculer en INTERNAL pour la mesure de la sonde puis le remettre sur DEFAULT pour l'exécution du reste de la boucle ?
Il y a t'il une autre solution ?
J'ai sur mon écran oled un pin 3.3V (donc un convertisseur intégré 5V/3.3V), puis-je alimenter ma sonde avec cette tension pour affiner les mesures ?

merci

68tjs

Quote
comment rejeter les 1ère mesures

Par exemple
- une boucle for qui fait 5 fois analogRead(Ax)           // --> les 5 mesures sont perdues
- suivie d'une ligne :
                                      mesure= analogRead(Ax);   // --> la mesure est sauvegardée

Quote
Ton dernier paragraphe est un peu flou

C'était une mise en garde : pas de tension appliquée sur Aref si la référence interne est sélectionnée.

Quote
mais l'arduino pro mini ne semble pas disposer de pin Aref

Le soucis c'est qu'il n'existe pas qu'une seule implantation ni même un seul schéma d'arduino pro mini .
Néanmoins même si elle n'est pas disponible en bord de circuit imprimé la broche Aref du micro-controleur est obligatoirement disponible sur le boiter de l'atmega328p. Il est donc possible, en faisant attention, d'y mesurer une tension.

Très souvent la broche Aref du micro-controleur est découplée avec un condensateur de 100 nF.
Il est possible de souder un fil sur le condensateur de découplage pour avoir accès à Aref, d'accord c'est délicat mais  c'est faisable.
Ensuite tu peux appliquer sur Aref n'importe quelle tension comprise entre 1,1 V et Vcc.

Quote
est-il possible de le basculer en INTERNAL pour la mesure de la sonde puis le remettre sur DEFAULT pour l'exécution du reste de la boucle ?

Bien sur !
C'est ce que j'ai voulu dire ici :
En résumé on peut par programmation commuter comme on veut les références de tension  :
- Vcc et Vref interne
- Vcc et Aref (Vref externe)
Mais pas  Vref interne avec Aref (Vref externe).


Et toujours en rejetant les premières mesures après une modification de la configuration de l'ADC.




pro_info

C'est parfait dans ce cas,
j'ai la précision en basculant l'ADC en internal pour la mesure de la température puis la possibilité de mesurer la tension avec mon pont résistif en déclarant l'ADC en default pour revenir sur la plage 0 - 5V.

Pour rejeter les premières mesures, je pensais qu'il existait une fonction, il est vrai qu'une boucle est tout aussi vite faite.

ps : Je viens de faire le test, j'ai dû quand même mettre un delay(1) dans la boucle, sinon même en ignorant les 5 valeurs, j'avais des interférences entre les deux entrées analogiques. J'ai pris pour valeur de Aref sans mesurer 1.1V (les mesures sont assez fiables et je ne prends pas de risque à faire un court-circuit en voulant mesurer^^)

voici le code fonctionnel :
Code: [Select]
  // -- mesure température
  analogReference(INTERNAL);
  for(int i = 0; i < 5; i++)
  {
    analogRead(THERMO_PIN);                                 // Boucle de rejet des 5 premières valeurs
    delay(1);
  }
  thermo_temp = analogRead(THERMO_PIN) *  (1.1 * 1000 / 1024) / 10 ;      // conversion en celcius
 
  display.setCursor(0, 0);                                                // affichage -- START
  display.setTextSize(1);
  display.print(thermo_temp,1);
  display.println("'C");
  display.setCursor(20, 15);
  display.setTextSize(2);
  display.print("Celsius");                                               // affichage -- END
  analogReference(DEFAULT);
  // -- End
 
  // mesure tension 12V
  for(int i = 0; i < 5; i++)
  {
    analogRead(TENS_12V_PIN);                                  // Boucle de rejet des 5 premières valeurs
    delay(1);
  }
 
  tension = map(analogRead(TENS_12V_PIN), 0, 1023, 0, 5000);              // conversion en mV
  tension = tension / 1000;                                               // conversion des mV en V
  tension = (tension / (TENSR2_12V /(TENSR1_12V + TENSR2_12V))) / 1.0152; // facteur de correction 1.0152
 
  display.setCursor(0, 35);                                               // affichage -- START
  display.setTextSize(1);
  display.print(tension);
  display.println("V (+12V)");                                            // affichage -- END
  // -- End


à noter que j'ai également mis une boucle pour mon pont résistif, ça ne mange pas de pain et évite de prendre une valeur avec des interférences.

Merci beaucoup pour ton aide et ta réactivité.

john_lenfr

Tu peux également prendre plusieurs valeur et retenir la moyenne ce qui lissera un peu les erreurs de lecture.

Par contre je ne comprenbds pas ta correction:
Code: [Select]
*  (1.1 * 1000 / 1024) / 10 ;

Perso je fais juste reading * 5.0 / 1024.0;


Code: [Select]
float lm35dz(){
  analogRead(3);
  delay(10);
  reading = analogRead(3); //LM35DZ connect to Analog pin 3
  //convert the voltage into temperature because the LM35DZ is at 10mV per °C
  voltage = reading * 5.0 / 1024.0;
  temperature = voltage * 100 ;
  return temperature;
}


pro_info

En effet, je vais faire une moyenne de 2 ou 3 valeurs pour gagner en précision, merci pour l'idée.

Par contre je ne comprends pas ta correction:
Code: [Select]
*  (1.1 * 1000 / 1024) / 10 ;
Perso je fais juste reading * 5.0 / 1024.0;

je suis tombé sur cette correction ici : http://www.instructables.com/id/ARDUINO-TEMPERATURE-SENSOR-LM35/
la personne y explique :
Quote
We can get value magic number 0.48828125 from following expression:

(SUPPLY_VOLTAGE x 1000 / 1024) / 10 where SUPPLY_VOLTAGE is 5.0V (the voltage used to power LM35)

1024 is 2^10, value where the analog value can be represented by ATmega (cmiiw) or the maximum value it can be represented is 1023. The actual voltage obtained by VOLTAGE_GET / 1024.

1000 is used to change the unit from V to mV

10 is constant. Each 10 mV is directly proportional to 1 Celcius.

By doing simple math: (5.0 * 1000 / 1024) / 10 = 0.48828125


Voyant que la formule fonctionnait, je n'ai pas poussé plus loin.
J'ai remplacé le 5.0 par 1.1 puisque "la référence interne est donnée pour 1,1 V" lorsque l'ADC est en "mode" INTERNAL, ce qui me donne exactement la bonne température (peut être un coup de chance).

Go Up