Capteurs de température et d’humidité DHT11 et DHT22

Ce tutoriel explique comment mettre en oeuvre des capteurs de température et d’humidité relative DHT11 et DHT22 (Grove et autres) en MicroPython. Ces capteurs sont très peu onéreux. Le DHT22, tout du moins dans l’implémentation en module Grove que nous avons testée, donne des mesures très précises et fiables d’humidité et de température. Notez bien que le DHT11 n’est pas capable de mesurer des températures inférieures à 0°C. Les figures ci-dessous montrent un module Grove intégrant un DHT11 (à gauche) et un module Grove intégrant un DHT22 (à droite).

Grove - Temperature&Humidity Sensor(DHT11) Grove - Temperature&Humidity Sensor Pro(DHT22)

Crédit images : Seeed Studio

Ces capteurs utilisent un protocole de communication qui leur est propre et qui ne nécessite que trois fils : une masse, une alimentation et une seule ligne de communication. Ce protocole est particulièrement délicat à programmer car il implique des mesures de fronts de signaux avec une précision de quelques millisecondes.

Matériel requis

  1. Une carte d’extension de base Grove
  2. La carte NUCLEO-WB55
  3. Un module Grove Temperature&Humidity Sensor Pro (DHT22)

Le code MicroPython

Les scripts présentés ci-après sont disponibles dans la zone de téléchargement.

Il faut ajouter le fichier dht.py dans le répertoire du périphérique PYBLASH. Editez maintenant le script main.py et copiez-y le code qui suit :

# Objet du script : utiliser un capteur d'humidité et de température
# de la famille DHT (DHT11 ou DHT22).

import dht # Pour gérer les DHT11 et DHT22
from time import sleep_ms # Pour temporiser

# Instanciation du DHT22
capteur = dht.DHT22('D2') 

# Pour un DHT11, utilisez simplement cette syntaxe :
# capteur = dht.DHT11('D2')

while True:

	# Structure de gestion des exceptions
	try:
		
		# On mesure et on lit les résultats
		capteur.measure()
		temp = capteur.temperature()
		humi = capteur.humidity()
		
		# Si les deux mesures renvoient 0 simultanément
		if humi == 0 and temp == 0:
			raise ValueError("Erreur capteur")

		# Formattage (arrondis) des mesures
		temperature = round(temp,1)
		humidity = int(humi)

		# Affichage des mesures
		print('=' * 40) # Imprime une ligne de séparation
		print("Température : " + str(temperature) + " °C")
		print("Humidité relative : " + str(humidity) + " %")

	# Si une exception est capturée
	except Exception as e:
		print(str(e) + '\n')

	# Temporisation de deux secondes
	sleep_ms(2000)

Affichage sur le terminal série de l’USB User

Une fois le script lancé avec CTRL-D, vous pourrez observer les valeurs d’humidité et de température qui défilent :

One Wire output

Pour aller plus loin

Les scripts présentés ci-après sont disponibles dans la zone de téléchargement.

Si le protocole de communication des capteurs DHTxx vous intéresse, vous trouverez une explication (pour Arduino) à ce sujet ici et une implémentation explicite en MicroPython à base de timers pour le DHT22 ici.

Ce dernier exemple aurait pu servir de base à notre tutoriel, mais après adaptation pour la NUCLEO-WB55, il est apparu qu’il fonctionne correctement avec la révision 1.17 mais pas avec certaines révisions antérieures.

  • Tout d’abord la bibliothèque dht22.py :
# Exemple adapté de https://github.com/kurik/uPython-DHT22/blob/master/main.py
# Construction d'un pilote pour le DHT22 en utilisant un timer pour compter les
# fronts (descendants) des signaux.

from time import sleep_ms # Pour temporiser
from pyb import ExtInt, Pin, Timer # Pour gérer les broches, les interruptions des broches et les Timers.

# Nous devons utiliser ici des variables globales car toute allocation de variable locale
# entrainerait un délai qui planterait la communication.

data = None
timer = None
micros = None

FALL_EDGES = const(42) # La réception comporte 42 fronts descendants

times = list(range(FALL_EDGES))
index = 0

# Le gestionnaire d'interruptions : capture la réponse du capteur après lee START
def edge(line):

	global index
	global times
	global micros

	times[index] = micros.counter()
	if index < (FALL_EDGES - 1): # Pour éviter un dépassement de buffer s'il y a du bruit sur la ligne
		index += 1

# Initialisation du capteur
def init(timer_id = 2, data_pin = 'D2'):

	global data
	global micros
	
	# Broche de la ligne de communication
	data = Pin(data_pin)
	
	# Identifiant du timer sélectionné
	timer = timer_id
	
	# Paramètres pour un timer de fréquence 1 microseconde
	micros = Timer(timer, prescaler=65, period=0x3fffffff)

	# Gestionnaire de l'interruption du timer
	ExtInt(data, ExtInt.IRQ_FALLING, Pin.PULL_UP, edge)

def do_measurement():

	global data
	global micros
	global index

	# Envoie la commande START
	data.init(Pin.OUT_PP)
	data.low()
	micros.counter(0)
	while micros.counter() < 25000:
		pass
		
	# Passe la broche en IN
	data.high()
	micros.counter(0)
	index = 0
	data.init(Pin.IN, Pin.PULL_UP)

	# Après 5 millisecondes, la mesure doit être terminée
	sleep_ms(5)
	
# Lis les données renvoyées par le capteur
def process_data():
	global times
	i = 2 # On ignore les deux premiers fronts descendants qui sont la réponse à la commande START
	result_i = 0
	result = list([0, 0, 0, 0, 0])
	
	while i < FALL_EDGES:
		result[result_i] <<= 1
		if times[i] - times[i - 1] > 100:
			result[result_i] += 1
		if (i % 8) == 1:
			result_i += 1
		i += 1
		
	[int_rh, dec_rh, int_t, dec_t, csum] = result
	humidity = ((int_rh * 256) + dec_rh)/10
	temperature = (((int_t & 0x7F) * 256) + dec_t)/10
	if (int_t & 0x80) > 0:
		temperature *= -1
	comp_sum = int_rh + dec_rh + int_t + dec_t
	if (comp_sum & 0xFF) != csum:
		raise ValueError('La somme de contrôle est incorrecte')
	return (humidity, temperature)

def measure():
	do_measurement()
	if index != (FALL_EDGES -1):
		raise ValueError('Echec du transfert de données : %s fronts descendants seulement' % str(index))
	return process_data()
  • Ensuite le fichier main.py :
# Exemple adapté de https://github.com/kurik/uPython-DHT22/blob/master/main.py
# Objet du script : Mise en oeuvre du capteur de température et humidité DHT22
# Deuxième approche : utilisation d'une classe exploitant les interruption d'un timer

import dht22 # Pour gérer le DHT22
from time import sleep_ms # Pour temporiser

# Initialisation du pilote du DHT22.
# On a besoin du timer 2 pour celui-ci
dht22.init(timer_id = 2, data_pin = 'D2')

while True:

	# Pour gérer les exceptions
	try:
		# Recupération des mesures (2-uple)
		(hum, tem) = dht22.measure()
		
		# En cas de retour erroné sur les deux mesures simultanément
		if hum == 0 and tem == 0:
			raise ValueError("Erreur capteur")

		# Formattage (arrondis) des mesures
		temp = round(tem,1)
		humi = int(hum)

		# Affichage des mesures
		print('=' * 40) # Imprime une ligne de séparation
		print("Température : " + str(temp) + " °C")
		print("Humidité relative : " + str(humi) + " %")

	# Si une exception est survenue
	except Exception as e:
		print(str(e) + '\n')

	# Temporisation de deux secondes
	sleep_ms(2000)