Das DHT20-Modul

Hier werden einzelne Projekte mit MicroPython vorgestellt
Antworten
Heinrichs
Beiträge: 198
Registriert: Do 21. Okt 2010, 18:31

Das DHT20-Modul

Beitrag von Heinrichs » Sa 19. Jul 2025, 16:31

Das DHT20-Modul (s. Abb. 1) dient zur Messung von Temperatur und Luftfeuchtigkeit. Von dem bereits in meinem Beitrag Mit dem DHT11-Modul Temperatur und Feuchtigkeit messen vorgestellten Modul DHT11 unterscheidet es sich in zwei wesentlichen Punkten:
  • Genauigkeit
  • Übertragungs-Protokkoll
DHT20.jpg
Abb.1: DHT20-Modul
DHT20.jpg (15.29 KiB) 709 mal betrachtet

Die Genauigkeit der Messwerte sind in der folgenden Tabelle zusammengefasst:

AuflösungGenauigkeitReproduzierbar
Temperatur0,01 °C0,5 °C0,1 °C
Luftfeuchtigkeit0,024 %0,024 %0,024 %

Die Tabelle zeigt: Es ist sinnvoll, die Messwerte mit einer einzigen Nachkommastelle anzugeben.

Die Versorgungsspannung liegt zwischen 2,2 V und 5,5 V; wir können das Modul also über den 3,3V-Pin betreiben.

Die Stromstärken sind recht gering: Im Ruhezustand ist sie unter 1 uA, bei einem Messvorgang unter 1 mA. Da der Messvorgang weniger als 1 ms dauert (s. u.), ist der "Stromverbrauch" sehr niedrig.

Die Kommunikation zwischen dem DHT20-Modul und dem Mikrocontroller erfolgt über eine I2C-Schnittstelle. Externe Pull-Up-Widerstände sind nicht nötig. Die maximale Taktfrequenz beim DHT20-Baustein ist 400 000 Hz. Das ist identisch mit der Standardfrequenz, mit der die Micropython-Software bei Benutzung des Hardware-I2C arbeitet (vgl. Abb. 2); deswegen kann bei der Instanziierung des i2c-Objekts auf die Angabe der Frequenz verzichtet werden.

DHT20_SCL_micropython_klein.jpg
Abb. 2: SCL-Diagramm
DHT20_SCL_micropython_klein.jpg (17.91 KiB) 708 mal betrachtet

Die Instanziierung habe ich folgendermaßen vorgenommen (SCL -> Pin 25, SDA -> Pin 26):

Code: Alles auswählen

from machine import Pin, I2C
i2c = I2C(1, scl=Pin(25), sda=Pin(26))
Mit der folgenden Funktion get_t_h werden vom DHT20-Modul Messwerte für die Temperatur (t) und die Luftfeuchtigkeit h ausgelesen und zurückgegeben. Die Funktion kontrolliert zunächst, ob das DHT-Modul bereit ist; sollte das nicht der Fall sein, wird eine Initialisierung durchgeführt; die Bereitschaft wird erneut kontrolliert. Ist der Baustein immer noch nichtt bereit, wird das Programm abgebrochen.

Anschließend wird mit der Funktion trigger_measurement eine Messung ausgelöst; nach einer Wartezeit von 80 ms werden die Werte für die Temperatur t und die Luftfeuchtigkeit h vom DHT20 mit der Funktion read_measurements ausgelesen. Auch hier wird ggf. ein zweiter Leseversuch vorgenommen. Der Rückgabewert wird in der Vatiablen buffer gespeichert; er besteht aus einem Bytestring von 7 Bytes.

Die Bedeutung der einzelnen Bytes von buffer ergibt sich aus der folgenden Tabelle von S. 11 des Datasheets (Abb. 3):

Rueckgabewert_read_measurements.jpg
Abb. 3: Bedeutung der buffer-Bytes
Rueckgabewert_read_measurements.jpg (122.83 KiB) 707 mal betrachtet

Byte 0: Status-Information; ist Bit 7 = 1, dann liegt kein lesbarer Messwert vor; das Programm wird abgebrochen.
Bytes 1, 2 und das höherwertige Halbbyte von Byte 3 geben die Luftfeuchtigkeit an.
Das niederwertige Halbbyte von Byte 3 und die Bytes 4 und 5 geben die Temperatur an.
Das letzte Byte 6 dient zur Durchführung eines CRC-Checks; auf diesen verzichten wir hier.

Durch geschickte Links- bzw. Rechts-Shifts und Oder-Verknüpfungen erhalten wir die Rohwerte raw_h und raw_t; diese können mit der auf derselben Seite angegebenen Formeln

t = raw_t / 2**20 * 200 - 50
h = raw_h / 2**20 * 100

in die Werte mit den üblichen Einheiten % bzw. °C umgerechnet werden.

Hier nun der Quellcode für die Funktion get_t_h:

Code: Alles auswählen

def get_t_h():
    # print('warten...')
    sleep_ms(100)
    if not is_ready(): 
        # print('Falscher Status! Initialisieren...')
        initialize()
        sleep_ms(100)
        if not is_ready():
            print('Falscher Status! Abbruch...')
            exit()
        else:
            print('Initialisieren erfolgreich!')    

    # print('messen...')
    sleep_ms(20) # ???????????????????????????????????????????????????????????????????????????????????????????
    trigger_measurements()     # AC-Command, vgl. Abschnitt 7.4.2 vom Datasheet
    sleep_ms(80)
    buffer = read_measurements()
    if buffer[0] >= 128: # Status-Bit 7 ist gleich 1 => Lesen der Messwerte noch nicht abgeschlossen
        print('Lesen der Messwerte noch nicht abgeschlossen => warten...')
        sleep_ms(80)
        buffer = read_measurements() # neuer Versuch...
        if buffer[0] >= 128:
            print('Keine Messwerte lesbar => Abbruch')
            exit()    
    raw_t = (buffer[3] & 0x0F) << 16 | buffer[4] << 8 | buffer[5]
    # das obere Halbbyte von buffer[3] löschen;
    # die Bytes dann um 16, bzw. 8,  bzw. 0 Bits nach links verschieben; 
    # die Ergebnisse mit ODER zusammenfügen;
    # vgl. Abschnitt 7.4.5 vom Datasheet
    raw_h = buffer[1] << 12 | buffer[2] << 4 | buffer[3] >> 4
    # die ersten beiden Bytes um 12 bzw. 4 Bits nach links verschieben,
    # das dritte um 4 Bits nach rechts;
    # die Ergebnisse mit ODER zusammenfügen;
    # vgl. Abschnitt 7.4.5 vom Datasheet 
    t = raw_t / 2**20 * 200 - 50 # vgl. Formeln in Abschnitt 8 vom Datasheet
    h = raw_h / 2**20 * 100
    return t, h
Die Funktion is_ready hat den Quellcode:

Code: Alles auswählen

def is_ready() -> bool: # vgl. Abschnitt 7.4.1 vom Datasheet
    i2c.writeto(address, b'\x71')
    return i2c.readfrom(address, 1)[0] & 0x18 == 0x18
Dabei gibt die Variable address die I2C-Adresse (0x38) OHNE read/write-Bit an.

Die Funktion initialize hat den Quellcode:

Code: Alles auswählen

def initialize():
    buffer = b'\x00\x00'
    i2c.writeto_mem(address, 0x1B, buffer)
    i2c.writeto_mem(address, 0x1C, buffer)
    i2c.writeto_mem(address, 0x1E, buffer)
Die Funktion trigger_measurements hat den Quellcode (vgl. S. 10 des Datasheet):

Code: Alles auswählen

def trigger_measurements():
    i2c.writeto_mem(address, 0xAC, b'\x33\x00')
Die Funktion read_measurements hat den Quellcode:

Code: Alles auswählen

def read_measurements():
    buffer = i2c.readfrom(address, 7)
    return buffer
Für den Fall, dass die Ausgabe nur auf dem Terminal erfolgen soll, ist das Hauptprogramm jetzt ganz einfach:

Code: Alles auswählen

while True:
    t, h = get_t_h()
    print('t =', t, '°C   h =', h, '%')
Das gesamte Programm finden Sie auch im Anhang; bei diesem werden die Messwerte auch auf 1 Nachkommastelle gerundet und auf dem Display des TTGO angezeigt.


.
Dateianhänge
DHT20_Anhang_0.zip
(635.2 KiB) 74-mal heruntergeladen

Antworten