Temperaturmessung mit dem Arduino

Ein interessantes Projekt mit Tiefgang

Der Arduino eignet sich bestens, Signale von Sensoren auszuwerten und auf der Grundlage der erhaltenen Ergebnisse unmittelbar Ereignisse auszulösen. Hier bietet sich beispielsweise ein Temperatur- und Feuchtesensor an, der zusammen mit einem Uhrenmodul ein Überwachungssystem für Räume bilden kann.

Die Aufgabe, Räume hinsichtlich der Temperatur sowie der Luftfeuchte zu überwachen, ist immer dann wichtig, wenn die diesbezüglichen Werte keine kritischen Werte unter- oder überschreiten dürfen. Dies kann beispielsweise in einer zerspanenden Fertigung oder im Druckgewerbe der Fall sein. In beiden Fällen ist es nötig, durch die Einhaltung eines Temperatur- und Feuchtigkeitsbereichs sicherzustellen, dass Passungen korrekt produziert werden und Papier zuverlässig durch die Druckmaschine läuft.

Zur Ermittlung von Temperatur und Luftfeuchtigkeit werden preisgünstige Module angeboten, die unmittelbar an Kleincomputer, wie etwa den Arduino angeschlossen werden können. Hier ist beispielsweise der digital arbeitende Sensor ›DHT11‹ zu nennen. Dieser besitzt je nach Version drei oder vier Anschlüsse und kann Temperaturen im Bereich von 0 bis 50 Grad Celsius sowie die Luftfeuchtigkeit im Bereich von 20 bis 90 Prozent erfassen.

Der Anschluss dieses Sensors am Arduino ist recht einfach, wie nachfolgende Zeichnung zeigt:

Wichtig!

Wichtig!

Auf jeden Fall einen sogenannten Pullup-Widerstand einbauen! Ein Zehn Kiloohm-Exemplar ist in diesem Fall geeignet.

Das zur Ansteuerung des Sensormoduls nötige Programm könnte wie folgt aussehen:

#include <SimpleDHT.h>
int pinDHT11 = 7; //Pin 7 als Eingang für das Temperatursignal festlegen
SimpleDHT11 dht11(pinDHT11);

void setup() {
Serial.begin(9600); } // Nötig für das Ansprechen des Monitors

void loop() {
Serial.println("=================================");
Serial.println("Stichprobe DHT11...");
float temperature = 0; // Festlegen von temperature als Flieskommavariable, Startwert=0
float humidity = 0; // Festlegen von humidity als Flieskommavariable, Startwert=0
int err = SimpleDHTErrSuccess;

//***** Fehlerroutine für Sensor *******
if((err=dht11.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess){
Serial.print("Lesefehler DHT11, err=");
Serial.println(err);
delay(2000); // Kleine Wartepause
return;

}

Serial.print("Stichprobe OK: ");
Serial.print((float)temperature);
Serial.print(" *C, ");
Serial.print((float)humidity);
Serial.println(" RH%"); delay(1500); // DHT11-Abtastrate ist 1HZ.

Wird der Monitor der Arduino-Entwicklungsumgebung aufgerufen, so bietet sich nebenstehendes Bild:

Es zeigt sich demnach, dass der Sensor korrekt angeschlossen ist und wie gewünscht arbeitet.

Soll die Temperatur- beziehungsweise Luftfeuchtemessung zusammen mit der Uhrzeit und dem aktuellen Datum protokolliert werden, so ist dem Schaltungsaufbau noch ein Uhrenmodul – etwa das Modell ›ZS-042‹ von AZ-Delivery – hinzuzufügen.

Dieses Modell besitzt auf der Rückseite eine Knopfzellenbatterie vom Typ ›CR2032‹, was eine Beibehaltung der Uhrzeit beim Abschalten der Stromzufuhr zum Arduino ermöglicht.

Der Anschluss am Arduino ist rasch erledigt, wie folgender Schaltplan verdeutlicht:

Wichtig!

Es vor allem darauf zu achten, dass der Anschluss ›VCC‹ des Uhrenmoduls ausschließlich am 3,3 V-Anschluss des Arduinos angeschlossen wird!

Ein lauffähiges Programm zum Betrieb der Uhr könnte wie folgt aussehen:

#include <Wire.h> // Datums- und Zeit-Funktionen der DS3231 RTC werden über das I2C aufgerufen.
#include "RTClib.h"

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
bool syncOnFirstStart = false; // true, falls die Zeitinformationen der RTC mit dem PC synchronisiert werden sollen.

void setup () {
pinMode(LED_BUILTIN, OUTPUT);

Serial.begin(9600);

if (! rtc.begin()) {
Serial.println("Kann RTC nicht finden");
while (1);
}

if (rtc.lostPower() || syncOnFirstStart) {
Serial.println("Die RTC war vom Strom getrennt. Die Zeit wird neu synchronisiert.");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
}

void loop () {

DateTime now = rtc.now();

// immer, wenn die RTC auf 0, 10, 20, 30, 40 oder 50 volle Sekunden hochgezählt hat,
// werden Datum und Zeit angegeben und die LED des Arduino leuchtet für eine Sekunde.

if (now.second() % 10 == 0) {
digitalWrite(LED_BUILTIN, HIGH);

Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();

delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(8000); // Unterbrechung der Zeitabfrage bis kurz vor dem nächsten 10s-Wert
}
}

Die Anzeige auf dem Monitor sieht wie folgt aus:

So richtig interessant wird der Umgang mit Sensoren und Uhren erst, wenn deren Daten auf einem LCD-Display ausgegeben werden, da dann ein Betrieb ohne PC gegeben ist, um Daten sichtbar zu machen.

Der dazu nötige Schaltplan könnte wie folgt aussehen:

Wichtig!

Es vor allem darauf zu achten, dass der Anschluss ›VCC‹ des Uhrenmoduls ausschließlich am 3,3 V-Anschluss des Arduinos angeschlossen wird!

Das Programm zum Ausgeben der Werte des Temperatur- sowie des Uhrenmoduls auf der LCD-Anzeige könnte wie folgt aussehen:

//**********************************************
// LCD-Anzeige, Uhr und Temperatursensor gemeinsam betreiben
//***********************************************

#include <Wire.h> // Datums- und Zeit-Funktionen der DS3231 RTC werden aufgerufen.
#include "RTClib.h" // Treiber Uhrenbaustein einbinden
#include <LiquidCrystal.h> // Treiber LCD-Anzeige einbinden
#include <SimpleDHT.h> // Treiber Temperatursensor

//****** Variablendeklaration ******
int pinDHT11 = 7; //Pin 7 als Eingang für das Temperatursignal
SimpleDHT11 dht11(pinDHT11); // Temperatursensor-Funktion mit Signaleingang verknüpft
RTC_DS3231 rtc; // Uhrenbaustein-Funktion
LiquidCrystal lcd(11, 10, 2, 3, 4, 5); // LCD-Pins festlegen für RS, E, D4, D5, D6, D7

char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};

bool syncOnFirstStart = false; // true, falls die Zeitinformationen der RTC mit dem PC synchronisiert werden sollen.

void setup () {
pinMode(LED_BUILTIN, OUTPUT); //
analogWrite(9, 150); // Pin 9 mit PWM-Analogwert 150 beaufschlagen
Serial.begin(9600); // Einstellung für Monitor

// *****LCD Ausgabe******
lcd.begin(16, 2);
lcd.setCursor(3, 0);
lcd.print("Hallo Welt!");
lcd.setCursor(3, 1);
lcd.print("WDF-Power");
delay(3000); // Kleine Pause
lcd.clear(); // LCD-Anzeige komplett löschen

Serial.begin(9600);

//*** Fehlrroutine, wenn Uhr z.B. defekt ist *****
if (! rtc.begin()) {
Serial.println("Kann RTC nicht finden");
while (1);
}

if (rtc.lostPower() || syncOnFirstStart) {
Serial.println("Die RTC war vom Strom getrennt. Die Zeit wird neu synchronisiert.");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Uhrzeit Startzeitpunkt
}
}

void loop () {
//******* Temperatur auf Monitor ausgeben *******
float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;

//****** Fehlerbehandlung Temperatursensorabfrage *****
if((err=dht11.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess){
// Hier könnte eine Routine für eine Meldungsausgabe stehen
return;
}

//***** Zeit auf Monitor ausgeben ******
DateTime now = rtc.now();
// immer, wenn die RTC auf 1 Sekunde hochgezählt hat, sollen Datum und Zeit
// angegeben werden und die boardinterne LED im Sekundentakt leuchten.
if (now.second() % 1 == 0) { // Wenn 1 Sekunde vergangen, dann weiter im Programm...

//******* Temperatur und Luftfeuchtigkeit am LCD-Display im Uhrentakt ausgeben ******
lcd.clear(); // LCD-Anzeige komplett löschen
lcd.setCursor(0, 0); // Cursor auf LCD-Zeile 1 Pos links stellen
lcd.print((float)temperature,1); // Temperatur mit 1 Nachkommastelle anzeigen
lcd.print(" C ");
lcd.print((float)humidity,0); // Luftfeuchtigkeit ohne Nachkommastelle anzeigen
lcd.print(" RH% "); //delay(1500); // DHT11 sampling rate is 1HZ.

//********* Datum, Wochentag und Uhrzeit auf LCD-Display ausgeben *************
lcd.setCursor(0, 1); // Cursor auf LCD-Zeile 2 Pos links stellen
lcd.print(now.hour(), DEC); //Stunde
lcd.print(':');
lcd.print(now.minute(), DEC); //Minute
lcd.print(':');
lcd.print(now.second(), DEC); //Sekunde
lcd.setCursor(10, 1); // Cursorposition für Datumsanzeige
lcd.print(now.day(), DEC); //Tag
lcd.print('.');
lcd.print(now.month(), DEC); //Monat

digitalWrite(LED_BUILTIN, HIGH);

//******* Temperatur und Luftfeuchtigkeit am Monitor im Uhrentakt ausgeben ******
Serial.print("Temperatur: ");
Serial.print((float)temperature);
Serial.print(" Grad Celsius, ");
Serial.print((float)humidity);
Serial.println(" RH%"); // DHT11-Samplingrate ist 1HZ.

//********* Datum, Wochentag und Uhrzeit auf Monitor ausgeben *************
Serial.print(now.day(), DEC); //Tag
Serial.print('.');
Serial.print(now.month(), DEC); //Monat
Serial.print('.');
Serial.print(now.year(), DEC); //Jahr
Serial.print(" ("); // Klammer auf für Wochentag
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); //Wochentag
Serial.print(") "); // Klammer zu für Wochentag
Serial.print(now.hour(), DEC); //Stunde
Serial.print(':');
Serial.print(now.minute(), DEC); //Minute
Serial.print(':');
Serial.print(now.second(), DEC); //Sekunde
Serial.println();

digitalWrite(LED_BUILTIN, LOW);
}
}

Hinweis:

Die Programmteile hinsichtlich der Datenanzeige auf dem Monitor dienen nur dem Verständnis und können wahlweise entfernt werden.

Einsatz eines Buzzers:

Es bietet sich in diesem Projekt an, einen hörbaren Alarm per Buzzer auszulösen, wenn die Toleranzbereiche für die Temperatur beziehungsweise die Luftfeuchtigkeit über- oder unterschritten werden.

Buzzer gibt es als passive (links im Bild) sowie als aktive (rechts im Bild) Bauteile. Der Unterschied ist, dass ein aktiver Buzzer einen integrierten Oszillator besitzt, ein passiver Buzzer jedoch nicht. Die Funktion des Oszillators muss daher bei einem passiven Buzzer vom Arduino übernommen werden.

Dies bedeutet, dass ein passiver Buzzer vom Arduino über den Befehl ›tone()‹ mit einem entsprechenden Signal versorgt wird, während ein aktiver Buzzer dazu lediglich ein Dauersignal auf einem Pin benötigt. Alternativ ist es bei einem passiven Buzzer möglich, durch Ein- und Ausschalten eines Dauersignals praktisch einen Oszillator zu simulieren, sodass auch dieser Weg zu einem hörbaren Alarmsignal führt.

Das Programm könnte wie folgt aussehen:

int Buzzer = 8; // Variable Buzzer entspricht Pin 8

void setup() {
pinMode(Buzzer, OUTPUT); // Pin 8 als Buzzer-Speiseausgang definieren
}

void loop() {
digitalWrite(Buzzer, HIGH); // Dauersignal an Pin 8 ausgeben
delay(100); // 1/10-Sekunde Haltezeit für das Dauersignal
digitalWrite(Buzzer, LOW); // Dauersignal wieder abschalten
delay(100); // 1/10-Sekunde Wartezeit
}

Hinweis:

Dieses Beispielprogramm ist für beide Buzzer-Bauarten nutzbar.

Ein funktionsfähiger Aufbau mit allen bisher verbauten Komponenten könnte wie folgt aussehen:

Hinweis:

Ärgerlich ist, dass ein Buzzer nicht unbedingt für ältere Personen hörbar ist, da dessen Frequenz womöglich außerhalb deren Hörvermögen arbeitet. In diesem Fall ist es angebracht, zusätzlich noch ein optisches Warnsignal für die Unter- oder Überschreitung der Temperatur beziehungsweise des Feuchtewerts in der LCD-Anzeige unterzubringen.

Natürlich ist zudem daran zu denken, eine Programmroutine in den Sketch einzubauen, die dafür sorgt, dass der Buzzer sich nur dann meldet, wenn Grenzwerte unter- oder überschritten werden. Gleiches gilt für die Anzeige in der LCD.

Ein entsprechendes Programm könnte folgendermaßen aussehen:

//***** Alarm ausgeben ********
if (((float)temperature) >25||((float)humidity) >40){
//**Buzzer**
digitalWrite(Buzzer, HIGH);
delay(100);
digitalWrite(Buzzer, LOW);
delay(100);
//**LCD-Warnung anzeigen**
lcd.setCursor(15, 0); // Cursor auf LCD-Zeile 0 und Spalte 15 stellen
lcd.print("!"); // Zeichen für Alarm
}

Erklärung:

Die größte Hürde zum Verständnis des Programms stell sicher der folgende Befehl dar:

if (((float)temperature) >25||((float)humidity) >40){

Übersetzt lautet der Befehl: Wenn Variable „temperature“ einen Wert über 25 ODER die Variable „humidity“ einen Wert über 40 besitzt, dann starte die Fehlerbehandlungsroutine.

Wichtig ist nun zu wissen, dass die geschweifte Klammer ›{‹ den Beginn der Fehlerbehandlungsroutine darstellt, während die Klammer ›}‹ die Routine abschließt.

Die logische Funktion ODER wird durch einen Doppelstrich ›||‹ gekennzeichnet, während eine UND-Funktion mit zwei kaufmännischen &&-Zeichen dargestellt wird. Sollte beispielsweise sichergestellt werden, dass der Alarm nur dann startet, wenn sowohl die Temperatur, als auch die Luftfeuchtigkeit ihre jeweiligen Grenzwerte übersteigen, so müsste der if-Befehl wie folgt abgeändert werden:

if (((float)temperature) >25&&((float)humidity) >40){

Eine LED hinzufügen:

Zur deutlicheren Sichtbarmachung eines Alarms auf größerer Strecke bietet es sich an, zusätzlich eine LED in die Schaltung einzufügen. Die dazu nötige Schaltung könnte wie folgt aussehen:

Das Programm zur Ansteuerung der LED ist relativ übersichtlich:

void setup() {

// Digital-Pin 6 als Ausgang festlegen
pinMode(6, OUTPUT);
}

void loop() {
digitalWrite(6, HIGH); // LED anschalten
delay(100); // 1/10-Sekunde warten
digitalWrite(6, LOW); // LED abschalten
delay(100); // 1/10-Sekunde warten
}

Wird nun das komplette Programm mit dem LED-Teil kombiniert, so ergibt sich:

//**********************************************
// LCD-Anzeige, Uhr und Temperatursensor gemeinsam betreiben
//***********************************************

#include <Wire.h> // Die Datums- und Zeit-Funktionen der DS3231 RTC werden aufgerufen.
#include "RTClib.h" // Treiber Uhrenbaustein einbinden
#include <LiquidCrystal.h> // Treiber LCD-Anzeige einbinden
#include <SimpleDHT.h> // Treiber Temperatursensor

//****** Variablendeklaration ******
int pinDHT11 = 7; //Variable pinDHT11 bekommt den Wert 7
int Buzzer = 8; //Variable Buzzer bekommt den Wert 8
int LED = 6; //Variable LED bekommt den Wert 6

SimpleDHT11 dht11(pinDHT11); // Temperatursensor-Funktion mit Signaleingang verknüpft
RTC_DS3231 rtc; // Uhrenbaustein-Funktion
LiquidCrystal lcd(11, 10, 2, 3, 4, 5); // LCD-Pins festlegen für RS, E, D4, D5, D6, D7
char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
bool syncOnFirstStart = false; // true, falls die Zeitinformationen der RTC mit dem PC synchronisiert werden sollen.

void setup () {
pinMode(LED_BUILTIN, OUTPUT);
analogWrite(9, 150); // Pin 9 für LCD-Hintergrundbeleuchtung
pinMode(Buzzer, OUTPUT); // Pin 8 als Ausgang für Buzzer
pinMode(LED, OUTPUT); // Pin 6 als Ausgang für LED
Serial.begin(9600); // Einstellung für Monitor

// *****LCD Ausgabe******
lcd.begin(16, 2);
lcd.setCursor(3, 0);
lcd.print("Hallo Welt!");
lcd.setCursor(3, 1);
lcd.print("WDF-Power");
delay(3000); // Kleine Pause
lcd.clear(); // LCD-Anzeige komplett löschen

Serial.begin(9600);

//*** Fehlrroutine, wenn Uhr z.B. defekt ist *****
if (! rtc.begin()) {
Serial.println("Kann RTC nicht finden");
while (1);
}

if (rtc.lostPower() || syncOnFirstStart) {
Serial.println("Die RTC war vom Strom getrennt. Die Zeit wird neu synchronisiert.");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Uhrzeit Startzeitpunkt
}
}

void loop () {

//******* Temperatur auf Monitor ausgeben *******
float temperature = 0;
float humidity = 0;
int err = SimpleDHTErrSuccess;

//****** Fehlerbehandlung Temperatursensorabfrage *****
if((err=dht11.read2(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess){
// Hier könnte eine Routine für eine Meldungsausgabe stehen
return;
}

//***** Zeit auf Monitor ausgeben ******
DateTime now = rtc.now();
// immer, wenn die RTC auf 1 Sekunde hochgezählt hat, sollen Datum und Zeit
// angegeben werden und die boardinterne LED im Sekundentakt leuchten.
if (now.second() % 1 == 0) { // Wenn 1 Sekunde vergangen, dann weiter im Programm...

//***** LCD löschen ****
lcd.clear(); // LCD-Anzeige komplett löschen

//***** Alarm ausgeben ********
if (((float)temperature) >25||((float)humidity) >42){
//**Buzzer**
digitalWrite(Buzzer, HIGH);
delay(100);
digitalWrite(Buzzer, LOW);
delay(100);
//**LCD-Warnung anzeigen**
lcd.setCursor(15, 0); // Cursor auf LCD-Zeile 0 und Spalte 15 stellen
lcd.print("!"); // Zeichen für Alarm
//**LED ansprechen**
digitalWrite(LED, HIGH); // LED anschalten
delay(100); // 1/10-Sekunde warten
digitalWrite(LED, LOW); // LED abschalten
delay(100); // 1/10-Sekunde warten
}

//******* Temperatur und Luftfeuchtigkeit am LCD-Display im Uhrentakt ausgeben ******
lcd.setCursor(0, 0); // Cursor auf LCD-Zeile 1 Pos links stellen
lcd.print((float)temperature,1); // Temperatur mit 1 Nachkommastelle anzeigen
lcd.print(" C ");
lcd.print((float)humidity,0); // Luftfeuchtigkeit ohne Nachkommastelle anzeigen
lcd.print(" RH% "); //delay(1500); // DHT11 sampling rate is 1HZ.

//********* Datum, Wochentag und Uhrzeit auf LCD-Display ausgeben *************
lcd.setCursor(0, 1); // Cursor auf LCD-Zeile 2 Pos links stellen
lcd.print(now.hour(), DEC); //Stunde
lcd.print(':');
lcd.print(now.minute(), DEC); //Minute
lcd.print(':');
lcd.print(now.second(), DEC); //Sekunde
lcd.setCursor(10, 1); // Cursorposition für Datumsanzeige
lcd.print(now.day(), DEC); //Tag
lcd.print('.');
lcd.print(now.month(), DEC); //Monat
digitalWrite(LED_BUILTIN, HIGH);

//******* Temperatur und Luftfeuchtigkeit am Monitor im Uhrentakt ausgeben ******
Serial.print("Temperatur: ");
Serial.print((float)temperature);
Serial.print(" Grad Celsius, ");
Serial.print((float)humidity);
Serial.println(" RH%"); // DHT11-Samplingrate ist 1HZ.

//********* Datum, Wochentag und Uhrzeit auf Monitor ausgeben *************
Serial.print(now.day(), DEC); //Tag
Serial.print('.');
Serial.print(now.month(), DEC); //Monat
Serial.print('.');
Serial.print(now.year(), DEC); //Jahr
Serial.print(" ("); // Klammer auf für Wochentag
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); //Wochentag
Serial.print(") "); // Klammer zu für Wochentag
Serial.print(now.hour(), DEC); //Stunde
Serial.print(':');
Serial.print(now.minute(), DEC); //Minute
Serial.print(':');
Serial.print(now.second(), DEC); //Sekunde
Serial.println();
digitalWrite(LED_BUILTIN, LOW);
}
}

Projektabschluss:

Das Projekt ist nun abgeschlossen und kann um eigene Vorstellungen erweitert werden.