GPIO – Capteurs de température

Dans cet article, nous allons voir comment mesurer la température ambiante avec deux types de sondes thermomètres très différentes : la sonde numérique DS18B20 et la sonde analogique TMP36. Dans les deux cas, il s’agit d’un minuscule composant à trois pattes, dont la résistance des composants internes varie en fonction de la température.

IMG_5766

Il faut savoir que le GPIO du Raspberry Pi ne dispose pas d’entrées analogiques, il est par conséquent impossible de mesurer la valeur d’une résistance ou d’un courant directement.

La sonde TMP36 étant un composant analogique, nous allons devoir utiliser un convertisseur analogique/numérique ou ADC (Analog to Digital Convert), comme le MCP3008.

La sonde  DS18B20 est, quant à elle, une sonde numérique qui utilise un bus/protocole particulier qui permet communiquer l’information à travers un seul câble (par extension, une seule broche du port GPIO du Pi) ; il s’agit du bus 1-Wire.

Matériel utilisé dans cet article

Pour réaliser ces deux montages, en plus des sondes TMP36 et DS18D20, vous aurez besoin d’une breadboard, de wire jumpers et d’une résitance. Vous pouvez trouver ces composants directement ici :

Sonde analogique TMP36 et ADC MCP3008

TMP36 MCP3008
sonde-temperature-tmp36 mcp3008

Alimentée entre 2,7V et 5,5V (parfait pour le Pi qui peut fournir une alimentation de 3V ou 5V), la sonde TMP36 permet de mesurer des températures de -50°C à +125°C avec une précision annoncée entre 0,5°C et 1°C en moyenne. Fonctionnant dans la même plage de tension (2,7V à 5,5V), le convertisseur analogique/numérique MCP3008 dispose de huit entrées, ce qui permet de lire les informations de huit capteurs (de température ou autre). Le MCP3008 dispose d’une interface SPI, nativement supportée par le Pi 🙂 En outre, il offre de résolution de 10 bits, ce qui va lui permettre de distinguer 2^10 soit 1024 valeurs. Il est important de noter que le MCP3008 permet un échantillonnage beaucoup plus fin (1024 valeurs) que ce que permet de mesurer le TMP36, ce dernier ne sachant distinguer que 50+125/0,5 soit 350 températures différentes (au mieux).

Le schéma ci-dessous montre comment brancher le MCP3008 sur le GPIO du Pi, et comment relier le TMP36 au MCP3008 :

raspberry_pi_gpio_mcp3008

En dehors des fils d’alimentation (en noir et en rouge), le bus SPI du MCP3008 occupe quatre broches sur le GPIO du Pi. La broche centrale (tension de sortie) du TMP36 est directement reliée à une des entrées du MCP3008.

Après les branchements, passons à la partie logicielle 🙂

Seul le paquet python-dev est strictement nécessaire pour utiliser l’interface SPI du MCP3008 :

apt-get install python-dev

Les dernières versions de Raspbian ne nécessitent pas de manipulations particulières pour utiliser le bus SPI du GPIO. Si toutefois vous rencontrez des problèmes, il faudra mettre à jour la lib Python rpi.gpio :

sudo easy_install -U distribute
sudo apt-get install python-pip
sudo pip install rpi.gpio

Intéressons nous maintenant au fonctionnement du MCP3008 pour comprendre comment extraire la température mesurée par le TMP36.

Le principe est relativement simple : le MCP3008 renvoie une valeur entre 0V et la tension de « référence«  (ici 3,3V ou 3300mV car nous avons connecté la broche Vréf du MCP3008 à la broche 3,3V du Pi). Cette valeur (en mV) est codée sur 10 bits (soit 2^10=1024 valeurs possibles) puis envoyée sur le bus SPI. Nous obtiendrons donc un nombre entier entre 0 et 1023. Pour obtenir la valeur en mV, il nous suffit d’appliquer une « règle de 3 » :

mV = valeur * 3300 / 1024

La tension renvoyée par le TMP36  se situe entre 0V pour -50°C et 1,75V pour 125°C, ce qui donne 1,75/(50+125)=0,01V soit 10mV par degré. Pour convertir les mV en degrés Celsius, nous devons donc réaliser le calcul suivant :

t °C = (mV / 10) - 50

(10mV par degré, puis on retire 50 car on part de -50°C à 0V)

Ci-dessous, un petit script Python, temperature_MCP3008_TMP36.py qui réalise toutes ces opérations et affiche la température en °C :

#!/usr/bin/env python

import time
import RPi.GPIO as GPIO

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

# initialise les ports du GPIO
GPIO.setup(24, GPIO.OUT)
GPIO.setup(23, GPIO.IN)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(25, GPIO.OUT)

# lit les donnees SPI du MCP3008 et renvoie un entier entre 0 et 1023
def readspi(mcp3008_input):
  GPIO.output(25, True)
  GPIO.output(18, False)
  GPIO.output(25, False)
  commandout = mcp3008_input
  commandout |= 0x18
  commandout <<= 3
  for i in range(5):
    if (commandout & 0x80):
      GPIO.output(24, True)
    else:   
      GPIO.output(24, False)
    commandout <<= 1
    GPIO.output(18, True)
    GPIO.output(18, False)
  bitout = 0
  for i in range(12):
    GPIO.output(18, True)
    GPIO.output(18, False)
    bitout <<= 1
    if (GPIO.input(23)):
      bitout |= 0x1
  GPIO.output(25, True)
  bitout /= 2
  return bitout

# boucle principale qui realise les calculs et affiche le resultat toutes les 5 secondes
while True:
  try:
    bitout = readspi(0) # lit les donnees de l'entree 0 du MCP3008
    mV = bitout * ( 3300.0 / 1024.0) # convertit la valeur en mV
    tC = (mV/10.0) - 50.0 # convertit les mV en degre Celsius
    tC = "%.1f" % tC # ne garde que une decimale
    print(tC)
    time.sleep(5)
  except KeyboardInterrupt:
    quit()

Et voilà 🙂 Il ne vous reste plus qu’à envoyer cette température à votre dashscreen pour afficher la température ambiante de votre salon 🙂

Sonde numérique DS18B20 et bus 1-Wire

DS18B20
DS18B20

Alimentée en 3V ou 5V la sonde numérique DS18B20 offre une précision de 0,5°C, et permet de mesurer des températures entre -55°C et +125°C. Cette sonde utilise un bus 1-Wire qui permet de se passer d’un convertisseur analogique/numérique, et occupe ainsi une seule broche du port GPIO du Pi (en dehors des deux broches d’alimentation). Pour assurer le bon fonctionnement de cette sonde, il convient d’utiliser une résistance dite « pullup » pour appliquer une tension de « référence » à la borne centrale du composant. Dans notre cas, et avec un Pi, il convient d’utiliser une résistance de 4,7k ohm.

Le schéma ci-dessous montre comment brancher la sonde DS18B20 et la résistance sur le GPIO du Pi :

raspberry_pi_ds18b20Pour faciliter le montage, vous pouvez souder la sonde et la résistance sur un petit morceau de plaque epoxy :

IMG_5768Passons à la partie logicielle qui est ici très simple. En effet, il suffit de charger les modules 1-wire nécessaires pour voir apparaitre un nouveau périphérique dans le répertoire /sys/bus/w1/devices :

modprobe w1-gpio
modprobe w1-therm
ls -l /sys/bus/w1/devices/
total 0
lrwxrwxrwx 1 root root 0 Dec  3 21:02 28-000005305b19 -> ../../../devices/w1_bus_master1/28-000005305b19
lrwxrwxrwx 1 root root 0 Dec  3 20:59 w1_bus_master1 -> ../../../devices/w1_bus_master1

Ici, ma sonde est détectée avec le numéro 28-000005305b19. Ce numéro est normalement unique et « gravé » en usine directement dans le composant. Si vous utilisez plusieurs DS18B20, vous devriez avoir plusieurs périphériques avec des numéros différents 🙂

Si vous lisez le contenu de ce nouveau périphérique, vous devriez obtenir quelque chose de ce type :

cat /sys/bus/w1/devices/w1_bus_master1/28-000005305b19/w1_slave 
7a 01 4b 46 7f ff 06 10 0b : crc=0b YES
7a 01 4b 46 7f ff 06 10 0b t=23625

La température est directement affichée en degré Celsius t=23625 🙂 Ou presque, car il faut tout de même diviser cette valeur par 1000.

Voici donc un petit script temperature_DS18B20.py dont le rôle est de lire le contenu de ce fichier et d’en extraire la température 🙂

#!/usr/bin/python

import os, glob, time, datetime

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

device_file='/sys/bus/w1/devices/28-000005305b19/w1_slave'

# lit le contenu du peripherique et extrait la temperature puis la divise par 1000
def read_temp():
  f = open(device_file, 'r')
  lines = f.readlines()
  f.close()
  temp_string = lines[1].strip()[-5:]
  temp_c = float(temp_string)/1000.0
  return temp_c

# boucle principale qui affiche la température toutes les 5 secondes
while True:
  try:
    tC = read_temp()
    print(tC)
    time.sleep(5)
  except KeyboardInterrupt:
    quit()

Et voilà, très simple, très économique, et relativement précis 🙂

TMP36 vs DS18B20

Par curiosité j’ai réalisé un script qui compare la température mesurée par le TMP36 et le DS18B20 :

TMP36 : 22.8 - DS18B20 : 23.2
TMP36 : 22.5 - DS18B20 : 23.2
TMP36 : 22.5 - DS18B20 : 23.2
TMP36 : 22.5 - DS18B20 : 23.2
TMP36 : 22.5 - DS18B20 : 23.2
TMP36 : 22.8 - DS18B20 : 23.3
TMP36 : 27.3 - DS18B20 : 28.0
TMP36 : 29.3 - DS18B20 : 29.4
TMP36 : 28.3 - DS18B20 : 28.3
TMP36 : 26.7 - DS18B20 : 27.1
TMP36 : 25.7 - DS18B20 : 26.4
TMP36 : 24.8 - DS18B20 : 25.9
TMP36 : 24.4 - DS18B20 : 25.6
TMP36 : 24.1 - DS18B20 : 25.4
TMP36 : 23.8 - DS18B20 : 25.2
TMP36 : 23.8 - DS18B20 : 25.1
TMP36 : 23.8 - DS18B20 : 25.0

Pour faire augmenter la température, j’ai posé un doigt sur chaque sonde. On constate que les deux sondes mesures des températures très proches. Le DS18B20 mesure cependant une température d’environ 0,5°C plus chaude que le TMP36.

Dans tous les cas, on ne peut qu’espérer une précision à 0,5°C. J’ai pu constater que ma station météo ainsi qu’un autre thermomètre de mon appartement affichent des températures similaires, avec des écarts jusqu’à 1°C.

22 réflexions au sujet de « GPIO – Capteurs de température »

  1. @rno

    Bonjour,

    J’ai vu ce montage plusieurs fois sur le web et l’ai réalisé.

    Malheureusement, je n’obtiens pas la température. Il s’affiche toujours 85°. Il semblerait d’après la doc constructeur du DS18B20, qu’il s’agisse de la température affichée lors du reset.

    J’ai retourné le montage dans tous les sens. Ma résistance de Pull Up mesurée à l’ohmmètre fait 4,68 k. C’est une 1W (j’avais pas de 1/4W) avec une précision de 5%

    Est-ce que ça pourrait venir de là ?

    Merci de m’éclairer.

    @.

    Répondre
    1. Olivier Auteur de l’article

      Hum… En théorie si la résistance est bien dimensionnée, ça devrait fonctionner correctement…
      As tu bien positionné la résistance au bon endroit ?

      Répondre
      1. Loan

        Bonjour,
        J’ai exactement le meme problème, ma résistance est de 4.67K. Quelqu’un a une solution

        Répondre
        1. Olivier Auteur de l’article

          Hello,
          Es tu certain d’avoir positionné ta résistance au bon endroit du circuit ?

          Répondre
  2. Creus

    Bonjour,

    Je voulais savoir comment faire si je veux connecter plusieurs sondes sur le circuit ? Quel est le nombre max de sonde ?

    Merci pour votre réponse.

    Répondre
    1. Olivier Auteur de l’article

      Bonjour,
      D’après ce que j’ai pu lire sur le net, le Pi peut adresser jusqu’à 10 composants 1-wire sur le même bus 🙂
      Pour la sonde de température DS18B20, il suffit de les brancher en parallèle sur les mêmes broches du GPIO 🙂
      Bonne continuation 🙂

      Répondre
  3. @rno

    Ok, alors en fait j’avais une DS18B20 PAR, c’est-à-dire une sonde qui se branche en mode parasite. Et à priori, ça ne fonctionne pas avec le RPI. J’ai acheté une DS18B20 normale et ça marche. J’en ai même mis 2 en parallèle. Sans problème.

    Merci à ceux qui ont pris la peine de me lire.

    Répondre
  4. Bertrand

    Bonjour,

    Merci pour ce tuto très instructif.

    Une petite question cependant: dans le montage avec la sonde numérique DS18B20, est-il possible d’utiliser d’autres ports du GPIO ? Par exemple:
    – Le 14 pour le Ground.
    – Le 17 pour le 3.3v.
    – Et un autre (15, 16 ou autre) à la place du 7.

    Et en adaptant éventuellement le code évidemment.

    Car les ports que tu utilises sont déjà occupés sur mon RPI (carte Razberry).

    Merci de ton aide.

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      A vérifier, mais je crois savoir que le bus 1-wire n’est supporté que sur la broche 7 du GPIO :/

      Répondre
  5. michae

    bonjour
    tout d’abord, merci pour le tuto, c’est très utile 🙂

    j’ai par contre un léger souci.

    quand je lance le script il m’affiche cette erreur :

    IOError: [Errno 2] No such file or directory: ‘/sys/bus/w1/devices/28-000004dc024d/w1_slave’

    si je le relance directement ensuite, tout fonctionne.. et cela a chaque reboot ..

    une idée de pourquoi ? (je voudrais pouvoir le lancer en cron au boot, mais du coup cela ne fonctionne pas..)
    Merci.

    Répondre
    1. michae

      j’ai trouvé la solution
      il suffit de charger ces deux modules au boot du pi

      w1-gpio
      w1-therm

      dans le fichier /etc/modules

      Répondre
      1. Olivier Auteur de l’article

        Hello,
        Navré de na pas t’avoir répondu plus tôt, et content de voir que tu as pu trouver la solution seul 😉

        Répondre
  6. skon07

    bonjour,
    tout d’abord merci pour le tuto.
    J’ai un petit problème, j’ai pas trouvé le capteur de température DS18B20, j’ai trouvé LM35, si je travaille avec ce capteur c’est la même démarche que vous avez proposé avec le DS18B20?

    Répondre
    1. Olivier Auteur de l’article

      Bonjour,
      Le DS18B20 est très répandu, vous pouvez le trouver ici par exemple : Amazon.fr – DS18B20 1-Wire Digital Thermometer.
      Le LM35 ne fonctionne pas en 1-wire comme le DS18B20. Le LM35 a un fonctionnement similaire au TMP36 utilisé dans l’article, vous devrez donc utiliser un convertisseur analogique/numérique comme le MCP3008 pour pouvoir le faire fonctionner avec un Pi.
      Le plus simple est donc de partir sur le DS18B20 🙂
      Bonne continuation,

      Répondre
  7. sky99

    Bonjour Olivier, je fais des recherches sur le sujet, et je souhaiterais signaler un petit problème : le MCP3008 présente une impédance d’entrée qui semble faible. Le problème de l’impédence d’entrée, c’est que si elle est de 10Mohms sur une entrée, il faut que les capteurs que l’on branche dessus aient une impédance inférieure de façon significative ( par exemple 1%). Sur le Arduino, l’impédance d’entrée est élevée (dans l’ordre du mégaohm), donc tout va bien. En revanche, il semble qu’ici elle est assez basse, alors que le TMP36 a une impédance assez élevée. Des gens sur le net disent avoir corrigé le problème en mettant un condensateur sur l’alimentation du TMP36, il faudra que je fasse des tests. Je vais essayer de comparer les résultats avec et sans, et par rapport à un DS18B20, un DHT11 et un DHT22.

    Répondre
    1. Olivier Auteur de l’article

      Hello.
      Merci pour l’info, le retour d’expérience m’intéresse 🙂 n’hésites pas à nous tenir au courant 🙂

      Répondre
  8. Ping : Pi BOAt - description des modules - MagdiBlog

    1. f-leb

      200 000 échantillons/seconde avec VDD=5V d’après la datasheet. Si tu as des signaux rapides ou que tu utilises plusieurs entrées du MCP3008, le gain de vitesse d’acquisition pourrait t’intéresser… Et avec VDD=5V, tu peux choisir VREF jusqu’à 5V.

      Répondre
  9. PERRIN René

    Bonjour

    Je n’arrive pas à déclencher le fichier d’ou l’erreur ci-dessous je suis débutant dans le système linux. D’avance merçi pour une réponse.

    root@raspberrypi:~# python3 temperature_ds18B20.py
    Traceback (most recent call last):
    File « temperature_ds18B20.py », line 22, in
    tC = read_temp()
    File « temperature_ds18B20.py », line 12, in read_temp
    f = open(device_file, ‘r’)
    IOError: [Errno 2] No such file or directory: ‘/sys/bus/w1/devices/28-000005305b

    Répondre
  10. multinet

    Bonjour, je ne sais pas très bien où poster ma question mais je pense que ce thread est le ‘moins eloigné’.

    Je recherche une solution pour un probleme tout bete : je souhaiterai pouvoir piloter depuis mon raspberry l’ouverture de mon portail.

    Pour cela, mon portal est équipé d’un bornier avec 2 cosses sur lequel je peux brancher un bouton poussoir : j’appuie sur le bouton (contact entre les deux bornes) ca ouvre le portail.

    Je me demande donc comment avec les GPIO je peux remplacer ce bouton poussoir physique pour piloter l’ouverture avec mon raspberry

    Si j’ai bien compris les GPIO en outpout ca n’est pas la solution vu que c’est du on/off et que ca envoi de la tension entre le + et le pin du gpio

    Si vous avez la solution je suis tres interessé par les explications 🙂

    Merci

    Répondre

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.