Forum: Projekte & Code DHT11 Luftfeuchtigkeitssensor Testcode für WinAVR


von Walter V. (low-budget)


Angehängte Dateien:

Lesenswert?

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

von Johannes R. (jr17oo)


Lesenswert?

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.

von Walter V. (low-budget)


Lesenswert?

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ß

von Yatko J. (denim)


Lesenswert?

Hi,

danke, aber sollte es nicht in der cksum berechnung etwa so aussehen ?:
1
  if ( ((dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3]) & 0xff ) != dht11_data[4])   // Checksum

von Yatko J. (denim)


Lesenswert?

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)
1
timeout = 255;  
2
while(DHT11_is_low) {if (!timeout--) {return 8;}}        
3
timeout = 255;  
4
while(DHT11_is_hi) {if (!timeout--) {return 9;}}

kommen falsche werte bei mir:
1
Error7,94  0  B 80 1F
2
Error7,94  0  B 80 1F
3
Error7,94  0  B 80 1F
4
Error7,94  0  B 80 1F

mit klappt es dann wieder:
1
40% 23C
2
40% 23C
3
40% 23C
4
40% 23C

von Walter V. (low-budget)


Lesenswert?

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 ?:
1
if ( ((dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3]) & 0xff ) != dht11_data[4])   // Checksum
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ß

von Yatko J. (denim)


Lesenswert?

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 ?:
>
1
if ( ((dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3]) &
2
> 0xff ) != dht11_data[4])   // Checksum
> 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.

von Walter V. (low-budget)


Lesenswert?

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:
1
if ((uint8_t)(dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3]) != dht11_data[4])
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ß

von woodbird (Gast)


Lesenswert?

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.

von Zenon R. (mombula1)


Lesenswert?

kannst Du Deinen verbesserten Code veröffentlichen?

von woodbird (Gast)


Lesenswert?

Da gibt es nicht mehr als die eine Zeile Code einzufügen. Ansonsten ist 
es der Sourcecode azus diesem Thread.

von Seppi (Gast)


Lesenswert?

DHT11 sind der grösste Drack.

Sowas von ungenau !!!

von DIY D. (diymechatron)


Angehängte Dateien:

Lesenswert?

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.
1
*feuchte = (dht11_data[0] << 8) + dht11_data[1];
2
*temperatur = (dht11_data[2] << 8) + dht11_data[3];
3
*checksum = dht11_data[4];
sowie die Paramter als long übergeben.
1
uint8_t dht11(unsigned long *feuchte, unsigned long *temperatur,unsigned 
2
char *checksum)
Die Prüfsummenberechnung funktioniert in bestimmten Situationeen (bei 
bestimmten Werten) auch nicht.

Wenn die Werte in den einzelnen char daten
1
(dht_data[0]+dht_data[1]+dht_data[2]+dht_data[3])
zusammen größer als 255 sind, dann läuft die Prüfsumme über.
Das bedeutet wenn der Prüfsummenabgleich nicht klappt, muss man nochmals 
prüfen, ob
1
(dht_data[0]+dht_data[1]+dht_data[2]+dht_data[3] != dht_data[4] +256)
stimmt.

Zusätzlich habe ich in meiner meiner Ausgabe die Umrechnung sowie die 
Fließkommaberchnung reingepackt.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.