Yahoo refuse tous les emails du site. Si vous avez une adresse chez un autre prestataire, c'est le moment de l'utiliser
En cas de soucis, n'hésitez pas à aller faire un tour sur la page de contact en bas de page.
Utiliser un capteur de température et d'humidité DHT11 / DHT22 avec une carte Arduino / Genuino
Et non, une humidité relative de 100% ne signifie pas que l'on nage dans une piscine

par skywodd | | Licence (voir pied de page)
Catégories : Tutoriels Arduino | Mots clefs : Arduino Genuino Humidité DHT11 DHT22 DHT21 AM2302 Capteur Température
Cet article a été modifié pour la dernière fois le
Cet article n'a pas été mis à jour depuis un certain temps, son contenu n'est peut être plus d'actualité.
Dans ce tutoriel, nous allons apprendre ensemble à communiquer avec un capteur de température et d'humidité, le DHT22 et son petit frère, le DHT11. Nous verrons les caractéristiques de ses capteurs, leurs fonctionnements et comment les utiliser. En bonus, nous verrons comment calculer le point de rosée, pour les amateurs de météo.
Sommaire
- Le capteur DHT22 et son petit frère le DHT11
- Câblage d'un capteur DHTxx
- Le protocole de communication
- Le montage de démonstration
- Le code de démonstration
- Bonus : calcule du point de rosée ("dew point")
- Bonus : conversion degrés Celsius vers Fahrenheit ou Kelvin
- Conclusion
Bonjour à toutes et à tous !
Si vous lisez cet article en été, vous êtes sûrement en train de travailler. Il fait chaud, l'air est lourd et vous avez l'impression de vous liquéfier sur votre siège. Voilà une situation des plus classique et des plus désagréable.
Dans ce genre de situation, trois questions vous traverse normalement l'esprit : "Quelle température fait-il ?", "Pourquoi fait-il aussi lourd !?" et "Que ce passerait-il si j'essayé de dormir dans ma baignoire ?".
Savoir mesurer la température et l'humidité d'une zone est une information très utile, en particulier pour prédire la météo ou pour stocker du matériel et des aliments dans de bonnes conditions.
Se pose donc la question suivante : comment mesurer (simplement) à la fois la température et l'humidité d'une pièce ou d'un contenant avec une carte Arduino / Genuino ? C'est le sujet de l'article d'aujourd'hui.
Le capteur DHT22 et son petit frère le DHT11
Capteur DHT22 versus capteur DHT11
Le capteur DHT22 (aussi connu sous la référence AM2302) et son petit frère le DHT11 sont des capteurs de température et d'humidité "deux en un".
Le capteur DHT22 / AM2302 est capable de mesurer des températures de -40 à +125°C avec une précision de +/- 0.5°C et des taux d'humidité relative de 0 à 100% avec une précision de +/- 2% (+/- 5% aux extrêmes, à 10% et 90%). Une mesure peut être réalisée toutes les 500 millisecondes (soit deux fois par seconde).
Le capteur DHT11 est lui capable de mesurer des températures de 0 à +50°C avec une précision de +/- 2°C et des taux d'humidité relative de 20 à 80% avec une précision de +/- 5%. Une mesure peut être réalisée toutes les secondes.
Le DHT22 et le DHT11 sont tous les deux compatibles 3.3 volts et 5 volts (le fabricant recommande cependant de toujours alimenter le capteur en 5 volts pour avoir des mesures précises). Ils ont aussi le même câblage et le même protocole de communication.
Pour résumer, voici les caractéristiques des deux capteurs sous forme de tableau comparatif :
DHT22 / AM2302 |
DHT11 |
|
---|---|---|
Humidité (relative %) |
0 ~ 100 % |
20 ~ 80% |
Précision (humidité) |
+/- 2% (+/- 5% aux extrêmes) |
+/- 5% |
Température |
-40 ~ +150°C |
0 ~ +50°C |
Précision (température) |
+/- 0.5°C |
+/- 2°C |
Fréquence mesure max |
2Hz (2 mesures par seconde) |
1Hz (1 mesure par seconde) |
Tension d'alimentation |
3 ~ 5 volts |
3 ~ 5 volts |
Stabilité à long terme |
+/- 0.5% par an |
+/- 1% par an |
Le DHT22 est clairement beaucoup plus précis et stable que le DHT11. Mais il est aussi deux fois plus cher. Le choix se résume donc à une question de balance entre budget, précision et rapidité de mesure.
En toute franchise, si vous voulez des mesures à peu près correctes, utilisez un DHT22, ou mieux, des capteurs d'humidité et de température spécialisés. Les capteurs DHTxx sont assez imprécis en général et tout particulièrement les DHT11 qui sont pour ainsi dire inutilisables en capteur d'humidité tellement la mesure est imprécise.
Le DHT11 ne peut pas mesurer (et supporter) des températures négatives ou des températures supérieures à 50°C. Attention donc en cas d'utilisation en extérieur !
N.B. Les capteurs DHT11 et DHT22 sont disponibles seuls ou précablés sur un petit circuit. C'est le cas par exemple du capteur DHT11 visible sur la photographie ci-dessus (le capteur bleu).
Câblage d'un capteur DHTxx
Quel que soit votre choix de capteur DHTxx, le câblage est le même.
Les capteurs DHTxx communiquent avec le microcontrôleur via une unique broche d'entrée / sortie, dont on verra ensemble le protocole de communication dans le chapitre suivant.
Le brochage du capteur est le suivant :
La broche n°1 est la broche d'alimentation (5 volts ou 3.3 volts).
La broche n°2 est la broche de communication. Celle-ci doit impérativement être reliée à l'alimentation via une résistance de tirage de 4.7K ohms (il s'agit d'une sortie à collecteur ouvert).
La broche n°3 n'est pas utilisée et ne doit pas être câblée.
La broche n°4 est la masse du capteur (GND).
N.B. Un condensateur de 100nF est requis entre les broches n°1 et n°4 pour que le capteur fonctionne correctement. On verra cela lors de la réalisation du montage de démonstration.
Le protocole de communication
Comme précisé précédemment, les capteurs DHTxx ont la particularité de communiquer avec le microcontrôleur via une unique broche d'entrée / sortie.
Bien que cela soit marqué "One Wire" un peu partout sur le document constructeur du capteur, il ne s'agit pas d'un véritable bus de communication 1-Wire. Il s'agit simplement d'un protocole de communication propriétaire, utilisant un seul fil et nécessitant des timings très précis.
Le déroulement d'une communication
Format d'une trame de communication
Détails du format d'une trame de communication (capteur DHT22)
La communication avec un capteur DHTxx se fait en 3 étapes :
Tout d'abord, le microcontrôleur maître (la carte Arduino dans notre cas) réveille le capteur en plaçant la ligne de données à
LOW
pendant au moins 800µs (au moins 18ms pour le DHT11). Durant ce laps de temps, le capteur va se réveiller et préparer une mesure de température et d'humidité. Une fois le temps écoulé, le maître va libérer la ligne de données et passer en écoute.Une fois la ligne de données libérée, le capteur répond au maître (pour montrer qu'il est bien réveillé) en maintenant la ligne de données à
LOW
pendant 80µs puis àHIGH
pendant 80µs.Le capteur va ensuite transmettre une série de 40 bits (5 octets). Les deux premiers octets contiennent la mesure de l'humidité. Les deux octets suivants contiennent la mesure de la température et le cinquième octet contient une somme de contrôle qui permet de vérifier que les données lues sont correctes.
N.B. La broche de communication des capteurs DHTxx est de type "collecteur ouvert".
La sortie du capteur ne génère pas de tension. Elle ne fait que commuter (via un transistor) la tension au niveau de la résistance de tirage sur la ligne de données.
Dans ce contexte, HIGH
est la tension de la résistance de tirage et LOW
la tension à la masse (0 volt). Cela peut paraitre complexe, mais sans cette sortie à collecteur ouvert,
il ne serait pas possible d'alimenter le capteur en 5 volts tout en ayant une résistance de tirage à 3.3 volts (dans le cas d'un montage avec une carte Arduino en 3.3 volts derrière).
Détails du format d'une trame de communication (capteur DHT11)
Il est bon de noter que même si le DHT11 et DHT22 partagent le même protocole de communication, la façon dont les valeurs sont transmises est différente.
Le DHT11 ne peut mesurer que des températures supérieures à zéro et à une précision faible qui rend inutile de transmettre des valeurs à virgules. Au contraire, le DHT22 peut mesurer des températures négatives et des valeurs avec une précision à 0.1 unité près.
On verra dans le chapitre "code" la façon dont sont codées les valeurs dans les deux cas.
Le montage de démonstration
Afin de comprendre comment utiliser un capteur DHT22 ou DHT11 avec une carte Arduino, nous allons faire un petit montage de démonstration très simple.
Dans notre montage, la carte Arduino va lire la température et l'humidité ambiante et envoyer les valeurs mesurées à l'ordinateur via le câble USB.
Pour réaliser ce montage, il va nous falloir :
Une carte Arduino UNO (et son câble USB),
Un capteur DHT11 ou DHT22 (ou AM2302),
Une résistance de 4.7K ohms – code couleur jaune / violet / rouge,
Un condensateur de 100nF,
Une plaque d'essai et des fils pour câbler notre montage.
N.B. Si vous disposez d'un module précâblé, la résistance et le condensateur doivent normalement déjà être câblés et sont donc inutiles dans ce cas.
Pour commencer notre montage, nous allons câbler les deux broches d'alimentation du capteur (broche n°1 et broche n°4) respectivement aux broches 5V
et GND
de la carte Arduino.
Dans la foulée, on câblera le condensateur de 100nF entre les broches n°1 et n°4 du capteur, en parallèle des broches d'alimentation. Les condensateurs de 100nF ne sont pas polarisés, ils peuvent donc être câblés dans n'importe quel sens.
On achève ensuite le circuit en reliant la résistance de 4.7K ohms d'un côté à la broche n°1 du capteur (+5v) et de l'autre à la broche n°2 du capteur (sortie du signal).
Pour finir, on câble la broche n°2 du capteur à la broche D5
de la carte Arduino avec un fil.
Dans le cas d'une utilisation avec une carte Arduino 3.3 volts, il faudra relier l'alimentation du capteur à la broche 5V
de la carte Arduino et la résistance de tirage à la broche 3.3 volts.
Si vous utilisez une carte Arduino 3.3 volts, ne câblez pas la résistance de tirage au 5 volts, sinon vous allez détruire votre carte !
N.B. La broche n°3 du capteur doit rester non connectée. C'est normal.
Le code de démonstration
Le code de démonstration de ce chapitre mesure la température et l'humidité ambiante et affiche le résultat sur le port série. Ce code est conçu pour fonctionner avec des capteurs DHT11 et DHT22.
Je préviens de suite, le code est complexe, très complexe même. Cela est dû aux timings très précis nécessaires pour la communication avec le capteur. Je vais essayer d'expliquer le code le plus simplement possible, mais un cachet d'aspirine risque d'être nécessaire pour finir la lecture.
Si vous voulez simplement utiliser le code sans le comprendre, regardez les commentaires dans le code d'exemple complet un peu plus bas
1 2 3 4 5 6 7 | /** Broche "DATA" du capteur */
const byte BROCHE_CAPTEUR = 5;
/* Code d'erreur de la fonction readDHT11() et readDHT22() */
const byte DHT_SUCCESS = 0; // Pas d'erreur
const byte DHT_TIMEOUT_ERROR = 1; // Temps d'attente dépassé
const byte DHT_CHECKSUM_ERROR = 2; // Données reçues erronées
|
Le code commence comme d'habitude avec la déclaration des constantes pour le programme.
Ici on déclare plusieurs constantes : une constante pour la broche du capteur et trois constantes pour les codes d'erreurs de la fonction qui va lire le capteur. Ces trois constantes nous permettront plus tard de détecter et gérer les erreurs de lecture du capteur.
1 2 3 4 5 6 7 8 9 10 | /** Fonction setup() */
void setup() {
/* Initialisation du port série */
Serial.begin(115200);
Serial.println(F("Demo DHT11 et DHT22"));
/* Place la broche du capteur en entrée avec pull-up */
pinMode(BROCHE_CAPTEUR, INPUT_PULLUP);
}
|
La fonction setup()
fait deux choses dans cet exemple : initialiser le port série à une vitesse de 115200 bauds pour l'affichage des valeurs mesurées
et mettre la broche du capteur en entrée avec résistance de tirage.
La mise en entrée de la broche n'est pas strictement nécessaire en soi. C'est juste une sécurité pour éviter de réveiller prématurément le capteur lors du démarrage de la carte Arduino.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** Fonction loop() */
void loop() {
float temperature, humidity;
/* Lecture de la température et de l'humidité, avec gestion des erreurs */
// N.B. Remplacer readDHT11 par readDHT22 en fonction du capteur utilisé !
switch (readDHT22(BROCHE_CAPTEUR, &temperature, &humidity)) {
case DHT_SUCCESS:
/* Affichage de la température et du taux d'humidité */
Serial.print(F("Humidite (%): "));
Serial.println(humidity, 2);
Serial.print(F("Temperature (^C): "));
Serial.println(temperature, 2);
break;
case DHT_TIMEOUT_ERROR:
Serial.println(F("Pas de reponse !"));
break;
case DHT_CHECKSUM_ERROR:
Serial.println(F("Pb de communication !"));
break;
}
/* Pas plus d'une mesure par seconde */
// N.B. Avec le DHT22 il est possible de réaliser deux mesures par seconde
delay(1000);
}
|
La fonction loop()
fait trois choses : elle lit le capteur, affiche le résultat de la lecture et attend une seconde avant de recommencer.
La lecture du capteur se fait via la fonction readDHT22()
que l'on étudiera tout à l'heure (une fonction semblable nommée readDHT11()
sera aussi présentée pour les utilisateurs de DHT11).
Cette fonction prend en argument le numéro de la broche du capteur à lire et deux pointeurs vers des variables de type float
qui contiendront le résultat des mesures.
PS Le &
devant les deux noms de variables est une syntaxe qui permet d'obtenir un pointeur sur la variable en question.
Cette fonction retourne un code d'erreur :
DHT_SUCCESS
si la lecture c'est bien passée,
DHT_TIMEOUT_ERROR
si le capteur n'a pas répondu
et DHT_CHECKSUM_ERROR
si le capteur a répondu, mais que les données sont corrompues.
On pourrait utiliser une cascade de if
/ else
pour tester le code de retour, mais cela ne serait pas très pratique à lire par la suite.
J'utilise donc un switch / case pour gérer les valeurs de retour possibles.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | byte readDHT11(byte pin, float* temperature, float* humidity) {
/* Lit le capteur */
byte data[5];
byte ret = readDHTxx(pin, data, 18, 1000);
/* Détecte et retourne les erreurs de communication */
if (ret != DHT_SUCCESS)
return ret;
/* Calcul la vraie valeur de la température et de l'humidité */
*humidity = data[0];
*temperature = data[2];
/* Ok */
return DHT_SUCCESS;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | byte readDHT22(byte pin, float* temperature, float* humidity) {
/* Lit le capteur */
byte data[5];
byte ret = readDHTxx(pin, data, 1, 1000);
/* Détecte et retourne les erreurs de communication */
if (ret != DHT_SUCCESS)
return ret;
/* Calcul la vraie valeur de la température et de l'humidité */
float fh = data[0];
fh *= 256;
fh += data[1];
fh *= 0.1;
*humidity = fh;
float ft = data[2] & 0x7f;
ft *= 256;
ft += data[3];
ft *= 0.1;
if (data[2] & 0x80) {
ft *= -1;
}
*temperature = ft;
/* Ok */
return DHT_SUCCESS;
}
|
La fonction readDHT11()
permet de lire un capteur DHT11.
La fonction readDHT22()
permet de lire un capteur DHT22.
Jusque là, rien de bien méchant. C'est après que ça se complique.
N.B. J'ai choisi de découper le code en plusieurs fonctions pour limiter le copier-coller ou le code inutile.
Ces deux fonctions commencent de la même façon : on déclare un tableau de 5 octets pour stocker les données du capteur et on appelle la fonction readDHTxx()
qui permet de lire un capteur DHT de manière brute, sans convertir les octets lus en valeurs utilisables.
Dans le cas du DHT11, la durée du signal de start est fixée à 18 millisecondes, contre 1 milliseconde pour le DHT22. Dans les deux cas, le timeout est de 1000 µs, soit une milliseconde.
Une fois le capteur lu, les deux fonctions suivent une logique similaire.
Premièrement, elles vérifient qu'il n'y a pas eu d'erreur de communication.
Si tout va bien, elles transforment les données brutes en valeurs utilisables, puis renvoient le code d'erreur DHT_SUCCESS
qui signifie que tout va bien.
Dans le cas du DHT11, la méthode de calcul de la température et de l'humidité est triviale.
Dans le cas du DHT22, c'est beaucoup plus complexe.
Il faut gérer la partie entière, la partie décimale et bien prendre en compte le signe pour les températures négatives.
Les plus curieux pourront se reporter à la capture d'écran de la documentation constructeur quelques chapitres plus haut
1 2 3 4 5 6 7 | /**
* Fonction bas niveau permettant de lire la température et le taux d'humidité (en valeurs brutes) mesuré par un capteur DHTxx.
*/
byte readDHTxx(byte pin, byte* data, unsigned long start_time, unsigned long timeout) {
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// start_time est en millisecondes
// timeout est en microsecondes
|
Accrochez-vous, ça va secouer
La fonction readDHTxx()
s'occupe de la communication avec les capteurs.
C'est une fonction générique qui se contente de suivre le protocole de communication pour lire les cinq octets de données du capteur, quelle que soit sa référence.
La fonction commence par mettre des zéros dans les cinq octets du tableau de sortie. Cela est nécessaire pour la suite du programme.
1 2 3 4 5 6 7 8 9 | /* Conversion du numéro de broche Arduino en ports / masque binaire "bas niveau" */
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *ddr = portModeRegister(port); // Registre MODE (INPUT / OUTPUT)
volatile uint8_t *out = portOutputRegister(port); // Registre OUT (écriture)
volatile uint8_t *in = portInputRegister(port); // Registre IN (lecture)
/* Conversion du temps de timeout en nombre de cycles processeur */
unsigned long max_cycles = microsecondsToClockCycles(timeout);
|
Ensuite, le code appelle différentes fonctions bas niveau du framework Arduino pour faire correspondre le numéro de broche à divers registres du processeur et masques binaires. Grâce à ces registres et masques, il est possible de manipuler la broche d'entrée sortie, sans avoir à passer par le framework Arduino.
Cela est nécessaire, car les timings requis pour une bonne communication avec un capteur DHT sont si précis que perdre
quelques microsecondes avec pinMode()
, digitalRead()
ou digitalWrite()
n'est pas envisageable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /* Evite les problèmes de pull-up */
*out |= bit; // PULLUP
*ddr &= ~bit; // INPUT
delay(100); // Laisse le temps à la résistance de pullup de mettre la ligne de données à HIGH
/* Réveil du capteur */
*ddr |= bit; // OUTPUT
*out &= ~bit; // LOW
delay(start_time); // Temps d'attente à LOW causant le réveil du capteur
// N.B. Il est impossible d'utilise delayMicroseconds() ici car un délai
// de plus de 16 millisecondes ne donne pas un timing assez précis.
/* Portion de code critique - pas d'interruptions possibles */
noInterrupts();
/* Passage en écoute */
*out |= bit; // PULLUP
delayMicroseconds(40);
*ddr &= ~bit; // INPUT
/* Attente de la réponse du capteur */
timeout = 0;
while(!(*in & bit)) { /* Attente d'un état LOW */
if (++timeout == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
timeout = 0;
while(*in & bit) { /* Attente d'un état HIGH */
if (++timeout == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Lecture des données du capteur (40 bits) */
for (byte i = 0; i < 40; ++i) {
/* Attente d'un état LOW */
unsigned long cycles_low = 0;
while(!(*in & bit)) {
if (++cycles_low == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Attente d'un état HIGH */
unsigned long cycles_high = 0;
while(*in & bit) {
if (++cycles_high == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Si le temps haut est supérieur au temps bas c'est un "1", sinon c'est un "0" */
data[i / 8] <<= 1;
if (cycles_high > cycles_low) {
data[i / 8] |= 1;
}
}
/* Fin de la portion de code critique */
interrupts();
/*
* Format des données :
* [1, 0] = humidité en %
* [3, 2] = température en degrés Celsius
* [4] = checksum (humidité + température)
*/
/* Vérifie la checksum */
byte checksum = (data[0] + data[1] + data[2] + data[3]) & 0xff;
if (data[4] != checksum)
return DHT_CHECKSUM_ERROR; /* Erreur de checksum */
else
return DHT_SUCCESS; /* Pas d'erreur */
}
|
Dans l'ordre :
le code place la broche en entrée avec résistance de tirage (au cas où cela ne serait pas déjà le cas),
le code passe la broche en sortie et envoi le signal de start pour réveiller le capteur,
le code désactive temporairement les interruptions pour avoir des timings précis,
le code passe la broche en entrée et attend une transition de
LOW
àHIGH
(avec timeout).Pour chacun des 40 bits de données :
le code mesure la durée de l'état bas du signal,
le code mesure la durée de l'état haut du signal,
si l'état haut est plus long que l'état bas, c'est un
1
,
une fois les 40 bits lus, le code réactive les interruptions,
et pour finir, vérifie que la somme de contrôle est valide afin de s'assurer de la bonne réception des données.
Le code complet avec commentaires :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | /**
* Exemple de code pour la lecture d'un capteur DHT11 ou DHT22.
*/
/** Broche "DATA" du capteur */
const byte BROCHE_CAPTEUR = 5;
/* Code d'erreur de la fonction readDHT11() et readDHT22() */
const byte DHT_SUCCESS = 0; // Pas d'erreur
const byte DHT_TIMEOUT_ERROR = 1; // Temps d'attente dépassé
const byte DHT_CHECKSUM_ERROR = 2; // Données reçues erronées
/** Fonction setup() */
void setup() {
/* Initialisation du port série */
Serial.begin(115200);
Serial.println(F("Demo DHT11 et DHT22"));
/* Place la broche du capteur en entrée avec pull-up */
pinMode(BROCHE_CAPTEUR, INPUT_PULLUP);
}
/** Fonction loop() */
void loop() {
float temperature, humidity;
/* Lecture de la température et de l'humidité, avec gestion des erreurs */
// N.B. Remplacer readDHT11 par readDHT22 en fonction du capteur utilisé !
switch (readDHT22(BROCHE_CAPTEUR, &temperature, &humidity)) {
case DHT_SUCCESS:
/* Affichage de la température et du taux d'humidité */
Serial.print(F("Humidite (%): "));
Serial.println(humidity, 2);
Serial.print(F("Temperature (^C): "));
Serial.println(temperature, 2);
break;
case DHT_TIMEOUT_ERROR:
Serial.println(F("Pas de reponse !"));
break;
case DHT_CHECKSUM_ERROR:
Serial.println(F("Pb de communication !"));
break;
}
/* Pas plus d'une mesure par seconde */
// N.B. Avec le DHT22 il est possible de réaliser deux mesures par seconde
delay(1000);
}
/**
* Lit la température et le taux d'humidité mesuré par un capteur DHT11.
*
* @param pin Broche sur laquelle est câblée le capteur.
* @param temperature Pointeur vers la variable stockant la température.
* @param humidity Pointeur vers la variable stockant le taux d'humidité.
* @return DHT_SUCCESS si aucune erreur, DHT_TIMEOUT_ERROR en cas de timeout, ou DHT_CHECKSUM_ERROR en cas d'erreur de checksum.
*/
byte readDHT11(byte pin, float* temperature, float* humidity) {
/* Lit le capteur */
byte data[5];
byte ret = readDHTxx(pin, data, 18, 1000);
/* Détecte et retourne les erreurs de communication */
if (ret != DHT_SUCCESS)
return ret;
/* Calcul la vraie valeur de la température et de l'humidité */
*humidity = data[0];
*temperature = data[2];
/* Ok */
return DHT_SUCCESS;
}
/**
* Lit la température et le taux d'humidité mesuré par un capteur DHT22.
*
* @param pin Broche sur laquelle est câblée le capteur.
* @param temperature Pointeur vers la variable stockant la température.
* @param humidity Pointeur vers la variable stockant le taux d'humidité.
* @return DHT_SUCCESS si aucune erreur, DHT_TIMEOUT_ERROR en cas de timeout, ou DHT_CHECKSUM_ERROR en cas d'erreur de checksum.
*/
byte readDHT22(byte pin, float* temperature, float* humidity) {
/* Lit le capteur */
byte data[5];
byte ret = readDHTxx(pin, data, 1, 1000);
/* Détecte et retourne les erreurs de communication */
if (ret != DHT_SUCCESS)
return ret;
/* Calcul la vraie valeur de la température et de l'humidité */
float fh = data[0];
fh *= 256;
fh += data[1];
fh *= 0.1;
*humidity = fh;
float ft = data[2] & 0x7f;
ft *= 256;
ft += data[3];
ft *= 0.1;
if (data[2] & 0x80) {
ft *= -1;
}
*temperature = ft;
/* Ok */
return DHT_SUCCESS;
}
/**
* Fonction bas niveau permettant de lire la température et le taux d'humidité (en valeurs brutes) mesuré par un capteur DHTxx.
*/
byte readDHTxx(byte pin, byte* data, unsigned long start_time, unsigned long timeout) {
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// start_time est en millisecondes
// timeout est en microsecondes
/* Conversion du numéro de broche Arduino en ports / masque binaire "bas niveau" */
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *ddr = portModeRegister(port); // Registre MODE (INPUT / OUTPUT)
volatile uint8_t *out = portOutputRegister(port); // Registre OUT (écriture)
volatile uint8_t *in = portInputRegister(port); // Registre IN (lecture)
/* Conversion du temps de timeout en nombre de cycles processeur */
unsigned long max_cycles = microsecondsToClockCycles(timeout);
/* Evite les problèmes de pull-up */
*out |= bit; // PULLUP
*ddr &= ~bit; // INPUT
delay(100); // Laisse le temps à la résistance de pullup de mettre la ligne de données à HIGH
/* Réveil du capteur */
*ddr |= bit; // OUTPUT
*out &= ~bit; // LOW
delay(start_time); // Temps d'attente à LOW causant le réveil du capteur
// N.B. Il est impossible d'utilise delayMicroseconds() ici car un délai
// de plus de 16 millisecondes ne donne pas un timing assez précis.
/* Portion de code critique - pas d'interruptions possibles */
noInterrupts();
/* Passage en écoute */
*out |= bit; // PULLUP
delayMicroseconds(40);
*ddr &= ~bit; // INPUT
/* Attente de la réponse du capteur */
timeout = 0;
while(!(*in & bit)) { /* Attente d'un état LOW */
if (++timeout == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
timeout = 0;
while(*in & bit) { /* Attente d'un état HIGH */
if (++timeout == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Lecture des données du capteur (40 bits) */
for (byte i = 0; i < 40; ++i) {
/* Attente d'un état LOW */
unsigned long cycles_low = 0;
while(!(*in & bit)) {
if (++cycles_low == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Attente d'un état HIGH */
unsigned long cycles_high = 0;
while(*in & bit) {
if (++cycles_high == max_cycles) {
interrupts();
return DHT_TIMEOUT_ERROR;
}
}
/* Si le temps haut est supérieur au temps bas c'est un "1", sinon c'est un "0" */
data[i / 8] <<= 1;
if (cycles_high > cycles_low) {
data[i / 8] |= 1;
}
}
/* Fin de la portion de code critique */
interrupts();
/*
* Format des données :
* [1, 0] = humidité en %
* [3, 2] = température en degrés Celsius
* [4] = checksum (humidité + température)
*/
/* Vérifie la checksum */
byte checksum = (data[0] + data[1] + data[2] + data[3]) & 0xff;
if (data[4] != checksum)
return DHT_CHECKSUM_ERROR; /* Erreur de checksum */
else
return DHT_SUCCESS; /* Pas d'erreur */
}
|
L'extrait de code ci-dessus est disponible en téléchargement sur cette page (le lien de téléchargement en .zip contient le projet Arduino prêt à l'emploi).
Bonus : calcule du point de rosée ("dew point")
Le code présenté ci-dessous est en grande partie copier-coller de la bibliothèque DHT11Lib. Seules quelques petites modifications ont été apportées pour rendre le code plus lisible.
Le code ci-dessous permet de calculer une approximation rapide du point de rosée en fonction de la température et de l'humidité ambiante. Le point de rosée est la température à laquelle les gouttelettes d'eau (la rosée) se forment sur les surfaces (comme sur les herbes en extérieur).
1 2 3 4 5 6 7 8 9 10 11 12 | /** Fonction de calcul rapide du point de rosée en fonction de la température et de l'humidité ambiante */
double dewPoint(double celsius, double humidity) {
// Constantes d'approximation
// Voir http://en.wikipedia.org/wiki/Dew_point pour plus de constantes
const double a = 17.27;
const double b = 237.7;
// Calcul (approximation)
double temp = (a * celsius) / (b + celsius) + log(humidity * 0.01);
return (b * temp) / (a - temp);
}
|
N.B. La page Wikipedia sur le calcul du point de rosée dispose d'un certain nombre de constantes pour l'approximation de résultat en fonction de la plage de température et de la pression atmosphérique. N'hésitez pas à aller y faire un tour pour voir.
Bonus : conversion degrés Celsius vers Fahrenheit ou Kelvin
Pour les amateurs d'unités de mesure anglaises, voici la classique formule de conversion de degrés Celsius vers degrés Fahrenheit :
1 2 3 | double celsiusToFahrenheit(double celsius) {
return 1.8 * celsius + 32;
}
|
Et pour les amateurs de science, voici la formule de conversion de degrés Celsius vers degrés Kelvin :
1 2 3 | double celsiusToKelvin(double celsius) {
return celsius + 273.15;
}
|
Conclusion
Ce tutoriel est désormais terminé.
Si ce tutoriel vous a plu, n'hésitez pas à le commenter sur le forum, à le diffuser sur les réseaux sociaux et à soutenir le site si cela vous fait plaisir.