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

Das folgende Testprogramm ist für einen ArduinoUno geschrieben. Vorlage war ein ähnliches Programm bei Adafruit.

Das zugehörige Atmel Studio-Projekt zum Download.

Anschlussplan Anschlussplan:

Die Stromversorgung erfolgt über den Arduino. Die Datenleitung des DHT11 ist mit dem Pin 2 des Arduino verbunden und mit einem Pullup-Widerstand von ca. 4,7 - 10 kΩ versehen.

 

In setup() wird die serielle Schnittstelle initialisiert und ein Start-Text ausgegeben.

loop() liest die Daten über readDHT11() ein und gibt das Ergebnis über die serielle Schnittstelle aus. Da das Ergebnis aus mehreren Teilen besteht, wurde ein komplexer Datentyp DHT11_Result zur Rückmeldung definiert.

readDHT11() übernimmt die Kommunikation mit dem DHT11. Es wird das Startsignal gesendet und danach die Dauer von 84 Signalzuständen (terminiert durch Flankenwechsel) gemessen. Je nach Nummer des Flankenwechsels und der Dauer des Signal wird auf 0 oder 1 erkannt. Zum Schluss wird die Prüfsumme überprüft und das Ergebnis zurückgeliefert.

Der große Nachteil ist, dass die Messung der Signalzeiten über das Auszählen von Schleifendurchläufen mit definierter Länge erfolgt. Damit dies funktioniert, müssen die Interrupts abgeschaltet sein, ansonsten würde aufgerufene ISR die Wartezeiten verlängern und zu einer reduzierten Anzahl an Schleifendurchläufen führen. Ca. 40 Bits mit einer Dauer von jeweils rd. 100 µs bedeuten eine Unterbrechung der Interrupts von ca. 4 ms. Eine geordneter Empfang serieller Daten ist damit nicht mehr möglich. Es würden Zeichen verloren gehen. Zum Testen und zur Fehlerbehebung ist das Programm aber sehr gut geeignet.

 

Optimierungsoption: Saubere Einbettung in Klasse

/*
 * Arduino-Programm
 * Test zum Einlesen von DHT11-Messwerten (Feuchte- und Temperatursensor)
 *
 * Die Werte werden im Abstand von etwa 2 Sekunden ausgelesen 
 * und über die serielle Schnittstelle ausgegeben.
 *
 */

#include "Arduino.h"
#include "AppVersion.h"

#define COUNT 6          // Anzahl Schleifendurchläufe, damit 1 erkannt wird.
                         // COUNT muss experimentell ermittelt werden, da die Schleifenverwaltung mitzählt.
#define MAXTIMINGS 84    // Anzahl der Flankenwechsel für den gesamten Bit-Strom.
#define DHT11_DATA_PIN 2 // Arduino-Pin: Datenleitung des DHT11.

typedef struct
{ bool valid;
  uint8_t humidity;
  uint8_t temperature;
} DHT11_Result;

DHT11_Result readDHT11(uint8_t DataPin);

// the setup routine runs once when you press reset:
void setup()
{ Serial.begin(9600);
  Serial.println(F("DHT11 Test, Version " VERSIONSTRING));
}

// the loop routine runs over and over again forever:
void loop()
{ // Daten einlesen
  DHT11_Result DHT = readDHT11(DHT11_DATA_PIN);

  // Daten ausgeben
  Serial.println("----------");
  if (DHT.valid)
  { Serial.print("Hum: ");
    Serial.print(DHT.humidity);
    Serial.print(" Temp: ");
    Serial.println(DHT.temperature);
  }
  else
    Serial.println("Invalid");
  delay(2000);
}

DHT11_Result readDHT11(uint8_t DataPin)
{ uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0;
  uint8_t data[5];
  DHT11_Result DHT;

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  // Datenleitung für ca. 20 ms auf Low
  pinMode(DataPin, OUTPUT);
  digitalWrite(DataPin, LOW);
  delay(20);

  // Die folgenden Timings sind zeitkritisch
  // Die Bearbeitung von (längeren) ISRs ist nicht möglich
  cli();

  // Datenleitung für ca. 30 µs auf High.
  digitalWrite(DataPin, HIGH);
  delayMicroseconds(30);

  // Datenleitung freigeben
  pinMode(DataPin, INPUT);

  // Bit-Strom einlesen
  for (uint8_t i=0; i< MAXTIMINGS; i++)
  { counter = 0;
    while (digitalRead(DataPin) == laststate)
    { counter++;
      delayMicroseconds(3);
      if (counter > 50)
        break;
    }
    laststate = digitalRead(DataPin);

    if (counter > 50)
    { break;
    }

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0))
    { // shove each bit into the storage bytes
      data[j/8] <<= 1;
     if (counter > COUNT)
       data[j/8] |= 1;
      j++;
    }
  }

  // Der zeitkritsche Teil ist beendet
  sei();

  // check we read 40 bits and that the checksum matches
  if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) )
  { DHT.valid=true;
    DHT.humidity=data[0];
    DHT.temperature = data[2];
  }
  else
    DHT.valid=false;
 return DHT;
}

Der Trick mit AppVersion ist übrigens hier erklärt: Build-Nummer: Immer Eins drauf!