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.
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.
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
}
}
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.
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.
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:
Ä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);
}
}