2015
HOME
Arduino als Frequenzzähler

Temperatur und Luftfeuchte mit einfachen Routinen (ohne Bibliotheken)
DHT11 am Arduino - Daten im Gänsemarsch
Im Blog embedded-lab.com wird eine ganz bequeme Art vorgestellt den Sensor ohne Breadboard zu benutzen.
Im Netzt gibt es unzählige Sensoren für Arduino & Co. Der DHT11 ist dabei weit verbreitet und liefert einen positiven Temeraturwert in Celsius, sowie die Relative Luftfeuchte in Prozent. Die Arduino-Gemeinde ist es gewohnt verwöhnt zu werden - anders ausgedrückt - es gibt zu jedem Sensor in kürzester Zeit eine Bibliothek und schon kann der Küchentisch-Elektroniker und Patchwork-Programmierer mit drei Klicks seine Vorstellungen in kürzester Zeit realisieren. Das Beispiel "Arduino als Zollstock" ist so zu verstehen.

Ist man allerdings interessiert, wie die Dinge im Untergrund der Technik und Bibliotheken funktionieren, wird die Sache schon schwieriger.


Das DSO-Quad zeigt am Digitaleingang D den Beginn der Übertragung. Nach 18 Millisekunden LOW folgt etwa 40 us HIGH als Anforderung vom Arduino. Der Sensor antwortet mit ca. 50 us LOW und ca 80 us HIGH. Dann folgt eine Impulspause der festen Länge 50 us und das erste Bit mit kurzer Impulsbreite, also eine "0". Die ersten Bits wären hiernach 0010010 ...
Dieser Sensor DHT11 sendet seine Informationen seriell im Gänsemarsch über die Leitung. In der linken Darstellung sind die ersten Bits der seriellen Datenübertragung zu sehen.

Die Spezifikation ist im Netz weit verbreitet. Die erforderlichen Signale findet man unter anderem hier: DHT11 Humidity Temperature_Sensor_Brick Communication Process: Serial Interface Single-Wire_Two-Way. Die Besonderheit ist, dass eine Leitung für beide Richtungen verwendet wird. So sendet der Arduino ein Signal und schaltet anschließend auf Empfang. Der Ausgang wird also zum Eingang. Der Datenaustausch kann wie folgt aus dem Datenblatt entnommen und zusammengefasst werden:

  • Ausgabe des Startsignals (Arduino)
  • Abwarten der Bestätigung (Sensor)
  • Einlesen von 40 Bit (5 Byte) Messdaten und Kontrolldaten

Im Detail ist das Startsignal ein Impuls der mindesten 18 ms LOW und 20 bis 40 us HIGH ist. Danach wird auf Empfang geschaltet und auf die Antwort des Sensors gewartet. Dieser legt zur Bestätigung den Eingang nun für 80 us auf LOW und danach 80 us auf HIGH. Nun folgen die 40 Bits bzw. 5 Bytes mit folgendem Inhalt:

  • Byte 1: Relative Luftfeuchte in Prozent
  • Byte 2: Nachkommastellen der Luftfeuchte (DHT11 immer 0)
  • Byte 3: Temperatur in Celsiusgrad
  • Byte 4: Nachkommastellen der Temperatur (DHT11 immer 0)
  • Byte 5: Summe der ersten vier Bytes zur Kontrolle

Ob ein Bit "1" oder "0" ist entscheidet die Impulsbreite. Nach einer immer gleich langen Impulspause (LOW) von 50 us folgt eine Impulsbreite (HIGH) von entweder 26 bis 28 us für eine "0" oder 70 us für eine "1". Damit steht einer Dekodierung nichts mehr im Weg. Das Signal erinnert etwas an das Funkuhr-Signal vom DCF77-Sender - mit anderen Zeiten.


Vorbereitungen setup

Die Messdaten werden vom Arduino über die RS232-Leitung geschickt. Der Sensor lag in der Nähe des Heizkörpers an einem kalten Winterabend. Die Luft war trocken ...
Vier globale Variablen - wegen der Einfachheit - sind für die Messergebnisse vorgesehen. Einmal zwei Ganzzahlen (Integer), da der DHT11 hier keine Nachkommastellen liefert und zwei Zeichenketten (Strings), die diese Werte als Text enthalten. Für die Ausgabe über Serial.print macht das keinen Unterschied, für eine möglicherweise angeschlossene Anzeige aber schon. Als Anschluss für den Sensor DHT11 ist Pin 2 rein willkürlich gewählt worden. In der Setup-Routine wird die RS232-Schnittstelle konfiguriert und danach eine Sekunde gewartet. Der Quelltextauschnitt zeigt folgendes Bild:

#define DHT_PIN 2

int feuchte, temperatur;
char sfeuchte[10],stemperatur[10];

void setup()
{Serial.begin(9600);
 Serial.println("DHT11 Messung.");
 delay(1000);
}


Hauptschleife loop
In der Hauptschleife werden die Messungen einmal in der Sekunde abgerufen und zur Anzeige gebracht. Die Funktion dht11(pin) führt die Konversation mit dem Sensor und liefert Messdaten für die Ausgabe.

void loop()
{dht11(DHT_PIN);
 Serial.print("DHT11 Luftfeuchte[%]/Temperatur[C]: ");
 Serial.print(sfeuchte);
 Serial.print("/");
 Serial.println(stemperatur);
 delay(1000);
}


Datenabfrage 1 oder 0
Die eigentliche Daten-Abfrage erfolgt so wie es der Hersteller angibt.
Nacheinander werden folgende Dinge ausgeführt:
  • Byte-Puffer auf Null setzen
  • Messanforderung senden
  • Bestätigung empfangen
  • Die 40 Bits einlesen und ablegen
  • Messwert in die Variablen übertragen

Die Funktion dht11 führt genau diese Schritte aus. Nach dem Rücksetzen der Byte-Puffer folgt die Anforderung (Request Sample) mit delay und delayMicroseconds. Danach wird der Pin als Eingang geschaltet. Mit pulseIn werden die ca. 70 us der Antwort (Acknowledge) abgewartet. Zeitlich entspricht dies dem 5. Skalenteil des Oszillogramms oben. Die 40 Bits (Read Output) werden nun anhand der Impulsbreite abgefragt, dabei liegt die zeitliche Schwelle bei 40 us. Falls der Impuls länger ist, wird ein gesetztes Bit (1) bitcnt-mal nach links geschoben (<<), damit es im Byte an der richtigen Stelle steht. Wenn ein Byte voll ist, wird der Bytezähler ix erhöht. Das wird so auch in der entsprechenden Bibliothek gemacht.

Sind alle 40 Bits eingelaufen, folgen die Variablenzuweisungen. Für den DHT11 gibt es keine Kommastellen, darum wird das Byte 0 zur Luftfeuchte und das Byte 3 zur Temperatur. An dieser Stelle müsste dies für Sensoren wie DHT22 etwas angepasst werden, ebenso wie die Checksummenabfrage (die im Hobbybereich auch entfallen kann). Zum Schluss erfolgt die Umwandlung der Zahlen in Zeichenketten. In C ist das itoa (Integer zu Ascii).

Bei genauem Hinsehen erfolgt die Abfrage der Impulslänge der 40 Bit nicht mit der eingebauten pulseIn()-Funktion, da diese hier aus noch unklaren Gründen nicht so wie erwartet funktioniert. Das liegt möglicherweise an der gerade benutzen Arduino-IDE. Zur Umgehung dieses Problems wird eine ähnliche Routine aufgerufen, die hier das erwartete Ergebnis zeigt: mypulseIn

Pulslängenabfrage Eigenbau mypulseIn()
Die integrierte pulseIn-Funktion wurde schon beim Projekt "Arduino als Zähler" erfolgreich verwendet. Falls Flanken nicht per Interrupt verarbeitet werden müssen, ist eine solche Funktion einfach in der Handhabung. Wenn die Beschreibung der Funktion unter Arduino.cc richtig verstanden wurde, ergibt sich - ohne im Quelltext zu wühlen - etwa folgender Ablauf:

unsigned long mypulseIn(int pin,int level)
{unsigned long t0,t1,t2,timeout=200;
 t0=micros();
 if(level==HIGH)
 {while(!digitalRead(pin) && (micros()-t0)<timeout);//Wait for _/
  t1=micros();
  while( digitalRead(pin) && (micros()-t1)<timeout);//Wait for \_
  t2=micros();
 }
 else
 {while( digitalRead(pin) && (micros()-t0)<timeout);//Wait for \_
  t1=micros();
  while(!digitalRead(pin) && (micros()-t1)<timeout);//Wait for _/
  t2=micros();
 }
 return t2-t1; 
}

Diese Eigenbauroutine mit festen 200 us Timeout funktioniert hier mit dem Arduino Uno R3. Der Gesamtquelltext ist hier hinterlegt.

											

										

Weitere Software
.
Startseite Bücher Software Digital RTV Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt