Hi Leute,
ich bin absoluter Arduino-Anfänger und sitze jetzt seit 1-2 Wochen an einer Steuerung für ein kleines Mini-Gewächshaus. Bei dem Projekt wird die Luft-Temperatur und Luftfeuchtigkeit im Gewächshaus mittels DHT22 gemessen. Zusätzlich befindet sich in er Erde ein DS18B20 Temperatursensor, der die Erd-Temperatur überwacht.
Nun zeigt der DS18B20 im Wechsel die richtige Temperatur (21,9°C) und -127°C.
Ich habe schon gelesen, dass das der Standart-Wert des DS18B20 ist, wenn er nicht richtig angesteuert wird.
Ich habe schon einige Sachen ausprobiert aber finde den Fehler in meinem Sketch nicht.
Kann jemand von euch den Fehler erkennen? Das würde mir sehr helfen:
// Arduino Gewächshaussteuerung 1.0
// TG
// 24.07.2022
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // Bibliothek für I2C-LCD-Displays
#include <FreqCounter.h> // Giesomat > Frequenz-Zähler (zählt die Impulse innerhalb einer bestimmten Zeit)
#include <DHT.h> // DHT Bibliothek laden
#include "RTClib.h" // RTC-Libary laden "RTClib"
//Pins Sensoren
#define ONE_WIRE_BUS 2 // Datenkabel von DS18B20 an Pin 2
#define DHTPIN 4 // Der DHT-Sensor wird an PIN 4 angeschlossen
#define DHTTYPE DHT22 // Es handelt sich um den DHT22 Sensor
// Pins Relais Modus
#define PIN_RELAY1_HEIZEN 9 // Heizmatte
#define PIN_RELAY2_LUFT 10 // Lüfter
#define PIN_RELAY3_WASSER 11 // Bewässerung
#define PIN_RELAY4_LICHT 12 // Licht
LiquidCrystal_I2C lcd(0x27,20,4); // setzt LCD Adresse auf 0x27 für 20 Zeichen and 4 Zeilen
OneWire oneWire(ONE_WIRE_BUS); // Setup a OneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire); // Pass OneWire reference to Dallas Temperature
DHT dht(DHTPIN, DHTTYPE); // Der Sensor wird ab jetzt mit „dth“ angesprochen
RTC_DS3231 rtc;
// ---------- BENUTZERDEFINIERTE WERTE ---------- //
// Tag-Beginn (Uhrzeit)
int STUNDE_TAG = 8; // Uhrzeit (Stunde) wann Tag-Zeit beginnen soll
int MINUTE_TAG = 00; // Uhrzeit (Minute) wann Tag-Zeit beginnen soll
//Nacht-Beginn (Uhrzeit)
int STUNDE_NACHT = 20; // Uhrzeit (Stunde) wann Nacht-Zeit beginnen soll
int MINUTE_NACHT = 00; // Uhrzeit (Minute) wann Nacht-Zeit beginnen soll
// Grenzwerte Erd-Temperatur
int temperatur_erde_min = 22; // Minimale Erdtemperatur unter derer die Heizmatte zum heizen einschalten soll
int temperatur_erde_max = 25; // Maximale Erdtemperatur ueber derer die Luefter zum abkuehlen einschalten sollen
int temperaturabsenkung_erde_nacht = -2; // allgemeine Temperaturabsenkung der Erde für die Nacht (reduziert die minimale und maximale Erdtemperatur für die Nacht)
int temp_erde_min, temp_erde_max;
// Grenzwert Bodenfeuchtigkeit
int feuchtigkeit_erde_min = 50; // Minimale Bodenfeuchtigkeit unter derer die Bewässerung einschalten soll
// Kalibrierung Giesomat
int freq_max = 25380; // Frequenz bei absoluter Trockenheit (0%)
int freq_min = 3300; // Frequenz bei absoluter Nässe (100%)
/* 06. Juni 2022 - mit Frequenzteiler: freq_max = 4386; freq_min = 363;
22. Juli 2022 - ohne Frequenzteiler: freq_max = 25380 (0%); freq_min = 3300 (100%); ideal = 9440 (69%)*/
// Lüftersteuerung nach Luftfeuchtigkeit oder zeitgesteuert
int luefter_steuerung = 0; // Lüftersteuerung nach Luftfeuchtigkeit = 0, Lüftersteuerung nach Zeitschaltuhr = 1
int luftfeuchte_max = 90; // Maximale Luftfeuchtigkeit ueber derer die Luefter zum trocknen einschalten sollen (Bedingung: Lüftersteuerung = 0)
int luefter_aktiv = 3; // Wie lange soll der Lüfter eingeschaltet bleiben (in Minuten), Voraussetzung: luefter_steuerung = 1
int luefter_inaktiv = 5; // Wie lange soll der Lüfter ausgeschaltet bleiben (in Minuten), Voraussetzung: luefter_steuerung = 1
// -------------------------------------------- //
// DEFINITION ZEITSCHALTUHR
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
unsigned long MyLuefterTimer = 0; // Timer-variables MUST be of type unsigned long
const unsigned long luefter_akt = luefter_aktiv * 60 * 1000UL; // Bsp: 3 Min * 60 Sek * 1000 Millisekunden = 180.000
const unsigned long luefter_inakt = luefter_inaktiv * 60 * 1000UL; // Bsp: 5 Min * 60 Sek * 1000 Millisekunden = 300.000
unsigned long SchaltIntervall;
boolean luefter_laeuft;
long int frq; // Frequenz als lange Ganzzahl nutzen
//BENUTZERDEFINIERTE SYMBOLE (max. 8)
byte thermometer[8] = {
B00100,
B01010,
B01010,
B01010,
B01010,
B10001,
B11111,
B01110
};
byte tropfen[8] = {
B00010,
B00110,
B00110,
B01110,
B01111,
B11111,
B11111,
B01110
};
byte pfeil_hoch[8] = {
B00100,
B01010,
B10001,
B00000,
B00100,
B01010,
B10001,
B00000
};
byte licht_an[8] = {
B00100,
B10101,
B01010,
B01010,
B10101,
B00100,
B00000,
B00000
};
byte pfeil_runter[8] = {
B10001,
B01010,
B00100,
B00000,
B10001,
B01010,
B00100,
B00000
};
byte luefter1[8] = {
B01000,
B10101,
B00010,
B01000,
B10101,
B00010,
B00000,
B00000
};
byte luefter2[8] = {
B01110,
B10101,
B10101,
B10111,
B10001,
B01110,
B00000,
B00000
};
void setup(void)
{
Serial.begin(9600); // Start serieller Monitor
sensors.begin(); // Start up the library
dht.begin(); // DHT22 Sensor starten
lcd.init(); // Display initialisieren
lcd.backlight(); // Display Hintergrundbeleuchtung einschalten
lcd.clear(); //Display zurücksetzen
lcd.createChar(0, thermometer); // Erstellt das Thermometer Zeichen
lcd.createChar(1, tropfen); // Erstellt das Tropfen Zeichen
lcd.createChar(2, pfeil_hoch); // Erstellt das Pfeil hoch Zeichen
lcd.createChar(3, licht_an); // Erstellt das Licht an Zeichen
lcd.createChar(4, pfeil_runter); // Erstellt das Pfeil runter Zeichen
lcd.createChar(6, luefter1); // Erstellt das Luefter1 Zeichen
lcd.createChar(7, luefter2); // Erstellt das Luefter2 Zeichen
rtc.begin(); // RTC Modul starten
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Uhrzeit vom PC übernehmen (Nur beim ersten Mal - danach wieder deaktivieren!)
pinMode(PIN_RELAY1_HEIZEN, OUTPUT); // Pin an Relais 1 auf Ausgabe stellen
digitalWrite(PIN_RELAY1_HEIZEN, HIGH); // Pin an Telais 1 zu Beginn ausschalten
pinMode(PIN_RELAY2_LUFT, OUTPUT); // Pin an Relais 2 auf Ausgabe stellen
digitalWrite(PIN_RELAY2_LUFT, LOW); // Pin an Telais 2 zu Beginn ausschalten
Serial.println("Setup: Lüftung EIN");
pinMode(PIN_RELAY3_WASSER, OUTPUT); // Pin an Relais 3 auf Ausgabe stellen
digitalWrite(PIN_RELAY3_WASSER, HIGH); // Pin an Telais 3 zu Beginn ausschalten
pinMode(PIN_RELAY4_LICHT, OUTPUT); // Pin an Relais 4 auf Ausgabe stellen
digitalWrite(PIN_RELAY4_LICHT, HIGH); // Pin an Telais 4 zu Beginn ausschalten
luefter_laeuft = true;
SchaltIntervall = luefter_akt;
MyLuefterTimer = millis(); // Der Zeitstempel des Schaltens wird in MyLuefterTimer (Variable) gespeichert
}
void loop(void){
// RTC UHRZEIT
DateTime now = rtc.now(); // Uhrzeit über RTC Modul abfragen
// NÄCHTLICHE TEMPERATURABSENKUNG
if(now.hour() < STUNDE_TAG || now.hour() >= STUNDE_NACHT) { // Wenn aktuelle Stunde (Uhrzeit) kleiner als Beginn-Tageszeit ODER größer als Beginn Nachtzeit, dann
temp_erde_min = temperatur_erde_min + temperaturabsenkung_erde_nacht; // minimaler Grenzwert für Erd-Temperatur mit nächtlicher Absenkung verrechnen
temp_erde_max = temperatur_erde_max + temperaturabsenkung_erde_nacht; // maximaler Grenzwert für Erd-Temperatur mit nächtlicher Absenkung verrechnen
} else { // Sonst
temp_erde_min = temperatur_erde_min; // minimaler Grenzwert für Erd-Temperatur wie eingetragen (ohne Korrektur "Nächtliche Absenkung")
temp_erde_max = temperatur_erde_max; // maximaler Grenzwert für Erd-Temperatur wie eingetragen (ohne Korrektur "Nächtliche Absenkung")
}
// SENSOREN AUSLESEN
// DS18B20
sensors.requestTemperatures(); // DS18B20 Temp-Sensor auslesen
// Giesomat
FreqCounter::f_comp= 8; // Kompensation einstellen
FreqCounter::start(100); // Startet Zählung für 100 ms
while (FreqCounter::f_ready == 0) // Warten bis Zählung abgeschlossen
frq=FreqCounter::f_freq; // Ergebnis lesen
frq=(-frq - -freq_max)*100/(-freq_min - -freq_max); // Frequenz in Prozent umrechnen
// DHT22 auslesen
float DHT_Luftfeuchtigkeit = dht.readHumidity(); // die Luftfeuchtigkeit auslesen und definieren als „DHT_Luftfeutchtigkeit“
float DHT_Temperatur = dht.readTemperature(); // die Temperatur auslesen und definieren als „DHT_Temperatur“
// AKTIONEN
// Wenn Tag dann Licht einschalten
if(now.hour() >= STUNDE_TAG && now.hour() < STUNDE_NACHT) { // Wenn aktuelle Stunde (Uhrzeit größer gleich Beginn-Tageszeit und kleiner als Beginn Nachtzeit, dann
digitalWrite(PIN_RELAY4_LICHT, LOW); // Relais 4 (Licht) einschalten
Serial.println("Tag: Licht EIN!"); // serielle Monitor Ausgabe: "Tag: Licht EIN!"
} else { // Sonst
digitalWrite(PIN_RELAY4_LICHT, HIGH); // Relais 4 (Licht) ausschalten
Serial.println("Nacht: Licht AUS!"); // serielle Monitor Ausgabe: "Nacht: Licht AUS!"
}
//BODENTEMPERATUR
if (sensors.getTempCByIndex(0) <= temp_erde_min) { // Wenn Bodentemperatur kleiner gleich Grenzwert minimale Erdtemperatur (inkl. nächt. Absenk.) dann
digitalWrite(PIN_RELAY1_HEIZEN, LOW); // Relais 1 (Heizmatte) einschalten
Serial.println("Bodentemperatur zu niedrig > Heizmatte EIN"); // serielle Monitor Ausgabe: "Bodentemperatur zu niedrig > Heizmatte EIN"
} else { // Sonst
digitalWrite(PIN_RELAY1_HEIZEN, HIGH); // Relais 1 (Heizmatte) ausschalten
Serial.println("Bodentemperatur OK"); // serielle Monitor Ausgabe: "Bodentemperatur OK"
}
//LUFTFEUCHTIGKEIT
if (luefter_steuerung == 0 && DHT_Luftfeuchtigkeit >= luftfeuchte_max || sensors.getTempCByIndex(0) >= temp_erde_max) { // Wenn Luftfeuchtigkeit höher max. Grenzwert ODER Bodentemperatur höher als max. Grenzwert, dann
digitalWrite(PIN_RELAY2_LUFT, LOW); // Relais 2 (Lüfter) einschalten
Serial.println("Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"); // serielle Monitor Ausgabe: "Luftfeuchtigkeit ODER Bodentemperatur zu hoch > Lüftung EIN"
}
else if (luefter_steuerung == 0) { // Sonst noch wenn
digitalWrite(PIN_RELAY2_LUFT, HIGH); // Relais 2 (Lüfter) ausschalten
Serial.println("Luftfeuchtigkeit UND Bodentemperatur OK"); // serielle Monitor Ausgabe: "Luftfeuchtigkeit UND Bodentemperatur OK"
}
// ZEITSCHALTUHR
if (luefter_steuerung == 1) {
lcd.setCursor(9, 0); // Cursor setzen: 10. Stelle, 1. Zeile
lcd.write(byte(7));
if ( TimePeriodIsOver(MyLuefterTimer, SchaltIntervall) ) {
if (luefter_laeuft) {
digitalWrite(PIN_RELAY2_LUFT, HIGH);
Serial.println("Zeitsteuerung aktiv: Lüftung AUS");
luefter_laeuft = false;
SchaltIntervall = luefter_inakt;
}
else {
digitalWrite(PIN_RELAY2_LUFT, LOW);
Serial.println("Zeitsteuerung aktiv: Lüftung EIN");
luefter_laeuft = true;
SchaltIntervall = luefter_akt;
}
}
}
if (digitalRead(10) == LOW) {
lcd.setCursor(10, 0); // Cursor setzen: 10. Stelle, 1. Zeile
lcd.write(byte(6));
} else {
lcd.setCursor(10, 0); // Cursor setzen: 10. Stelle, 1. Zeile
lcd.print(" ");
}
//BODENFEUCHTIGKEIT
if (frq < feuchtigkeit_erde_min && frq > 0) { // Wenn Bodenfeuchtigkeit unter min. Grenzwert UND über Null, dann
digitalWrite(PIN_RELAY3_WASSER, LOW); // Relais 3 (Bewässerung) einschalten
Serial.println("Bodenfeuchte zu niedrig > Bewässerung EIN"); // serielle Monitor Ausgabe: "Bodenfeuchte zu niedrig > Bewässerung EIN"
} else { // Sonst
digitalWrite(PIN_RELAY3_WASSER, HIGH); // Relais 3 (Bewässerung) ausschalten
Serial.println("Bodenfeuchte OK"); // serielle Monitor Ausgabe: "Bodenfeuchte OK"
}
//DISPLAY AUSGABE
//Datum schreiben
lcd.setCursor(0, 0); // Cursor setzen
char buf3[] = "DD.MMM"; // Tag (zweistellig), Monat (dreistellig als Text)
lcd.print(now.toString(buf3));
//Uhrzeit schreiben
lcd.setCursor(15, 0); // Cursor setzen
char buf1[] = "hh:mm"; // Uhrzeit: Stunden und Minuten (zweistellig)
lcd.print(now.toString(buf1));
//Text schreiben
lcd.setCursor(0, 1); // Cursor setzen
lcd.print("---ERDE-- ---LUFT--"); // Display Ausgabe
//ERDE - DS18B20 Werte schreiben
lcd.setCursor(0, 2); // Cursor setzen: 1. Stelle, 3. Zeile
lcd.write(byte(0)); // Zeichen 0 = Thermometer
lcd.setCursor(1, 2); // Cursor setzen: 2. Stelle, 3. Zeile
lcd.print(String(sensors.getTempCByIndex(0),1) + "\xDF" + "C "); // DS18B20 Temperatur schreiben + Grad Symbol + C + Leerzeichen (alte Zeichen überschreiben)
if (sensors.getTempCByIndex(0) < temp_erde_min) { // Wenn Erd-Temperatur unter Grenzwert, dann
lcd.setCursor(8, 2); // Cursor setzen: 9. Stelle, 3. Zeile
lcd.write(byte(2)); // Zeichen 2 = Pfeil hoch
} else if (sensors.getTempCByIndex(0) >= temp_erde_max) { // Oder wenn Erd-Temperatur über Grenzwert, dann
lcd.setCursor(8, 2); // Cursor setzen: 9. Stelle, 3. Zeile
lcd.write(byte(4)); // Zeichen 4 = Pfeil runter
} else { // Sonst
lcd.setCursor(8, 2); // Cursor setzen: 9. Stelle, 3. Zeile
lcd.print(" "); // Leerzeichen (alte Zeichen überschreiben)
}
//ERDE - Giesomat Werte schreiben
lcd.setCursor(0, 3); // Cursor setzen: 1. Stelle, 4. Zeile
lcd.write(byte(1)); // Zeichen 1 = Tropfen
if (frq >=0 && frq <=99) { // Wenn Frequenz innerhalb, dann
lcd.setCursor(1, 3); // Cursor setzen: 2. Stelle, 4. Zeile
lcd.print(String(frq) + " % "); // Frequenz schreiben
lcd.setCursor(3, 3); // Cursor setzen: 4. Stelle, 4. Zeile
lcd.print(" % "); // Prozentzeichen mit Leerzeichen um alte Zeichen zu überschreiben
} else { // Sonst
lcd.setCursor(1, 3); // Cursor setzen: 2. Stelle, 4. Zeile
lcd.print(String(frq) + " % "); // Frequenz schreiben mit Prozentzeichen
}
if (frq < feuchtigkeit_erde_min && frq > 0) { // Wenn Frequenz unter minimalen Grenzwert UND über Null
lcd.setCursor(7, 3); // Cursor setzen: 9. Stelle, 4. Zeile
lcd.print(" "); // Leerzeichen (alte Zeichen überschreiben)
lcd.setCursor(8, 3); // Cursor setzen: 9. Stelle, 4. Zeile
lcd.write(byte(2)); // Zeichen 2 = Pfeil hoch
} else { // Sonst
lcd.setCursor(8, 3); // Cursor setzen: 9. Stelle, 4. Zeile
lcd.print(" "); // Leerzeichen (alte Zeichen überschreiben)
}
//LUFT - DHT Temperatur Werte schreiben
lcd.setCursor(11, 2); // Cursor setzen: 12. Stelle, 3. Zeile
lcd.write(byte(0)); // Zeichen 0 = Thermometer
lcd.setCursor(12, 2); // Cursor setzen: 13. Stelle, 3. Zeile
lcd.print(String(DHT_Temperatur,1) + "\xDF" + "C "); // DHT Temperatur schreiben + Grad Symbol + C + Leerzeichen (alte Zeichen überschrieben)
//LUFT - DHT Feuchtigkeit Werte schreiben
lcd.setCursor(11, 3); // Cursor setzen: 12. Stelle, 4. Zeile
lcd.write(byte(1)); // Zeichen 1 = Tropfen
if (DHT_Luftfeuchtigkeit >=0 && frq <=99) { // Wenn Luftfeuchtigkeit innerhalb, dann
lcd.setCursor(12, 3); // Cursor setzen: 13. Stelle, 4.Zeile
lcd.print(String(DHT_Luftfeuchtigkeit,0) + " % "); // DHT Luftfeuchtigkeit schreiben + Prozent + Leerzeichen (alte Zeichen überschreiben)
} else { // Sonst
lcd.setCursor(12, 3); // Cursor setzen: 13. Stelle, 4. Zeile
lcd.print(String(DHT_Luftfeuchtigkeit,0) + " %"); // Frequenz schreiben mit Prozentzeichen + Leerzeichen (alte Zeichen überschreiben)
}
if (luefter_steuerung == 0 && DHT_Luftfeuchtigkeit >= luftfeuchte_max) { // Wenn Luftfeuchtigkeit über maximalen Grenzwert
lcd.setCursor(19, 3); // Cursor setzen: 20. Stelle, 4. Zeile
lcd.write(byte(4)); // Zeichen 4 = Pfeil runter
} else { // Sonst
lcd.setCursor(19, 3); // Cursor setzen: 20. Stelle, 4. Zeile
lcd.print(" "); // Leerzeichen (alte Zeichen überschreiben)
}
//LICHT SYMBOL
if(now.hour() >= STUNDE_TAG && now.hour() < STUNDE_NACHT) { // Wenn aktuelle Stunde (Uhrzeit größer gleich Beginn-Tageszeit und kleiner als Beginn Nachtzeit
lcd.setCursor(12, 0); // Cursor setzen: 13. Stelle, 1. Zeile
lcd.write(byte(3)); // Zeichen 3 = Licht an
} else { // Sonst
lcd.setCursor(12, 0); // Cursor setzen: 13. Stelle, 1. Zeile
lcd.print(" "); // Leerzeichen (alte Zeichen überschreiben)
}
//SERIELLE MONITOR AUSGABE
Serial.println("Temperatur: " + String(sensors.getTempCByIndex(0),1) + "°C"); // Monitor Ausgabe Temperatur DS18B20
Serial.println("Bodenfeuchte: " + String(frq) + "%"); // Monitor Ausgabe Bodenfeuchte in Prozent von Giesomat
Serial.println("Lufttemp: " + String(DHT_Temperatur,1) + "°C"); // Monitor Ausgabe Luft-Temperatur DHT22
Serial.println("Luftfeuchte: " + String(DHT_Luftfeuchtigkeit,0) + "%"); // Monitor Ausgabe Luft-Feuchte DHT22
delay(2000); // Pause (2000 = 2 Sekunden)
}


