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.
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 |
---|---|
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 :
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 |
---|
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 :
Pour faciliter le montage, vous pouvez souder la sonde et la résistance sur un petit morceau de plaque epoxy :
Passons à 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.
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.
@.
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 ?
Bonjour,
J’ai exactement le meme problème, ma résistance est de 4.67K. Quelqu’un a une solution
Hello,
Es tu certain d’avoir positionné ta résistance au bon endroit du circuit ?
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.
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 🙂
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.
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.
Hello,
A vérifier, mais je crois savoir que le bus 1-wire n’est supporté que sur la broche 7 du GPIO :/
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.
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
Hello,
Navré de na pas t’avoir répondu plus tôt, et content de voir que tu as pu trouver la solution seul 😉
pas de soucis 🙂
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?
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,
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.
Hello.
Merci pour l’info, le retour d’expérience m’intéresse 🙂 n’hésites pas à nous tenir au courant 🙂
Ping : Pi BOAt - description des modules - MagdiBlog
Pour le MCP3008, est t’il mieux de choisir une alimentation de 3,3V ou de 5V ?
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.
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
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