Skyduino:~#
Articles
arduino, programmation, tutoriel

[Arduino] Capteur de température sans contact MLX90614

Bonjour tout le monde !

S0072007

Il y a déjà quelques mois dans le courant du mois d’aout environ j’ai acheté ce petit capteur que vous pouvez voir sur la photo ci dessus.

C’est un capteur de température sans contact – par infrarouge donc – qui est capable de mesurer la température d’un objet en face de lui à une distance de quelques centimètres.
La référence du capteur est : MLX90614, pour ma part je suis tomber sur la version 3v3 au lieu de la version 5v mais ça ne change rien pour la suite de cet article 😉
A noter quand même que ce capteur bien que tout petit coute pas loin de 15€ pièce ! Évitez donc de le cramer par erreur …

Par chance hier j’ai pu (enfin) faire marcher le code que j’avais commencé en aout 😉

La théorie

Le capteur MLX90614 communique avec son maitre au moyen d’un bus compatible I2C ou directement en générant un signal PWM proportionnel à la température.
Pour cet article je vais utiliser le mode compatible I2C pour des raisons évidentes de simplicité 😉

Exceptionnellement je vais passer outre les informations du datasheet, celui-ci n’est que partiellement compréhensible.
Beaucoup trop d’informations éparpillées un peu partout ou bien trop condensées … bref un vrai kouglof.

Voici uniquement le principal à savoir :
– la commande pour lire la température est 0x07,
– la température est retournée sur 2 octets (LSB en premier) avec le bit de poids fort (bit n°15) à ignorer,
– la température est suivit d’un octet de contrôle qui ne nous intéresse pas mais que l’on doit lire.
– il ne faut pas libérer le bus I2C entre l’envoi de la commande et la réception de la réponse (c’est là qu’est toute l’astuce !)

Le montage

S0172017

Rien de bien compliqué ni d’extraordinaire pour réaliser ce montage.

Il vous faut :
– une carte Arduino (ici UNO)
– un capteur MLX90614 (logique vous ne trouvez pas ?)
– un condensateur de 100nF
– deux résistances de 4k7
C’est tout !

S0192019

Le câblage par contre est un peu plus compliqué de par le boitier métallique du capteur …
Je vous conseille de regarder le schéma de câblage disponible sur le site de Bildr, c’est le plus clair que j’ai pu trouver.
(le lien vers l’article complet sur le site de Blidr est un peu plus bas dans l’article)

Pour résumer en image (ce sera plus simple) :

S0212021

Si vous avez le détrompeur du capteur vers le haut, face à vous :
– en haut à droite : la masse
– en bas à droite : le +3v3 (Faite bien attention si vous avez un capteur 3v3 ou 5v !)
–> Le condensateur de 100nF vient se mettre entre de la masse et l’alimentation.

– en haut à gauche : ligne SCL du bus I2C (broche A5 sur une carte Arduino UNO)
– en bas à gauche : ligne SDA du bus I2C (broche A4 sur une carte Arduino UNO)
–> Les résistances viennent se mettre entre l’alimentation (ici 3v3) et les lignes du bus I2C.

Le code

Celui-ci est conçu pour fonctionner sur une carte Arduino UNO (ou mega2560) et est commenté comme d’habitude 😉

/* Librairie Wire pour les communications I2C */
#include <Wire.h>

/* Adresse par défaut du capteur IR */
#define I2C_ADDR 0x5A

/** Fonction setup() */
void setup() {
  
  /* Initialisation du port série (pour debug) */
  Serial.begin(115200);
  Serial.println(F("BOOT"));

  /* Initialisation du bus I2C */
  Wire.begin();
}

/** Fonction loop() */
void loop() {

  /* Données brute de température */
  uint16_t data;

  /* Commande de lecture de la RAM à l'adresse 0x07 */
  Wire.beginTransmission(I2C_ADDR);
  Wire.write(0x07);
  Wire.endTransmission(false);

  /* Lecture des données : 1 mot sur 16 bits + octet de contrôle (PEC) */
  Wire.requestFrom(I2C_ADDR, 3, false);
  while(Wire.available() < 3);
  data = Wire.read();
  data |= (Wire.read() & 0x7F) << 8;  // Le MSB est ignoré (bit de contrôle d'erreur)
  Wire.read(); // PEC
  Wire.endTransmission();

  /* Calcul de la température */
  const float tempFactor = 0.02; // 0.02°C par LSB -> résolution du MLX90614
  float tempData = (tempFactor * data) - 0.01;
  float celsius = tempData - 273.15; // Conversion des degrés Kelvin en degrés Celsius

  /* Affichage de la température */
  Serial.print(F("Celsius: "));
  Serial.println(celsius);

  /* Temps d'attente */
  delay(1000);
}

/!\ Attention /!\
Remarquez bien la présence du paramètre supplémentaire « false » dans ces deux lignes :

Wire.endTransmission(false);
// ...
Wire.requestFrom(I2C_ADDR, 3, false);

Ce « false » dit à la librairie Wire de ne pas libérer le bus I2C quand elle a fini.
C’est ce « false » qui fait toute la différence entre un code qui marche et un code qui ne marche pas 😉

Parenthèse concernant le code ci dessus

Si vous avez déjà essayé de faire marcher ce capteur avec une carte Arduino vous avez du surement tomber sur cet article de Bildr :
http://bildr.org/2011/02/mlx90614-arduino/

Celui-ci propose un code parfaitement fonctionnel mais qui n’est plus vraiment d’actualité !
Entre le moment où cet article a été rédigé et maintenant la librairie Wire pour Arduino a bien évolué (et dans le bon sens cette fois).
Plus besoin de passer par tout plein de bricolage pour arriver à ses fins !

Cela impose cependant une grosse limitation : le code ci dessus est conçu pour les versions 1.0 et supérieur du logiciel Arduino.
Pour utiliser ce capteur avec les anciennes versions 0023 ou antérieur il faudra repartir sur la solution proposé par Bildr.

Le résultat


BOOT
Celcius: 24.45
Celcius: 24.44
Celcius: 24.45
Celcius: 115.36
Celcius: 30.12
Celcius: 24.50

Je vous laisse deviner à quel moment j’ai placer le capteur devant la tête de mon fer à souder 😉

Ps: un deuxième article utilisant ce capteur devrait être prés d’ici peu.
Indice : dans celui ci il y aura des leds de couleurs et un appareil photo à exposition manuel.

Discussion

15 réflexions sur “[Arduino] Capteur de température sans contact MLX90614

  1. Excellente démonstration bien utile.

    J’aurais toutefois une remarque concernant le bus i2c et qui pourrait avoir son importance dans un environnement plus complexe : Le bus i2c Arduino fonctionne avec des niveaux logiques 0 et 5V, celui de capteur de température 0 et 3.3V. Il conviendrait d’insérer des adaptateurs de niveaux logiques « i2c level shifter » sur les signaux SDA et SCL, au minimum un mosfet BSN10 ou équivalent, voir cet « Application Note » de 1997 :

    Cliquer pour accéder à AN97055.pdf

    Publié par jmparatte | 2 novembre 2013, 18 h 27 min
    • D’après la doc la partie I2C du capteur peut supporter du 12v maximum donc 5v …

      Publié par skywodd | 2 novembre 2013, 18 h 33 min
      • le bus i2c est open drain, en plus, donc le niveau haut est au choix (pullups) et tant que tous les composants sont d’accord sur la tension max, pas de souci.

        sinon, ton false, c’est juste une repeated start condition, qu’il faut utiliser chaque fois qu’on veut lire sur le bus non? ou alors c’est plus compliqué?

        Publié par f4grx | 2 novembre 2013, 22 h 59 min
      • >> sinon, ton false, c’est juste une repeated start condition, qu’il faut utiliser chaque fois qu’on veut lire sur le bus non? ou alors c’est plus compliqué?

        Sans le false Wire envoi un stop qui casse tout, avec false ya pas de stop du coup le start suivant deviens un restart.

        Publié par skywodd | 2 novembre 2013, 23 h 07 min
  2. bonjour,
    J’ai un MLX90614ESF-BAA que si je n’ai pas mal lu, il devrait être la version à 3,3 volts, et un DUE Arduino.
    J’ai essayé votre code et, par conséquent, j’ai toujours du 0x7FFF
    vous pouvez me donner quelques conseils?

    désolé pour le français, mais j’ai utilisé un traducteur automatique

    merci

    Publié par Simone | 5 janvier 2014, 16 h 17 min
    • Je suis pas sûr que le bus I2C de l’arduino Due s’utilise de la même manière que sur une carte Arduino classique.
      J’essayerai déjà de mettre des résistances de pullup de 1K5 au lieu de 4K7 pour voir.
      Sinon j’ai aucune idée d’où peut venir le probléme.

      Publié par skywodd | 5 janvier 2014, 19 h 18 min
      • merci pour la réponse
        DEUX Arduino dans SDA et SCL a déjà pullup résistances à 1.5K. A ce stade, je ne sais pas.
        si quelqu’un a une idée ….

        Publié par Simone | 7 janvier 2014, 15 h 16 min
      • The MLX90614 meets all the timing specifications of the SMBus [1]. The maximum frequency of the MLX90614 SMBus is 100 KHz and the minimum is 10 KHz.

        L’Arduino DUE travaille à une fréquence beaucoup plus élevée!

        Publié par jmparatte | 8 janvier 2014, 15 h 03 min
      • Il pourrait y avoir une erreur dans l routine TWI_ConfigureMaster:

        if ( dwClDiv TWI_CWGR = (dwCkDiv << 16) | (dwClDiv << 8) | dwClDiv ;

        Ca me paraît incohérent.

        Publié par jmparatte | 8 janvier 2014, 19 h 00 min
      • bonjour
        merci pour la réponse
        pour la vitesse, j’ai vu que le AT91SAM3X8E est compatible avec les bus 100 KHz à 400 KHz. la page 713 de la feuille de données. pour la deuxième question, je ne sais pas.

        Publié par Simone | 8 janvier 2014, 22 h 40 min
      • J’ai analysé les signaux i2c de l’Arduino DUE avec un oscilloscope. La fréquence est correctement de 100kHz, comme pour l’Arduino UNO. en revanche, les séquences START/STOP/RESTART sont incorrectes. J’ai mémorisé les écrans des trames i2c des 2 modèles d’Arduino, on voit immédiatement le problème sur la séquence START.

        Publié par jmparatte | 9 janvier 2014, 17 h 13 min
  3. Suite aux problèmes avec l’Arduino DUE, j’ai analysé le protocole i2c avec l’oscilloscope. J’y ai relevé un nombre anormal de bytes émis. Aussi je me suis pris au jeu d’étudier les ordres de la librairie Wire qui m’était jusqu’à lors inconnu. Et j’ai relevé quelques incohérences dans les manipulations i2c de ton exemple. Je propose la variante suivante qui émet et reçoit le nombre exact de bytes.

    J’ai effectué 1 modification dans la commande Wire.requestFrom et la suppression de la commande finale Wire.endTransmission().

    Remarque: Ce code ne fonctionne toujours pas avec l’Arduino DUE.

    Le code actualisé:

    /* Librairie Wire pour les communications I2C */
    #include

    /* Adresse par défaut du capteur IR */
    #define I2C_ADDR 0x5A

    /** Fonction setup() */
    void setup() {

    /* Initialisation du port série (pour debug) */
    Serial.begin(9600);
    Serial.println(F(« BOOT »));

    /* Initialisation du bus I2C */
    Wire.begin();

    /** Fonction loop() */
    void loop() {

    /* Données brute de température */
    uint16_t data;

    /* Commande de lecture de la RAM à l’adresse 0x07 */
    Wire.beginTransmission(I2C_ADDR);
    Wire.write(0x07);
    Wire.endTransmission(false);

    /* Lecture des données : 1 mot sur 16 bits + octet de contrôle (PEC) */
    // Wire.requestFrom(I2C_ADDR, 3, false);
    Wire.requestFrom(I2C_ADDR, 3, true);
    while(Wire.available() < 3);
    data = Wire.read();
    data |= (Wire.read() & 0x7F) < résolution du MLX90614
    float tempData = (tempFactor * data) – 0.01;
    float celsius = tempData – 273.15; // Conversion des degrés Kelvin en degrés Celsius

    /* Affichage de la température */
    Serial.print(F(« Celsius: « ));
    Serial.println(celsius);

    /* Temps d’attente */
    delay(1000);
    }

    Publié par jmparatte | 9 janvier 2014, 17 h 04 min
  4. Bonjour j’ai acheté le capteur que vous utiliser et j’aimera Savoir si vous on est obligé d’utiliser une aussi grosse résistance ou pas car je ne dispose pas de ses résistances. Merci d’avance si vous me répondez

    Publié par Romain | 8 janvier 2019, 18 h 52 min

Rétroliens/Pings

  1. Pingback: Melexis MLX90614 | jmP - 9 janvier 2014

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.