Problème lecture DHT22

Bien le bonsoir mes amis (si vous me laisser vous appeler mes amis :p)...

Je demande l'aide de ce forum pour me sortir d'un casse tête qui m'a broyé l'esprit durant toute l'après midi...

C'est tout simple : j'essaye de lire la température et l'humidité à partir d'un DHT22 mais... Bah ça marche pas :confused:

Pour vous avancer un peu j'ai tester 2 librairies, en alternant des pull-up de 4.7k Ohm ou 10k ohm, et en testant avec le 5v et le 3.3v...
J'ai bien sûr vérifié mes branchements quelques fois...

Pour ce qui est de l'erreur, le détail le plus précis que j'ai pu avoir, c'était "ACK_time_out" ...

À votre avis, d'où cela peut il venir ?
Je vous remercie d'avance pour vos contributions :slight_smile:

Dans le DHT22 les résistances de pull up de tirage à l'alim sont déjà incorporée contrairement au DHT11.

ACK_time_out

signifie que le DHT22 ne répond pas à la demande d'émettre que la librairie n'arrive pas à détecter la réponse du DHT22.

Récupère une librairie sur le playground de Rob Tillaaert, c'est ce qui fonctionne le moins mal.
http://playground.arduino.cc/Main/DHTLib

Je pense que à l'origine l'erreur provient d'une mauvaise lecture d'une mauvaise datasheet, maintenant on trouve une datasheet un peu moins mauvaise mais l'entêtement aidant la librairie n'a pas été rectifiée.

Dans LES librairies on attend l'acknoledge pendant un temps fixe alors que ce temps est variable.
Tu es peut-être tombé sur un exemplaire atypique mais dans la spec.

Fig 6 page 6
Le maitre met la connection à 0 pendant un temps qui doit être compris entre 0,8 et 20 ms, puis relache la ligne en repassant à 1.
Le DHT22 envoi un acknoledge après le relâchement de la ligne au bout d'un temps qui est compris entre 20µs et 200µs avec une moyenne à 30 µs c'est là qu'il y a un temps fixe souvent de 30 µs et c'est probablement là qu'il y a l'erreur . Si ton exemplaire répond en 100 µs il sera dans la spec mais la lib ne fonctionnera pas. Si par malheur il répond en 20 ms cela pourra ne pas fonctionner, cette fois à cause de la lenteur des fonctions digitalRead().

Il faudrait que tu modifie la librairie en remplaçant ce temps fixe par une boucle identique à celle qui sert à détecter la fin de l'élément binaire "1".

Ensuite il y a la phase d'acknoledge : un "0" suivi d'un "1" de longueur égale (80µs +/- 5µs).
Puis l'envoi des bits sachant que :
un bit 0 est constitué d'un élement binaire "0" suivi d'un élément binaire "1" de longueur plus courte que celle de l'élément binaire "0".
un bit 1 : c'est pareil sauf que la longueur de l'élément binaire 1 est cette plus longue que celle de l'eb 0

La gestion du DHT22 consiste à comparer les temps entre des "0" et des "1".

En pj une datasheet du DHT22 aussi appelé AM2302

AM2302.pdf (570 KB)

Bonjour, tout d'abord merci pour votre réponse très complète et désolé pour la mienne un peu tardive ...

Alors j'ai téléchargé la librairie indiquée et sans la modifier j'obtiens "DHT22, Connect error, 0.0, 0.0, 5128"
J'ai très bien compris vos explications très claires sur le fonctionnement de la sonde, cependant je ne sais pas trop quoi modifier dans la librairie pour l'adapter ...
J'ai essayer de "d'inverser" certains systèmes de boucles comme ici :

// while(digitalRead(pin) == LOW)
    while ((*PIR & bit) == LOW )  // T-rel
    {
        if (--loopCount == 0) return DHTLIB_ERROR_ACK_L;
    }

ou là :

while ((*PIR & bit) != LOW )  // T-reh
    {
        if (--loopCount == 0) return DHTLIB_ERROR_ACK_H;
    }

(en inversant ligne commentée et ligne décommentée)
Mais cela n'a absolument rien donnée ...
Pourriez-vous m'éclairer ?

Préambule :
Je pense que tu es d'accord avec les niveaux :

  • signal non actif --> la ligne est à 5V
  • signal actif --> la ligne est à 0V

Après la prise de ligne et le relâchement de la ligne il y a un temps mort où la ligne est à 5V.
Le début de l'acquiessement est un créneau à 0V.
Il faut donc détecter quand la ligne bascule de 5V à 0V

Je n'ai pas la librairie sous les yeux mais de mémoire il doit y avoir une ligne :
delaymicroseconde(30);
qu'il faudrait remplacer par une boucle while comme celle qui sert à détecter la longueur des éléments binaires.

while (digitalRead(pin)==1)
{
  // code  
  si temps_max dépassé DHT_erreur_acquiessement
}

PS : je parle d'élément binaire 1 ou d'élément binaire 0 pour éviter la confusion. Si je disais qu'un bit 1 est défini par un bit 0 suivi d'un bit 1 cela ne serait pas clair du tout.
De plus je suis dans la norme car dans les définitions officielles 1 bit est une quantité d'information et non plus un signal 0 ou +V volts. Quand l'I2C envoi un ordre elle envoi 2 octets (l'adresse + l'ordre) soit 16 éléments binaires. En fait sur les 16 seul 8 contiennent une information utile soit 8 bits.

PS1 : tu dispose d'une librairie plus évoluée que celle que j'avais utilisé : l'auteur a (enfin) supprimé l'appel a la fonction digitalRead(pin) qui est énormément lente.

Personnellement j'avais fait appel à la lecture directe des registres des ports qui est la solution la plus rapide mais la moins portable. Tout est écrit en dur et si on change de pin il faut changer dans la librairie.
En faisant des fouilles archéologiques je dois pouvoir retrouver une version intermédiaire, archivée sur le forum, où malheureusement je n'avais pas encore retiré le délais, quant à la version définitive elle n'a pas résisté à un changement de disque dur.

Fin des recherches archéologiques dans mon disque dur : j'ai retrouvé un dossier du joli nom de "foutoir" et miracle j'y ai trouvé ce que je cherchais, il a survécu au changement de disque dur.
J'en ai profité pour améliorer les commentaires.

Point de départ : l'AM2302 est un capteur "rapide" et pour le gérer correctement il y a des phases où il faut faire vite.
Dans ma solution il n'y a aucune astuce comme dans la lib du playground, c'est du bourin mais du bourin réfléchi.
Exemple : pour savoir si l'élément binaire 1 est celui d'un bit 0 ou celui d'un bit 1 il n'est pas utile de perdre du temps avec la fonctions milli() pour mesurer exactement sa longueur. Il suffit d'utiliser une image de sa longueur et de comparer si elle plus grande ou plus petite que celle du 0. L'image que j'ai choisi est la lecture du compteur d'un timer. En fait c'est le principe de milli() mais sans tous les traitements inutiles pour détecter un temps aussi court.

Pour lire le signal du capteur j'ai éliminé la fonction digitalRead et j'ai utilisé la lecture des registre. En faisant cela j'ai perdu la portabilité mais j'ai multiplié la vitesse de lecture par 10.
J'avais essayer la fonction digitalFast mais on ne gagnait au mieux qu'un rapport 2.
J'ai compris la raison dernièrement : Wiring/Arduino utilise des macros pour faire la conversion entre la gestion Atmel par Port et indice dans le Port et la gestion Arduino de 1 à N qui est portable.
Il se trouve que Wiring a été développé sur un petit micro où la RAM était rare donc H Barragan a fait le choix d'utiliser PROGMEM qui permet de stocker les constantes en flash mais PROGMEM est lent.
DigitalReadFast est digitalRead débarrassé de tous les contôles inutiles et même comme cela du fait de la lenteur de PROGMEM il ne peut rivaliser en vitesse avec la lecture des registres des ports.
Dans sa dernière version Wiring n'utilise plus PROGMEM : c'est en comparant Wiring et Arduino que j'ai trouvé l'explication.

Avec les librairies basées sur Arduino il subsiste des erreurs checksum plus ou moins rares mais il en subsiste, ce n'est pas forcément génant on peut le gérer mais elles sont là.
J'ai fait tourner le montage avec ma version pendant plusieurs jours (presque une semaine) je n'ai eu aucune erreur.

Aux utilisateurs de choisir.

archive_AM2302.zip (4.33 KB)