Hi,
Kürzlich ist bei mir ein DHT11 Temperatur und Luftfeuchtigkeitssensor
aus China eingetrudelt (1,15€). Wollte ihn dann schnell ausprobieren um
die Bewertung bei E. abzugeben. Da ich auf anhieb keinen WinAVR-Code
gefunden habe gibt’s jetzt meinen.
Der DHT11 ist wohl das untere Ende von dem was der Markt an solchen
Sensoren bereithält (+/- 5% RH, +/- 2°C). Die Ergebnisse die ich
erziele, erscheinen mir dennoch halbwegs plausibel.
In der Zip-Datei ist ein komplettes Testprogramm mit UART-Ausgabe für
einen ATtiny2313. Die eigentliche DHT11-Routine (dht11() in dht11.c)
sollte auf so ziemlich jedem 8Bit AVR laufen. (kein Interrupt, kein
Timer ...)
Ist sicher noch nicht perfekt aber Funktioniert!
Freue mich über Anregungen, Kritik und Geschenke ;-)
Gruß Walter
Danke für das Veröffentlichen deines Codes. Hier im Forum sind aber
schon ähnliche Codeschnipsel gepostet wurden, z. B.
Beitrag "Re: DHT22 liefert eigenartige Werte"
Da ich mich selbst kürzlich mit der Ansteuerung eines AM2302 (anderer
Name: DHT22) per AVR beschäftigt habe, kenne ich das Protokoll. In den
zahlreichen im Internet kursierenden Beispielcodes werden immer wieder
Konstrukte wie
1
while(DHT11_BUS_HIGH);
und
1
while(DHT11_BUS_LOW);
zur Synchronisierung der Signalflanken verwendet. Da man natürlich nie
weiß, was auf dem Bus so alles passiert, kann diese Art der
Programmierung den Controller ganz schnell in eine Endlosschleife
katapultieren. Ich selbst habe feste Wartezeiten für die Abfrage des
Bus-Pegels verwendet. Je nach Bauteiltoleranz und Abweichungen zwischen
den verschiedenen Modellen wird das aber unter Umständen nicht mit allen
Sensoren funktionieren.
Deine Lösungs-Variante mit dem Timeout-Zähler gefällt mir ganz gut,
damit dürfte man in jedem Fall auf der sicheren Seite sein.
Der AM2302 arbeitet übrigens erstaunlich präzise. Die Temperaturmessung
stimmt +/- 0,2 °C mit einem DS18S20 überein, für die Luftfeuchte habe
ich leider keinen Vergleichswert. Kostet zwar das Dreifache eines DHT11,
für die angegebene Genauigkeit von +/- 0,5 °C und +/- 2% RH ist das aber
immer noch günstig.
Hi Johannes,
Erst mal vielen dank für deinen ausführlichen Beitrag, und dass du dich
um Leute kümmerst die zu blöd zum suchen sind.
Bin einfach nicht auf die Idee gekommen nach DHT22 zu suchen, obwohl ich
von dessen Existenz wusste. Übrigens finde ich unter DHT11 den von dir
verlinkten Code, in der hiesigen Forensuche, auch heute nicht (sucht
wohl nur im Betreff?). Das „bunte G“ liefert vorwiegend Arduino-Code.
Und nach einem Blick ins Datenblatt, wollte ich mir die Erfahrung und
den Spaß, es selbst zu machen dann nicht mehr nehmen lassen.
In Sachen Genauigkeit bin ich voll deiner Meinung. Wer mehr als Spielen
will sollte etwas mehr ausgeben. Veränderungen durch lüften, heizen oder
auch nur „dranhauchen“ lassen sich aber recht gut darstellen.
Zu erwähnen ist auch noch die mangelnde Langzeitstabilität des DHT11.
Mit 1% / Jahr (feuchte) da kann ich ihn ja gleich sockeln ;-)
Der AM2302 / DHT22 macht da mit < 0,5% / Jahr den Preisunterschied schon
fast wider wett.
Gruß
des weiteren musste ich noch ein weiteres bit verschieben, sonst kamen
falschen werte raus. komisch, laut oszi / logic analysizer sollte sein
code direkt laufen.
ich habe das ganze mal aufm 8mhz atmega8 gestartet. ohne zusätzlichen
(nach return 4)
Hi Yatko
Falls du noch am Projekt bist (is ja schon ein paar Tage her) Folgendes:
Yatko Jaens schrieb:> aber sollte es nicht in der cksum berechnung etwa so aussehen ?:
Du könntest die Prüfsumme in 16 Bit berechnen und dann mit 0x00FF
maskieren.
Ein gültiger Wert kann aber beim DHT11 nicht größer als 8 Bit werden:
MaxRH 90
MaxTemp 50
+
MaxSumm 140
Außerdem werden die überschüssigen Bits sowieso links raus geschuppst;-)
Zum verlorene Bit.
Ja. Deine Ausgaben sind alle um 1 Bit nach rechts verschoben. Vermutlich
wird ein Bit bei der Initialisierung nicht erkannt und deshalb
übersprungen. Das hast du ja auch erkannt und die Sache „geflickt“. Es
muss aber irgend einen Grund dafür geben, und den würde ich gerne
herausfinden. Folgende Fragen und Ideen:
1. Wie lang sind deine Leitungen (also die zum DHT11 ;-) )? (verkürzen?)
2. Externer Pullup? (bei langer Leitung WO?)
3. Hast du schon probiert das NOP (vor return 2) zu reaktivieren? (oder
ein paar µs delay)
4. In der "dht11.c" gibt es die (auskommentierte) Funktion
„dht11_logik_analyse (void)“.
Lass dir mal deren Ausgabe in einem Terminalprogramm (z.B, HTerm.exe) im
Binärformat anzeigen. Das zeigt dir die Antwort des DHT11 (bei 8MHz etwa
im 1µS Takt) an. Das Ergebnis kannst du gern mal posten, dann schau ich
mal drauf.
5. Wen du sonst noch etwas am Code geändert hast, dann häng deine
Dateien möglicht auch dran.
Gruß
Hallo Walter,
ich habe nun einen DHT22 besorgt, gibt es zur Zeit für schlappe 5,99€ in
der Bucht. Hier sehen die Werte realistischer aus und auch ist der
Sensor flink und nicht so träge wie der DHT11.
Ich möchte gerne im Low Cost Bereich bleiben. Ich weiss, dass es
durchaus bessere > 15€ Sensoren gibt. Aber für das bisschen
Experimentieren
lohnt es sich für mich nicht .
So, da ich den DHT11 erstmal zur Seite geschmissen habe, kann ich jetzt
nicht eben schnell was anderes aufbauen
Mein kleines Projekt sieht wie folgt aus: der Sensor und ein 433MHz
Sender hängen an einem Pollin NETIO Board. 433MHz Sender um
Funk-Steckdosen zu schalten. DHT22 um RH und Temp zu loggen. Das Ganze
wird von einer Sheeva Plug (1,2GHz Mini Linux Server) gesammelt und mit
Gnuplot alle 5 Min. auf einem USB Monitor (Samsung U70) aktualisiert.
Ich weiss, dass Ganze hat nichts mit der Sache zu tun. Aber vielleicht
inspiriert es den einen oder anderen.
Walter V. schrieb:> Hi Yatko>> Falls du noch am Projekt bist (is ja schon ein paar Tage her) Folgendes:>> Yatko Jaens schrieb:>> aber sollte es nicht in der cksum berechnung etwa so aussehen ?:>
> Du könntest die Prüfsumme in 16 Bit berechnen und dann mit 0x00FF> maskieren.
Ich glaube CRC war schon 16bit , daher musste ich extra mit 0xff
maskieren. Da wie du sehen kann, mit den falschen Werten Werte im
Bereich > 0xff rauskam, ist es mir aufgefallen. Das dürfte oben in
Deinem Code immer noch so sein.
> Ein gültiger Wert kann aber beim DHT11 nicht größer als 8 Bit werden:> MaxRH 90> MaxTemp 50> +> MaxSumm 140
Ja, das hast du recht. Dann bräuchte man das Maskieren nicht. :)
> 1. Wie lang sind deine Leitungen (also die zum DHT11 ;-) )? (verkürzen?)>> 2. Externer Pullup? (bei langer Leitung WO?)
Leitungen sind kurz und es ist ein 10k Pull Up aufgelötet. Auch 5,6k
brachten keine Besserung. Da Fall ist aufjedenfall interessant. Da Dein
Code und laut Oszillogramm es einfach funktionieren sollte. Ein logische
Erklärung muss es geben :-)
> 3. Hast du schon probiert das NOP (vor return 2) zu reaktivieren? (oder> ein paar µs delay)>> 4. In der "dht11.c" gibt es die (auskommentierte) Funktion> „dht11_logik_analyse (void)“.> Lass dir mal deren Ausgabe in einem Terminalprogramm (z.B, HTerm.exe) im> Binärformat anzeigen. Das zeigt dir die Antwort des DHT11 (bei 8MHz etwa> im 1µS Takt) an. Das Ergebnis kannst du gern mal posten, dann schau ich> mal drauf.>> 5. Wen du sonst noch etwas am Code geändert hast, dann häng deine> Dateien möglicht auch dran.
3-5 Werde ich machen sobald ich den DHT11 wieder angeschlossen habe.
>> Gruß
Danke Walter, LG zurück.
Bin noch blutiger Anfänger, sorry.
Viele Tage später...
Hi Yatko
Interessantes Projekt. Bei mir liegt auch einen „Streifenraster – Pollin
– Nachbau“ mit RFM02 / RFM12 Funkmodul für die Funksteckdosen. klappt
prima!
Hab mir noch mal die Prüfsumme angeschaut. Und du hast recht! Die
Addition wird in 16Bit ausgeführt. Man kann sie aber auf 8Bit Casten und
den Überlauf nutzen. Ich würde das also so machen:
Spart dann ein wenig Code und sollte auch mit dem DHT22 funktionieren,
wenn man die Nachkommerstellen mit übergibt. (außer bei dir :-( ???
kannst ja mal probieren)
> Leitungen sind kurz und es ist ein 10k Pull Up aufgelötet.
10k ging bei mir auch problemlos.
Alles andere scheint ja auch OK zu sein. Ist es aber nicht. Komisch!
Gruß
Den Fehler mit dem verschobenen Bit habe ich gefunden: Nach dem
Umschalten auf Eingang kann auf der Datenleitung ein Störimpuls von ca.
10yS Länge sein. Ursache unbekannt. Lösung: Nach "DHT11_in;" ein
"_delay_us(15);" einfügen. Seither kann ich sogar mit 10m langen
Leitungen einwandfrei auslesen.
Der Beitrag ist zwar schon ein bisschen älter, aber der Quellcode hat
mir schon sehr weiter geholfen.
Nur bei der Übergabe der ausgelesenen Werte an die Parameter der
funktion uint8_t dht11(unsigned char *feuchte, unsigned char
*temperatur); sind mir ein paar Fehler aufgefallen.
Wenn man zwei char zusammen packt
1
*feuchte=dht_data[0];*temperatur=dht_data[2];
landet man bei einem 'long'.
Habe den code wie folgt angepasst.