Hallo zusammen,
Es ist eine Weile her seit ich dieses Thema eröffnet habe. Nun habe ich die komplette Hardware zusammen und starte langsam mit dem Programm. Ich werde euch auch, wenn dies hier möglich ist, Bilder hochladen nachdem ich meine Arbeit abgegeben habe.
Nun habe ich Heute mit der Temperaturregelung begonnen und stehe schon an:
Mit dem Temperatursensor erfasse ich die Wassertemperatur. Mit einem Taster stelle ich die Temperatur zwischen 15 und 35 °C ein. Jetzt möchte ich bei der LCD Anzeige den Text: "Temperatur OK" solange die Temperatur +/- 2°C um die Solltemperatur ist. Wenn höher als 2°C ab Solltemperatur muss Ralais Kühlung einschalten und so lange laufen bis Punkt Solltemperatur erreicht ist. Während dem Betrieb steht statt "Temperatur OK" -> "Kuehlung EIN".
Und das ganze umgekehrt auch beim Heizen. Fällt die Temp mehr als 2°C unter Solltemperatur soll das Relais Heizung einschalten und dementsprechend die Anzeige auf HEIZUNG EIN wechseln. Sobald Punkt Solltemperatur erreicht ist soll diese ausschalten und die Anzeige wechselt auf "Temperatur OK".
Das Programm habe ich ungefähr hingekriegt, nur schaltet mal das falsche Relais ein (Verkabelung geprüft) und stellt danach bei Erreichen der Solltemp. nicht ab und das zweite relais zieht schon usw. einwenig chaotisch. Die Anzeige funktioniert mehr oder weniger: Wenn Temp. OK gestanden ist und auf Heizung EIN wechselt, sieht man immernoch die restlichen Buchstaben der vorherigen Anzeige. Somit geht diese nicht weg sondern wird einfach überschrieben.
Sensoren, LCD etc im Programm ersichtlich. Ich hoffe jemand kann mir helfen. (Im Programm der letzte Abschnitt mit den If's und Else)
/*
Titel: Temperaturregelung Aquarium
Datum: 27.06.2021
Autor: ribaribi
Hardware: Temperatursensor, 2x Relais, LCD Display, Taster, Arduino Mega
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define DS18B20_DATA 2 //Daten-Pin für TemperaturSensor DS18B20
#define Heizung_PIN 7 //Pin für Relais Heizung
#define Kuehlung_PIN 6 //Pin für Relais Kühlung
#define Knopf_PIN 3 //Pin für den Tasterknopf zur Soll-Temp. Einstellung
#define start 20 //Start/Soll Temperatur
#define min 15 //Temperatur minimum
#define max 35 //Temperatur maximum
//=============================================================================
OneWire oneWire(DS18B20_DATA);
DallasTemperature sensors(&oneWire);
int knopf;
int soll_Temp;
void setup(){
lcd.init();
lcd.backlight();
sensors.begin();
pinMode(Heizung_PIN, OUTPUT);
pinMode(Kuehlung_PIN, OUTPUT);
digitalWrite(Heizung_PIN,true);
digitalWrite(Kuehlung_PIN,true);
pinMode(Knopf_PIN,INPUT_PULLUP);
}
void loop(){
if (soll_Temp == 0){
soll_Temp = start;
}
knopf = digitalRead(Knopf_PIN);
if (knopf == 0){
soll_Temp = soll_Temp + 1;
}
if (soll_Temp > max){
soll_Temp = min;
}
sensors.requestTemperatures();
float temp (sensors.getTempCByIndex(0));
lcd.setCursor(0,0);
lcd.print("Temperatur Aquarium");
lcd.setCursor(0,1);
lcd.print("Aktuell: ");
lcd.print(String(temp,1));
lcd.print("\337C ");
lcd.setCursor(0,2);
lcd.print("Soll: ");
lcd.print(soll_Temp);
lcd.print(".0\337C ");
if (temp <= soll_Temp -2){
lcd.setCursor(0,3);
lcd.print("Heizung EIN");
digitalWrite(Heizung_PIN,true);
}else{
if (temp >= soll_Temp){
lcd.setCursor(0,3);
lcd.print("Temperatur OK");
digitalWrite(Heizung_PIN,false);
}
}
if (temp >= soll_Temp +2){
lcd.setCursor(0,3);
lcd.print("Kuehlung EIN");
digitalWrite(Kuehlung_PIN,true);
}else{
if (temp <= soll_Temp){
lcd.setCursor(0,3);
lcd.print("Temperatur OK");
digitalWrite(Kuehlung_PIN,false);
}
}
delay(500);
}
das ist klar. du setzt ja nur setCursor und schreibst dann wieder ab dieser Position.
Entweder überschreibst du zunächst mit 16 Leerschritten, machst dann wieder ein setCursor und schreibst dann erst, oder
du fügst deinen Texten einfach ausreichen Leerschritten hinzu sodass sie eventuelle andere alte Zeichen "löschen"
Du musst, wenn Du das KühlungsRelais einschaltest, dafür sorgen das Du das Heizungsrelais ausschaltest und das Ganze auch anders rum. - Stichwort verriegeln.
Ansonsten kann es Dir passieren, das Du beides am Laufen hast.
Und dann hast noch nen Pfund:
Wenn
if (temp <= soll_Temp - 2) {
true ist und Du eigentlich heizen willst, dann sagt Dir:
//Kuehlung
if (temp <= soll_Temp) {
lcd.print("Temperatur OK");
Merkst was?
Also musst Du Dir merken, was Du als letztes gemacht hast. Oder Du lagerst die Anzeige aus.
Also, ich habe es jetzt versucht. Die Relais schalten bei erreichen der Soll-Temp nicht aus sondern erst bei überschreiten von 2° aber gleichzeitig schaltet das andere relais an..... zum Teil sind auch beide gezogen. Die idee ist das diese bei 2+ oder 2- einschalten aber bei genau Solltemp. ausschalten. hmm.... versuche es weiter
Mache dir ein konkretes Zahlenbeispiel und schreibe die Zahlen auf ein Blatt Papier. Schreibe über die Zahlen die Variablennamen und dann anaylsiere was die Bedingungen mit den konkreten Zahlen ergibt
Solltemperatur temp_soll 28°C Ist-Temperatur temp_ist 30°C
Wenn die Abweichung +2°C erreicht dann Kühlung einschalten.
wenn temp_ist - temp_soll >= 2 ==> Kühlung ein
Solltemperatur temp_soll 28°C Ist-Temperatur temp_ist 26°C
Wenn die Abweichung -2°C erreicht dann Heizung einschalten.
wenn temp_ist - temp_soll <= -2 ==> Heizung ein.
Du kannst stundenlang jedes einzelne mal "auf die Schnelle" eine kleine Programmänderung machen die 30 Sekunden dauert nur um erneut festzustellen ne so funktioniert es auch nicht.
Oder du kannst dir 5-10 Minuten Zeit nehmen seriellen Debug-output dazu zu programmieren der Klartext redet was wirklich passiert und dadurch in 20 Minuten herausfinden wie es programmiert werden muss.
Weißt du wie man seriellen output programmiert?
vgs
Hallo Stefan,
danke für deine Nachricht. Leider kann ich mit "seriellen Debug-output" noch nichts anfangen. Ich müsste mich da erstmal schlau machen. So wie der Code nun steht müsste es funktionieren. Ich verstehe nur nicht weshalb die Relais bei Soll- Erreichen nicht abschalten.
Die Frage nach dem wissen was serieller Debug-output ist diente einfach dazu zu klären ob du es weißt oder nicht. Du kennst es noch nicht also erkläre ich es.
Und am besten an deiner aktuellen Code-Version. Das heißt poste mal deine aktuellste Code-Version dann baue ich ein Beispiel ein das es erklärt und dann kannst du das Programm komplet damit ausstatten und herausfinden woran es liegt.
nur so weist du, dass die Bedingung erfüllt ist und der Controller die zwei nachfolgenden Zeilen anspringt.
nicht vergessen, dass du auch ein Serial.begin(115200); im setup() brauchst.
Derartige Debug-Ausgaben helfen eigentlich meistens, den Ablauf zu verfolgen und Logikfehler zu erkennen.
Der nächste Schritt der Fehlersuche liegt fast auf der Hand:
Du kannst die die zwei Variablen ausgeben:
Das geht nicht, denn es ist nur 1 Relais HIGH.
Es gibt keinen Zeitpunkt, an dem beide Relais HIGH gehen.
ODER(!)
Und das ist eher die Vermutung, das Dein Code in #21 schon nicht das darstellt, was DU hast.
Wenn nämlich die Relais LOW-Aktiv sind (und das sind 99,99% aller Relaismodule) genau dann passiert das.
Das erklärt dann auch die Diskrepanz zwischen Setup
und
Bedingung:
Kannst Du testen. Tausche in meinem Code
alt: false neu: true
alt: true neu: false
Damit man bei low-aktiven Relais sich nicht immer die Invertierung dazu denken muss
würde ich ich mir zwei Konstanten definieren die dann als Namen das haben was tatsächlich passiert
/*
Titel: Temperaturregelung Aquarium
Datum: 29.06.2021
Autor: ribaribi
Hardware: Temperatursensor, 2x Relais, LCD Display, Taster, Arduino Mega
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#define DS18B20_DATA 2 //Daten-Pin für TemperaturSensor DS18B20
#define Heizung_PIN 7 //Pin für Relais Heizung
#define Kuehlung_PIN 6 //Pin für Relais Kühlung
#define Knopf_PIN 3 //Pin für den Tasterknopf zur Soll-Temp. Einstellung
#define start 20 //Start/Soll Temperatur
#define min 15 //Temperatur minimum
#define max 35 //Temperatur maximum
// angenommen wenn man den IO-pin LOW schaltet wird das Relais
//so geschaltet das der Kontakt geschlossen = HEIZUNG EINgeschaltet ist
#define EIN LOW
#define AUS HIGH
OneWire oneWire(DS18B20_DATA);
DallasTemperature sensors(&oneWire);
int knopf;
int soll_Temp;
void setup() {
Serial.begin(115200); // im seriellen Monitor als Baudrate auch 115200 einstellen
Serial.println( F("Setup-Start") );
lcd.init();
lcd.backlight();
sensors.begin();
pinMode(Heizung_PIN, OUTPUT);
pinMode(Kuehlung_PIN, OUTPUT);
digitalWrite(Heizung_PIN, AUS);
digitalWrite(Kuehlung_PIN, AUS);
pinMode(Knopf_PIN, INPUT_PULLUP);
}
void loop() {
if (soll_Temp == 0) {
soll_Temp = start;
}
knopf = digitalRead(Knopf_PIN);
if (knopf == 0) {
soll_Temp = soll_Temp + 1;
}
if (soll_Temp > max) {
soll_Temp = min;
}
sensors.requestTemperatures();
float temp (sensors.getTempCByIndex(0));
lcd.setCursor(0, 0);
lcd.print("Temperatur Aquarium");
lcd.setCursor(0, 1);
lcd.print("Aktuell: ");
lcd.print(String(temp, 1));
lcd.print("\337C ");
lcd.setCursor(0, 2);
lcd.print("Soll: ");
lcd.print(soll_Temp);
lcd.print(".0\337C ");
Serial.print( F("temp=") ); // name der Variable auasgeben
Serial.print(temp); // Inhalt der Variable ausgeben
Serial.print( F(" soll_Temp - 2") );
Serial.print(soll_Temp - 2); // Ergebnis der Berechnung soll_Temp - 2 ausgeben
Serial.println(); // println print-line in die nächste Zeile springen
Serial.print( F("temp=") ); // name der Variable auasgeben
Serial.print(temp); // Inhalt der Variable ausgeben
Serial.print( F(" soll_Temp + 2") );
Serial.print(soll_Temp + 2); // Ergebnis der Berechnung soll_Temp + 2 ausgeben
Serial.println(); // println print-line in die nächste Zeile springen
if (temp <= soll_Temp - 2) {
Serial.println( F("Bedingung (temp <= soll_Temp - 2) ist TRUE") );
Serial.println( F("Kühlung aus, Heizung ein") );
lcd.setCursor(0, 3);
lcd.print("Heizung EIN");
digitalWrite(Heizung_PIN, EIN);
digitalWrite(Kuehlung_PIN, AUS);
}
if (temp >= soll_Temp + 2) {
Serial.println( F("Bedingung (temp >= soll_Temp + 2) ist TRUE") );
Serial.println( F("Kühlung ein, Heizung aus") );
lcd.setCursor(0, 3);
lcd.print("Kuehlung EIN");
digitalWrite(Kuehlung_PIN, EIN);
digitalWrite(Heizung_PIN, AUS);
}
if (temp == soll_Temp) {
Serial.println( F("Bedingung (temp == soll_Temp) ist TRUE") );
Serial.println( F("Heizung und Kühlung aus") );
digitalWrite(Heizung_PIN, AUS);
digitalWrite(Kuehlung_PIN, AUS);
}
if (!digitalRead(Heizung_PIN) && !digitalRead(Kuehlung_PIN))
{
Serial.println( F("Bedingung (!digitalRead(Heizung_PIN) && !digitalRead(Kuehlung_PIN) ist TRUE") );
lcd.setCursor(0, 3);
lcd.print("Temperatur OK ");
}
delay(500);
}
Und gaaanz am Anfang wenn man ein Bauteil noch nicht kennt lernt man das Bauteil erst einmal durch ein Testprogramm kennen. Im Falle des Relais sieht das dann ungefähr so aus
#define Heizung_PIN 7 //Pin für Relais Heizung
int meinZaehler = 0;
void setup() {
Serial.begin(115200); // im seriellen Monitor als Baudrate auch 115200 einstellen
Serial.println( F("Setup-Start") );
pinMode(Heizung_PIN, OUTPUT);
digitalWrite(Heizung_PIN, LOW);
Serial.println( F("Heizung_PIN LOW geschaltet") );
}
void loop() {
meinZaehler++;
if (meinZaehler == 10) {
digitalWrite(Heizung_PIN, HIGH);
Serial.println( F("Heizung_PIN HIGH geschaltet") );
}
if (meinZaehler == 20) {
meinZaehler = 0;
digitalWrite(Heizung_PIN, LOW);
Serial.println( F("Heizung_PIN LOW geschaltet") );
}
if (digitalRead(Heizung_PIN == LOW) ) {
Serial.println( F("Heizung_PIN ist LOW was macht das Relais?") );
}
if (digitalRead(Heizung_PIN == HIGH) ) {
Serial.println( F("Heizung_PIN ist HIGH was macht das Relais?") );
}
delay(1000);
}
Das Programm schaltet alle 10 Sekunden den IO-pin auf LOW dann auch HIGH, auf LOW usw. usw. usf.
So ein Programm schreiben dauert auch 15 Minuten. Aber jetzt vergleiche:
Wie wie viele Stunden hast du herumprobiert "eigentlich müsste doch ...."
Was lernt man daraus?
Wenn es besonders schnelllll gehen soll geht es in Wirklichkeit besonders laaaaaaangsaaaaam.