Diese Seite ist Teil des Projekts Automatische Gewächshauslüftung.

Der DHT11 ist ein preiswerter Feuchte-Temperatur-Sensor.

DHT11 Temperatur- und Luftfeuchtigkeitssensor DHT11 Temperatur- und Luftfeuchtigkeitssensor

Betriebsspannung 3,5 - 5,5 V
Relative Luftfeuchtigkeit 20 - 95 % (± 5 %)
Temperatur 0 - 50 °C (± 2 °C)

Datenblatt

Er ist der kleine Bruder des DHT22 mit kleinerem Messbereich und ist ein wenig ungenauer. Das Auslesen der Werte ist identisch. Für beide Versionen findet man eine Reihe von Beispielen im Netz.

Messwerte auslesen

Das Auslesen der Messwerte erfolgt in drei Phasen:

  1. Startsignal durch die MCU.
  2. Bereitschaftsmeldung durch den DHT11
  3. Übertragung der Messwerte

DHT11 Timing

Startsignal

Im Ruhezustand liegt die Datenleitung des DHT11 auf VCC-Potenzial (HIGH). Die MCU sendet ein Startsignal, das Datenübertragung einleitet. Dazu zieht sie die Datenleitung für etwa 20 ms auf GND-Potenzial (LOW). Die genaue Dauer ist unkritisch, darf aber nicht zu kurz sein. Danach wird die Datenleitung wieder für 20-40 µs auf HIGH gelegt.

Bereitschaftsmeldung

Nach Aussendung des Startsignals gibt die MCU die Datenleitung frei (Input-Modus). Der DHT11 zieht die Leitung für etwa 80 µs auf LOW und danach für etwa die gleiche Zeit wieder auf HIGH.

Diese Zeiten ließen sich im Test nicht genau reproduzieren. Die Gesamtzeit war i.d.R. deutlich kürzer als 160 µs. Eine Programmsteuerung durch Zeitmessung des Bereitschaftssignals führt zu keinen befriedigenden Ergebnissen. Hier muss eine Flankensteuerung programmiert werden. Die ersten beiden fallenden Flanken gehören zum Bereitschaftssignal.

Messwertübertragung

Die Messwerte werden in Form von 40 seriellen Bits übertragen. Jedes Bit beginnt mit einer 50 µs dauernden LOW-Phase. Die Dauer der folgenden HIGH-Phase bestimmt, ob eine 0 oder eine 1 übertragen wird. Bei einer 0 dauert die HIGH-Phase zwischen 26 und 18 µs, eine 1 wird durch eine 70 µs dauernde HIGH-Phase übertragen. Den Abschluss bildet eine kurze LOW-Phase, danach gibt der Sensor die Datenleitung wieder frei.

Die 40 Bits ergeben 5 Bytes. Die Übertragung beginnt jeweils mit dem MSB eines jeden Bytes. Die 5 Bytes bedeuten:

  1. Feuchte
  2. 0 (eine Dezimalstelle beim DHT22)
  3. Temperatur
  4. 0 (eine Dezimalstelle beim DHT22)
  5. Checksumme (Addition der vorhergehenden 4 Bytes)

Die Gesamtübertragungszeit dauert vom Beginn des Startsignals bis zur abschließenden fallenden Flanke des 40. Bits ja nach Anzahl der übertragenen 1 zwischen
   20 ms + 160 µs + 40 × 80 µs ≈ 340 ms
und
   20 ms + 160 µs + 40 × 120 µs ≈ 500 ms.

Hinzu kommt die abschließende Low-Phase nach dem 40. Bit.

Testprogramme

Zunächst habe ich ein einfaches Arduino-Programm zum Test der Messwerterfassung von Adafruit ein wenig angepasst. Der Nachteil dieser Version ist, dass der Zustand der Datenleitung per Polling abgefragt wird. Da die Unterscheidung zwischen 0 und 1 auf unterschiedlich langen Signalzeiten beruhen, werden zu deren Messung die Interrupts abgeschaltet. Dies führt u.a. dazu, dass ein serieller Datenempfang nicht mehr sauber möglich ist. Es würden Zeichen verloren gehen.

Eine Abwandlung des Programms benutzt Interrupts zur Kontrolle des Einlesevorgangs und vermeidet die o.g. Nachteile.

Implemtierung

Das Testprogramm lässt sich wegen der enthaltenen Zeitschleifen nicht direkt verwenden. Die Ausprägung der Statusvariablen für das Messwertauslesen wurde um die Option 2 (Wartezeit bis zur nächsten Messung) erweitert. Die Steuerung der Messwertübertragung vom DHT11 erfolgt nun im Rahmen eines kleinen Zustandsautomaten mit Dht11State als Zustandsvariable (deshalb auch die Umbenennung).

extern volatile int8_t Dht11State;  // Status des Messvorgangs
                                    //  0: Messung aktiv;
                                    //  1: Gültige Messung;
                                    //  2: Wartezeit bis zur nächsten Messung
                                    // -1: Timeout;
                                    // -2: Zeitfehler, Bit-Zeit zu klein;
                                    // -3: Zeitfehler, Bit-Zeit zu groß;
                                    // -4: Prüfsumme stimmt nicht
#define LOOPCOUNT 2500 // 2000 ms Pause + 500 ms Einlesedauer

void loop() // run over and overstatic uint16_t cnt = 0;

  switch (Dht11State)   // Messung beobachten
  { case 0:             // lfd. Messung, nichts machen
      break;
    case 1:             // lfd. Messung abgeschlossen
      Dht11State = 2;   // Zeitschleife beginnen
      break;
    case 2:             // Zeitschleife, nichts machen
      break;
    default:            // Fehler
      Dht11BeginRead(); // neue Messung starten
      cnt = 0;          // neue Zeitschleife
  }

  // andere Dinge machen, z.B. die serielle Schnittstelle auswerten

  delay(1);             // Zeitschleife realisieren

  cnt++;
  if (cnt > LOOPCOUNT)
  { Dht11BeginRead(); // neue Messung starten
    cnt = 0;          // neue Zeitschleife
  }
}