Hallo,
hab ich da was übersehen? Schreib das mal so
(digitalRead(Niveauschalterminimum) == LOW)
oder
(!digitalRead(Niveauschalterminimum))
In deinem #6 stehts richtig da. :o
Hallo,
hab ich da was übersehen? Schreib das mal so
(digitalRead(Niveauschalterminimum) == LOW)
oder
(!digitalRead(Niveauschalterminimum))
In deinem #6 stehts richtig da. :o
Verstehe ich das richtig: (digitalRead(Niveauschalterminimum) == LOW) und (!digitalRead(Niveauschalterminimum)) das meitn das gleiche?
// PSEUDOCODE / kompiliert
// die boolche Variable ist zu ersetzen durch den Schalterzustand
unsigned long timestore; // Variabler Speicher für 15 Minuten und 15Sekunden
int Pumpe = 9;
bool Niveauschalterminimum =false; // Schalterzustand ist im Normalfall geschlossen ( LOW)
void setup() {
pinMode(Pumpe, OUTPUT);
digitalWrite(Pumpe, LOW);
}
void loop() {
if (Niveauschalterminimum == false ) // wenn der Schalterzusand LOW ist ( Schalter geschlossen)
{
if (digitalRead(Pumpe) && (millis() - timestore > 3000)) // wenn der PumpenPin HIGH (aus) ist und die Zeit abgelaufen
{
digitalWrite(Pumpe, LOW); // Pumpenpin LOW setzen ( an)
timestore = millis(); // Zeit merken
}
if (!digitalRead(Pumpe) && (millis() - timestore > 6000)) // Wenn PumpenPin LOW ist ( an) UND Zeit abgelaufen
{
digitalWrite (Pumpe, HIGH); // Pumpe aus machen
timestore = millis(); // Zeit merken
}
}
}
Ich habe mir an die Seite ein paar Sachen geschrieben um zu verstehen was die Zeilen bedeuten, liege ich da richtig?
LeonardoFiando:
@my_xy_projekt: ...liege ich da richtig?
Es war Dein 100 Post...
Ich habs noch um zwei Kommentare erweitert.
// PSEUDOCODE / kompiliert
// die boolche Variable ist zu ersetzen durch den Schalterzustand
unsigned long timestore; // Variabler Speicher für 15 Minuten und 15Sekunden
int Pumpe = 9;
bool Niveauschalterminimum =false; // Schalterzustand ist im Normalfall geschlossen ( LOW)
void setup() {
pinMode(Pumpe, OUTPUT);
digitalWrite(Pumpe, LOW);
}
void loop() {
if (Niveauschalterminimum == false ) // wenn der Schalterzusand LOW ist ( Schalter geschlossen)
{ // Neu: DANN geht es hier weiter
if (digitalRead(Pumpe) && (millis() - timestore > 3000)) // wenn der PumpenPin HIGH (aus) ist und die Zeit abgelaufen
{
digitalWrite(Pumpe, LOW); // Pumpenpin LOW setzen ( an)
timestore = millis(); // Zeit merken
}
if (!digitalRead(Pumpe) && (millis() - timestore > 6000)) // Wenn PumpenPin LOW ist ( an) UND Zeit abgelaufen
{
digitalWrite (Pumpe, HIGH); // Pumpe aus machen
timestore = millis(); // Zeit merken
}
}
// Neu: SONST würde es hier weiter gehen
}
Und jetzt siehst Du, das Du alles das, was nach der Abfrage der Bedingung steht eigentlich in eine einzelne Funktion "periodicPump" auslagern kannst.
// PSEUDOCODE / kompiliert
// die boolche Variable ist zu ersetzen durch den Schalterzustand
unsigned long timestore; // Variabler Speicher für 15 Minuten und 15Sekunden
int Pumpe = 9;
bool Niveauschalterminimum = false; // Schalterzustand ist im Normalfall geschlossen ( LOW)
void setup() {
pinMode(Pumpe, OUTPUT);
digitalWrite(Pumpe, LOW);
}
void loop() {
if (Niveauschalterminimum == false ) // wenn der Schalterzusand LOW ist ( Schalter geschlossen)
{
periodicPump();
}
// Neu: SONST würde es hier weiter gehen
}
void periodicPump()
{ // Neu: DANN geht es hier weiter
if (digitalRead(Pumpe) && (millis() - timestore > 3000)) // wenn der PumpenPin HIGH (aus) ist und die Zeit abgelaufen
{
digitalWrite(Pumpe, LOW); // Pumpenpin LOW setzen ( an)
timestore = millis(); // Zeit merken
}
if (!digitalRead(Pumpe) && (millis() - timestore > 6000)) // Wenn PumpenPin LOW ist ( an) UND Zeit abgelaufen
{
digitalWrite (Pumpe, HIGH); // Pumpe aus machen
timestore = millis(); // Zeit merken
}
}
Und wenn Du nicht endlich Deinen nicht stimmenden 15 Minuten-Kommentar so anpasst, das er das widergibt, was Du willst, vergraulst mich restlos.
[edit]
Nur als Hinweis: Im setup beginnst Du mit digitalWrite(Pumpe, LOW);
Wenn ich jetzt 1+1 zusammenzähle und da schon einschaltet, flutest Du.
Ich würde es eher vertrocknen lassen....
Und noch ein Hinweis:
Das PeriodicPump geht natürlich nur und ausschliesslich solange, wie der Schalter LOW ist.
Sobald der NiveauSchalter seinen Umschaltpunkt erreicht hat, bleibt das in dem Zustand.
Erreicht der Schalter seinen Zustand - z.B. wegen Kabelbruch oder gezogenem Stecker etc. - nie, hängt das System in ständigem nachpumpen vs. überfluten der Umgebung.
Du merkst langsam, das das doch etwas tricky ist? ![]()
[/edit]
Ja du hast Recht, das Thema das ich hier aufgemacht habe (die Unterbrechung einer Intervallsteuerung durch einen Schalter) ist ein Teil eines größeren Sketches.
Ich dachte mir ich fahre vielleicht besser, wenn ich den Sketch in mehrere kleine Teile aufsplitte, die ich dann später zusammenfüge, ich konnte aber raushören, dass das nicht wirklich sinnvoll ist?
Dieser Sketch funktioniert jetzt so ganz gut, er unterbricht die Intervallsteuerung wenn der Schalter offen ist, und lässt die Intervallsteuerung laufen wenn er geschlossen ist:
unsigned long timestore; // Variabler Speicher für 15 Minuten und 15Sekunden
int PumpenStatus = LOW; // Pumpe is normally on
int Pumpe = 9;
int Niveauschalterminimum = 2;
void setup() {
// put your setup code here, to run once:
pinMode(Pumpe, OUTPUT);
digitalWrite(Pumpe, LOW);
pinMode(Niveauschalterminimum, INPUT_PULLUP);
}
void loop()
// wenn der Nivauschalterminimum geschlossen wird
{
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore > 3000) { // auf die Uhr sehen, ob die 15 Minuten schon rum sind, wenn ja
digitalWrite(Pumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore > 6000) { // auf die Uhr sehen ob die 15 Minuten und 15 Sekunden schon rum sind, wenn ja
digitalWrite (Pumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore = millis();
}
}
} else digitalWrite(Pumpe, HIGH); //Pumpe ausschalten
}
Ich habe ihn gerade in den größeren Sketch eingebunden, der die Zustände inzwischen erfolgreich regelt (wie auf der Skizze) aber die Intervallsteuerung bisher nicht unterbrochen hat wie vorgesehen. Er macht es auch inzwischen nicht:/:
Und hier der große Sketch, in den der Kleinere eingebettet werden soll:
(Teil 1)
// Ezo-Hum-Sensor
//This code was written to be easy to understand.
//Modify this code as you see fit.
//This code will output data to the Arduino serial monitor.
//Type commands into the Arduino serial monitor to control the humidity sensor.
//This code was written in the Arduino 1.8.13 IDE
//An Arduino UNO was used to test this code.
//This code was last tested 8/2020
#include <SoftwareSerial.h> //we have to include the SoftwareSerial library, or else we can't use it
#define rx 4 //define what pin rx is going to be
#define tx 5 //define what pin tx is going to be
SoftwareSerial myserial(rx, tx); //define how the soft serial port is going to work
String inputstring = ""; //a string to hold incoming data from the PC
String sensorstring = ""; //a string to hold the data from the Atlas Scientific product
boolean input_string_complete = false; //have we recived all the data from the PC
boolean sensor_string_complete = false; //have we recived all the data from the Atlas Scientific product
// Pumpensteuerung
unsigned long timestore; // Zeitmerker für Pumpensteuerung
int PumpenStatus = LOW;
// LCD- Display
unsigned long timestore_LCD; // Zeitmerker für LCD Display
// Temperatur Nährlösung
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#define ONE_WIRE_BUS 3 //Data von Temp.Sensor
OneWire oneWire(ONE_WIRE_BUS );
DallasTemperature sensors(&oneWire);
// Notabschaltung Heizstab, Hochdruckpumpe, Umwaelzpumpe und Foerderpumpe
int RelaisHeizstab = 8;
int RelaisHochdruckpumpe = 9;
int RelaisUmwaelzpumpe = 10;
int RelaisFoerderpumpe= 11;
int Niveauschalterminimum = 2;
int Niveauschaltermaximum = 6;
bool Auffuellvorgang = false; // Auffüllvorgang ist nicht aktiviert
// Intervallsteuerung
bool Intervallsteuerung = false; // Intervallsteuerung ist nicht aktiviert
void setup() {
// Ezo-Hum-Sensor
Serial.begin(9600); //set baud rate for the hardware serial port_0 to 9600
myserial.begin(9600); //set baud rate for the software serial port to 9600
inputstring.reserve(10); //set aside some bytes for reciving data from the PC
sensorstring.reserve(30); //set aside some bytes for reciving data from Atlas Scientific product
lcd.init();
lcd.backlight();
sensors.begin();
// Notabschaltung Heizstab und Hochdruckpumpe, Umwaelzpumpe und Foerderpumpe
pinMode(RelaisHeizstab, OUTPUT);
pinMode(RelaisHochdruckpumpe, OUTPUT);
pinMode(RelaisUmwaelzpumpe, OUTPUT);
digitalWrite(RelaisHeizstab, LOW);
digitalWrite(RelaisHochdruckpumpe, LOW);
digitalWrite(RelaisUmwaelzpumpe, LOW);
// Foerderpumpe
pinMode(RelaisFoerderpumpe, OUTPUT);
digitalWrite(RelaisFoerderpumpe, HIGH); // Die Förderpumpe ist normalerweise aus
pinMode(Niveauschalterminimum, INPUT_PULLUP);
pinMode(Niveauschaltermaximum, INPUT_PULLUP);
}
//Ezo-Hum-Sensor
void serialEvent() { //if the hardware serial port_0 recives a char
inputstring = Serial.readStringUntil(13); //read the string until we see a <CR>
input_string_complete = true; //set the flag used to tell if we have recived a completed string from the PC
}
(Teil 2)
void loop() {
//Ezo-Hum-Sensor
if (input_string_complete == true) { //if a string from the PC has been recived in its entirety
myserial.print(inputstring); //send that string to the Atlas Scientific product
myserial.print('\r'); //add a <CR> to the end of the string
inputstring = ""; //clear the string
input_string_complete = false; //reset the flag used to tell if we have recived a completed string from the PC
}
if (myserial.available() > 0) { //if we see that the Atlas Scientific product has sent a character
char inchar = (char)myserial.read(); //get the char we just recived
sensorstring += inchar; //add the char to the var called sensorstring
if (inchar == '\r') { //if the incoming character is a <CR>
sensor_string_complete = true; //set the flag
}
}
if (sensor_string_complete == true) { //if a string from the Atlas Scientific product has been recived in its entirety
if (isdigit(sensorstring[0]) == false) { //if the first character in the string is a digit
Serial.println(sensorstring); //send that string to the PC's serial monitor
}
else //if the first character in the string is NOT a digit
{
print_Humidity_data(); //then call this function
}
sensorstring = ""; //clear the string
sensor_string_complete = false; //reset the flag used to tell if we have recived a completed string from the Atlas Scientific product
}
}
void print_Humidity_data(void) { //this function will pars the string
char sensorstring_array[30]; //we make a char array
char *HUM; //char pointer used in string parsing.
char *TMP; //char pointer used in string parsing.
char *NUL; //char pointer used in string parsing (the sensor outputs some text that we don't need).
char *DEW; //char pointer used in string parsing.
float HUM_float; //float var used to hold the float value of the humidity.
float TMP_float; //float var used to hold the float value of the temperatur.
float DEW_float; //float var used to hold the float value of the dew point.
sensorstring.toCharArray(sensorstring_array, 30); //convert the string to a char array
HUM = strtok(sensorstring_array, ","); //let's pars the array at each comma
TMP = strtok(NULL, ","); //let's pars the array at each comma
NUL = strtok(NULL, ","); //let's pars the array at each comma (the sensor outputs the word "DEW" in the string, we dont need it)
DEW = strtok(NULL, ","); //let's pars the array at each comma
Serial.println(); //this just makes the output easier to read by adding an extra blank line.
Serial.print("HUM:"); //we now print each value we parsed separately.
Serial.print(HUM); //this is the humidity value.
Serial.print("Air TMP:"); //we now print each value we parsed separately.
Serial.print(TMP); //this is the air temperatur value.
Serial.print("DEW:"); //we now print each value we parsed separately.
Serial.print(DEW); //this is the dew point.
Serial.println(); //this just makes the output easier to read by adding an extra blank line.
//uncomment this section if you want to take the values and convert them into floating point number.
/*
HUM_float=atof(HUM);
TMP_float=atof(TMP);
DEW_float=atof(DEW);
*/
// Temperatur Nährlösung LCD
if (millis() - timestore_LCD> 10000 ) // wenn Pausenzeit um
{
lcd.setCursor(0,0); // Werte auf LCD anzeigen
lcd.print("Wurzelzone:");
lcd.setCursor(0,1);
lcd. print ("T:");
lcd.print(TMP);
lcd.print("\337C");
lcd. print (" Hum:");
lcd.print(HUM);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("NL:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
lcd.print(" Dew:");
lcd.print(DEW);
sensors.requestTemperatures();
lcd.setCursor(0,3);
lcd.print("Rasen: ");
lcd.print("T:");
lcd.print(sensors.getTempCByIndex(1));
lcd.print("\337C");
timestore = millis(); // Ausschaltzeit merken
}
// Pumpensteuerung
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore > 3000) { // auf die Uhr sehen, ob die 15 Minuten schon rum sind, wenn ja
digitalWrite(RelaisHochdruckpumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore > 6000) { // auf die Uhr sehen ob die 15 Minuten und 15 Sekunden schon rum sind, wenn ja
digitalWrite (RelaisHochdruckpumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore = millis();
}
}
} else digitalWrite(RelaisHochdruckpumpe, HIGH); //HochdruckPumpe ausschalten
// Notabschaltung Heizstab, Hochdruckpumpe, Umwälzpumpe und Förderpumpe
// Zustand 1
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== LOW) // wenn der Niveauschalterminimum geschlossen ist und der Niveauschaltermaximum geschlossen ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, HIGH); // Foerderpumpe aus
Auffuellvorgang = false; // Auffuellvorgang deaktiviert
Intervallsteuerung = true; // Intervallsteuerung aktiviert
}
// Zustand 2
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== HIGH && Auffuellvorgang == false ) // wenn der Niveauschalterminimum geschlossen ist, der Niveauschaltermaximum offen ist und der Auffuellvorgang deaktiviert ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, HIGH); // Foerderpumpe aus
Intervallsteuerung = true; // Intervallsteuerung aktiviert
}
// Zustand 3
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== HIGH && Auffuellvorgang == true ) // wenn der Niveauschalterminimum geschlossen ist, der Niveauschaltermaximum offen ist und der Auffuellvorgang aktiviert ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, LOW); // Foerderpumpe an
Intervallsteuerung = true; // Intervallsteuerung aktivieren
}
// Zustand 4
if (digitalRead(Niveauschalterminimum) == HIGH && digitalRead(Niveauschaltermaximum)== HIGH)// wenn der Niveauschalterminimum offen ist und der Niveauschaltermaximum offen ist
{
digitalWrite(RelaisHeizstab, HIGH); // Heizstab ausmachen
digitalWrite(RelaisUmwaelzpumpe, HIGH); // Umwälzpumpe ausmachen
digitalWrite(RelaisFoerderpumpe, LOW);
Intervallsteuerung = false; // Intervallsteuerung deaktivieren
Auffuellvorgang = true; // Auffuellvorgang aktivieren
}
}
Und wenn Du nicht endlich Deinen nicht stimmenden 15 Minuten-Kommentar so anpasst, das er das widergibt, was Du willst, vergraulst mich restlos.
Hey es tut mir wirklich sehr Leid aber ich komme einfach nicht so schnell hinterher bei den Sachen, die ihr hier schreibt. Ich bin leider einfach ein ziemlicher Neuling und mir fällt es super schwer zu verstehen, was ihr mir versucht zu vermitteln. Ich kann verstehen, dass Euch das langweilt aber ich strenge mich hier wirklich an es zu verstehen!
Hallo,
wenn du fast den gesamten Code in die Funktion print_Humidity_data steckst, die wiederum nur bedingt aufgerufen wird, dann kann der Rest nicht funktionieren. Trenne die Pumpensteuerung von irgendwelchen Ausgaben. Ausgaben/Anzeigen können Intervallmäßig nebenläufig aufgerufen werden.
Das musst das Projekt strukturieren. Kleine Funktionen schreiben die genau das machen was der Funktionsname aussagt. Bei Intervall mäßigen Aufrufen gezielt lokale Variablen nutzen. Damit kommen sich globale Variablen nicht in die Quere. Das Optimum ist, wenn man in loop nur noch Funktionen aufruft.
LeonardoFiando:
Hey es tut mir wirklich sehr Leid aber ich komme einfach nicht so schnell hinterher bei den Sachen, die ihr hier schreibt.
Leid tun? Häh? Ich schreibs gerne und wiederholt: Für was?
Es ist Deine Entscheidung: Du hast entweder EINE Baustelle oder XXXX Baustellen.
Du kannst gerne EINE Baustelle zu Ende bringen oder KEINE.
Fange mit einem Modul an. Bringe es zu Ende - mache mit dem nächsten weiter.
Ach - da merkst Du das Du beim ersten Mal nicht weiter gedacht hast? - kurzer Änderungskatalog. Fertig.
Allein, wenn ich das sehe:
// Notabschaltung Heizstab, Hochdruckpumpe, Umwälzpumpe und Förderpumpe
// Zustand 1
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum) == LOW) // wenn der Niveauschalterminimum geschlossen ist und der Niveauschaltermaximum geschlossen ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, HIGH); // Foerderpumpe aus
Auffuellvorgang = false; // Auffuellvorgang deaktiviert
Intervallsteuerung = true; // Intervallsteuerung aktiviert
}
ist mir klar, das das niemals! das wird, was das steht oder niemals! das wird was Du beabsichtigst.
Also fange an endlich in Modulen zu denken, die Du so wie Du sie beschreibst auch umsetzt.
Finde den Fehler.
Gute Nacht!
Doc_Arduino war schneller - ich gehe davon aus, das jeder eigentlich genau das selbe aussagen möchte.
Danke für Eure Hilfe!
Ich mache morgen weiter, schlaft gut!![]()
LeonardoFiando:
Hey es tut mir wirklich sehr Leid aber ich komme einfach nicht so schnell hinterher bei den Sachen, die ihr hier schreibt. Ich bin leider einfach ein ziemlicher Neuling und mir fällt es super schwer zu verstehen, was ihr mir versucht zu vermitteln. Ich kann verstehen, dass Euch das langweilt aber ich strenge mich hier wirklich an es zu verstehen!
Kann ich nachvollziehen, keine Sorge. Aktuell bist du gezwungen mehrere Schritte gefühlt gleichzeitig zu machen.
Überlege was unbedingt zusammengehört, dass stecke in eine Funktion.
void heartbeat (const unsigned long interval)
{
static unsigned long lastMillis = 0;
static bool state = LOW;
if (millis() - lastMillis >= interval) {
lastMillis += interval;
state = !state;
digitalWrite(LED_BUILTIN, state);
}
}
wird aufgerufen mit
heartbeat(500);
die Onboard Led D13 blinkt im Sekundentakt. Ohne eine Einzige globale Variable. Okay, einen anderen Pin kann man global definieren und der Funktion als 2. Parameter übergeben. Einmal so als Bsp. was Intervall artig abgearbeitet wird.
Bei my_xy_projekt liegen aktuell die Nerven blank.
Das beruhigt sich wieder. Solche Phasen kenne ich auch. ![]()
Doc_Arduino:
Bei my_xy_projekt liegen aktuell die Nerven blank.
![]()
Das möchte ich nicht mal abstreiten.
[OT]
https://forum.arduino.cc/index.php?topic=723604.msg4865076#msg4865076
Gerne um eine Erklärung bittend. ![]()
Und noch ein Hinweis:
Das PeriodicPump geht natürlich nur und ausschliesslich solange, wie der Schalter LOW ist.
Sobald der NiveauSchalter seinen Umschaltpunkt erreicht hat, bleibt das in dem Zustand.
D.h. sobald der Schalter HIGH wird, bleibt das in diesem Zustand mit der PeriodicPump- Funktion? D.h. wenn der Schalter HIGH wird und die Funktion gerade in diesem Teil ist:
if (digitalRead(Pumpe) && (millis() - timestore > 3000)) // wenn der PumpenPin HIGH (aus) ist und die Zeit abgelaufen
{
digitalWrite(Pumpe, LOW); // Pumpenpin LOW setzen ( an)
timestore = millis(); // Zeit merken
}
dann pumpt sie weiter auch wenn der Schalter HIGH ist? Wenn ja könnte man das nicht auch mit einer Funktion regeln?
Erreicht der Schalter seinen Zustand - z.B. wegen Kabelbruch oder gezogenem Stecker etc. - nie, hängt das System in ständigem nachpumpen vs. überfluten der Umgebung.
Ich habe die Pumpe übrigens so an dem Relais angeschlossen, dass sie ausgeschaltet ist wenn der Stecker gezogen ist.
wenn du fast den gesamten Code in die Funktion print_Humidity_data steckst, die wiederum nur bedingt aufgerufen wird, dann kann der Rest nicht funktionieren.
ich dachte solange ich nicht die vollen vollen Speicher des UNO nutze ist alles in Ordnung. Meinst Du damit ich muss den Code vom Ezo- Hum- Sensor verändern? Ich habe gehofft ich kann ihn einfach vom Hersteller übernehmen, ich wüsste ehrlich gesagt auch garnicht wo ich anfangen sollte da etwas für mein Vorhaben " nicht notwendiges" rauszukürzen.
Trenne die Pumpensteuerung von irgendwelchen Ausgaben
Mit welchen Ausgaben ist die Pumpensteuerung denn gerade verbunden? Meinst du mit "Trennen" die Pumpensteuerung in eine eigene Funktion zu packen wie z.B die PeriodicPump?
Ausgaben/Anzeigen können Intervallmäßig nebenläufig aufgerufen werden.
Kannst Du mir dafür bitte ein Beispiel geben? Darunter kann ich mir leider nichts vorstellen:/.
Das musst das Projekt strukturieren. Kleine Funktionen schreiben die genau das machen was der Funktionsname aussagt. Bei Intervall mäßigen Aufrufen gezielt lokale Variablen nutzen.
Das habe ich versucht. Ich habe es so strukturiert:
Das habe ich dann in den void setup und void loop Teil einsortiert. Ich weiß, dass ich das wahrscheinlich total laienhaft und falsch gemacht habe;). In welche Funktionen und welche Funktionsnamen würdet Ihr das Projekt strukturieren?
Damit kommen sich globale Variablen nicht in die Quere. Das Optimum ist, wenn man in loop nur noch Funktionen aufruft.
Globale Variablen können von jeder Funktion in einem Programm gesehen werden, lokale Variablen sind nur innerhalb der Funktion sichtbar, in der sie deklariert worden sind. Der Einsatz lokaler Variablen stellt sicher, dass nur eine Funktion Zugriff auf ihre eigenen Variablen hat. Dadurch kann diese Funktion nicht Variablen ändern, die von einer anderen Funktion verwendet werden
aus Arduino das umfassende Handbuch von Claus Kühnel (S.220 und 2021)
Das heißt alle Variablen, die ich in einer neuen Funktion z.B void PeriodicPump deklariere sind dann nur innerhalb dieser Funktion gültig
void heartbeat (const unsigned long interval)
{
static unsigned long lastMillis = 0;
static bool state = LOW;
if (millis() - lastMillis >= interval) {
lastMillis += interval;
state = !state;
digitalWrite(LED_BUILTIN, state);
}
}
und hier gibt es keinen void loop Teil mehr vor dem man die ganzen Variablen deklarieren muss wie bei deinem Beispiel hier drüber, lieber Doc_Arduino...
Hier ist nochmal der Code von dessen Strukturierung ich eben sprach (habe ihn vor meinem letzten Beitrag nochmal ein kleines bisschen umstrukturiert:
(Teil 1)
// Ezo-Hum-Sensor
//This code was written to be easy to understand.
//Modify this code as you see fit.
//This code will output data to the Arduino serial monitor.
//Type commands into the Arduino serial monitor to control the humidity sensor.
//This code was written in the Arduino 1.8.13 IDE
//An Arduino UNO was used to test this code.
//This code was last tested 8/2020
#include <SoftwareSerial.h> //we have to include the SoftwareSerial library, or else we can't use it
#define rx 4 //define what pin rx is going to be
#define tx 5 //define what pin tx is going to be
SoftwareSerial myserial(rx, tx); //define how the soft serial port is going to work
String inputstring = ""; //a string to hold incoming data from the PC
String sensorstring = ""; //a string to hold the data from the Atlas Scientific product
boolean input_string_complete = false; //have we recived all the data from the PC
boolean sensor_string_complete = false; //have we recived all the data from the Atlas Scientific product
// Pumpensteuerung
unsigned long timestore; // Zeitmerker für Pumpensteuerung
int PumpenStatus = LOW;
bool Intervallsteuerung = false; // Intervallsteuerung ist nicht aktiviert
// LCD- Display
unsigned long timestore_LCD; // Zeitmerker für LCD Display
// Temperatur Nährlösung
#include <DallasTemperature.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#define ONE_WIRE_BUS 3 //Data von Temp.Sensor
OneWire oneWire(ONE_WIRE_BUS );
DallasTemperature sensors(&oneWire);
// Steuerung von Heizstab, Hochdruckpumpe, Umwaelzpumpe und Foerderpumpe
int RelaisHeizstab = 8;
int RelaisHochdruckpumpe = 9;
int RelaisUmwaelzpumpe = 10;
int RelaisFoerderpumpe= 11;
int Niveauschalterminimum = 2;
int Niveauschaltermaximum = 6;
bool Auffuellvorgang = false; // Auffüllvorgang ist nicht aktiviert
void setup() {
// Ezo-Hum-Sensor
Serial.begin(9600); //set baud rate for the hardware serial port_0 to 9600
myserial.begin(9600); //set baud rate for the software serial port to 9600
inputstring.reserve(10); //set aside some bytes for reciving data from the PC
sensorstring.reserve(30); //set aside some bytes for reciving data from Atlas Scientific product
lcd.init();
lcd.backlight();
sensors.begin();
// Notabschaltung Heizstab, Hochdruckpumpe, Umwaelzpumpe und Foerderpumpe
pinMode(RelaisHeizstab, OUTPUT);
pinMode(RelaisHochdruckpumpe, OUTPUT);
pinMode(RelaisUmwaelzpumpe, OUTPUT);
pinMode(RelaisFoerderpumpe, OUTPUT);
pinMode(Niveauschalterminimum, INPUT_PULLUP);
pinMode(Niveauschaltermaximum, INPUT_PULLUP);
digitalWrite(RelaisHeizstab, LOW);
digitalWrite(RelaisHochdruckpumpe, LOW);
digitalWrite(RelaisUmwaelzpumpe, LOW);
digitalWrite(RelaisFoerderpumpe, HIGH); // Die Förderpumpe ist normalerweise aus
}
//Ezo-Hum-Sensor
void serialEvent() { //if the hardware serial port_0 recives a char
inputstring = Serial.readStringUntil(13); //read the string until we see a <CR>
input_string_complete = true; //set the flag used to tell if we have recived a completed string from the PC
}
(Teil 2)
void loop() {
//Ezo-Hum-Sensor
if (input_string_complete == true) { //if a string from the PC has been recived in its entirety
myserial.print(inputstring); //send that string to the Atlas Scientific product
myserial.print('\r'); //add a <CR> to the end of the string
inputstring = ""; //clear the string
input_string_complete = false; //reset the flag used to tell if we have recived a completed string from the PC
}
if (myserial.available() > 0) { //if we see that the Atlas Scientific product has sent a character
char inchar = (char)myserial.read(); //get the char we just recived
sensorstring += inchar; //add the char to the var called sensorstring
if (inchar == '\r') { //if the incoming character is a <CR>
sensor_string_complete = true; //set the flag
}
}
if (sensor_string_complete == true) { //if a string from the Atlas Scientific product has been recived in its entirety
if (isdigit(sensorstring[0]) == false) { //if the first character in the string is a digit
Serial.println(sensorstring); //send that string to the PC's serial monitor
}
else //if the first character in the string is NOT a digit
{
print_Humidity_data(); //then call this function
}
sensorstring = ""; //clear the string
sensor_string_complete = false; //reset the flag used to tell if we have recived a completed string from the Atlas Scientific product
}
}
void print_Humidity_data(void) { //this function will pars the string
char sensorstring_array[30]; //we make a char array
char *HUM; //char pointer used in string parsing.
char *TMP; //char pointer used in string parsing.
char *NUL; //char pointer used in string parsing (the sensor outputs some text that we don't need).
char *DEW; //char pointer used in string parsing.
float HUM_float; //float var used to hold the float value of the humidity.
float TMP_float; //float var used to hold the float value of the temperatur.
float DEW_float; //float var used to hold the float value of the dew point.
sensorstring.toCharArray(sensorstring_array, 30); //convert the string to a char array
HUM = strtok(sensorstring_array, ","); //let's pars the array at each comma
TMP = strtok(NULL, ","); //let's pars the array at each comma
NUL = strtok(NULL, ","); //let's pars the array at each comma (the sensor outputs the word "DEW" in the string, we dont need it)
DEW = strtok(NULL, ","); //let's pars the array at each comma
Serial.println(); //this just makes the output easier to read by adding an extra blank line.
Serial.print("HUM:"); //we now print each value we parsed separately.
Serial.print(HUM); //this is the humidity value.
Serial.print("Air TMP:"); //we now print each value we parsed separately.
Serial.print(TMP); //this is the air temperatur value.
Serial.print("DEW:"); //we now print each value we parsed separately.
Serial.print(DEW); //this is the dew point.
Serial.println(); //this just makes the output easier to read by adding an extra blank line.
//uncomment this section if you want to take the values and convert them into floating point number.
/*
HUM_float=atof(HUM);
TMP_float=atof(TMP);
DEW_float=atof(DEW);
*/
// LCD - Display
if (millis() - timestore_LCD> 10000 ) // wenn Pausenzeit um
{
lcd.setCursor(0,0); // Werte auf LCD anzeigen
lcd.print("Wurzelzone:");
lcd.setCursor(0,1);
lcd. print ("T:");
lcd.print(TMP);
lcd.print("\337C");
lcd. print (" Hum:");
lcd.print(HUM);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("NL:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
lcd.print(" Dew:");
lcd.print(DEW);
sensors.requestTemperatures();
lcd.setCursor(0,3);
lcd.print("Rasen: ");
lcd.print("T:");
lcd.print(sensors.getTempCByIndex(1));
lcd.print("\337C");
timestore = millis(); // Ausschaltzeit merken
}
// Pumpensteuerung
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore > 3000) { // auf die Uhr sehen, ob die 15 Minuten schon rum sind, wenn ja
digitalWrite(RelaisHochdruckpumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore > 6000) { // auf die Uhr sehen ob die 15 Minuten und 15 Sekunden schon rum sind, wenn ja
digitalWrite (RelaisHochdruckpumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore = millis();
}
}
} else digitalWrite(RelaisHochdruckpumpe, HIGH); //HochdruckPumpe ausschalten
// Steuerung von Heizstab, Umwälzpumpe und Förderpumpe
// Zustand 1
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== LOW) // wenn der Niveauschalterminimum geschlossen ist und der Niveauschaltermaximum geschlossen ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, HIGH); // Foerderpumpe aus
Auffuellvorgang = false; // Auffuellvorgang deaktiviert
Intervallsteuerung = true; // Intervallsteuerung aktiviert
}
// Zustand 2
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== HIGH && Auffuellvorgang == false ) // wenn der Niveauschalterminimum geschlossen ist, der Niveauschaltermaximum offen ist und der Auffuellvorgang deaktiviert ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, HIGH); // Foerderpumpe aus
Intervallsteuerung = true; // Intervallsteuerung aktiviert
}
// Zustand 3
if (digitalRead(Niveauschalterminimum) == LOW && digitalRead(Niveauschaltermaximum)== HIGH && Auffuellvorgang == true ) // wenn der Niveauschalterminimum geschlossen ist, der Niveauschaltermaximum offen ist und der Auffuellvorgang aktiviert ist
{
digitalWrite(RelaisHeizstab, LOW); // Heizstab an
digitalWrite(RelaisUmwaelzpumpe, LOW); // Umwälzpumpe an
digitalWrite(RelaisFoerderpumpe, LOW); // Foerderpumpe an
Intervallsteuerung = true; // Intervallsteuerung aktivieren
}
// Zustand 4
if (digitalRead(Niveauschalterminimum) == HIGH && digitalRead(Niveauschaltermaximum)== HIGH)// wenn der Niveauschalterminimum offen ist und der Niveauschaltermaximum offen ist
{
digitalWrite(RelaisHeizstab, HIGH); // Heizstab ausmachen
digitalWrite(RelaisUmwaelzpumpe, HIGH); // Umwälzpumpe ausmachen
digitalWrite(RelaisFoerderpumpe, LOW);
Intervallsteuerung = false; // Intervallsteuerung deaktivieren
Auffuellvorgang = true; // Auffuellvorgang aktivieren
}
}
Es gibt noch eine andere Möglichkeit wie ich das Problem lösen kann:
Ich habe die Pumpensteuerung gerade allein auf einem Mikrocontroller mit diesem Sketch:
//Festlegen der Variablen
int PUMPE= 8;
void setup() {
// initialize digital pin PUMPE as an output.
pinMode(PUMPE, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(PUMPE, LOW); // turn the PUMPE on (HIGH is the voltage level)
delay(15000); // 15 Sekunden warten
digitalWrite(PUMPE, HIGH); // turn the PUMPE off by making the voltage LOW
delay(300000); // 5 Minuten warten
}
Ich könnte in meinem aktuellen Sketch auch einfach mit dem RelaisHochdruckpumpe diesen Mikrocontroller anschalten, der dann die Pumpensteuerung übernimmt. Ich weiß, das ist keine elegante Lösung aber sie funktionert auf jeden Fall:D
Mir ist eben ein Fehler aufgefallen der sehr gravierend war:
// Temperatur Nährlösung LCD
if (millis() - timestore_LCD> 10000 ) // wenn Pausenzeit um
{
lcd.setCursor(0,0); // Werte auf LCD anzeigen
lcd.print("Wurzelzone:");
lcd.setCursor(0,1);
lcd. print("T:");
lcd.print(TMP);
lcd.print("\337C");
lcd. print(" Hum:");
lcd.print(HUM);
lcd.print("%");
lcd.setCursor(0,2);
lcd.print("NL:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
lcd.print(" Dew:");
lcd.print(DEW);
sensors.requestTemperatures();
lcd.setCursor(0,3);
lcd.print("Rasen: ");
lcd.print("T:");
lcd.print(sensors.getTempCByIndex(1));
lcd.print("\337C");
timestore = millis(); // Ausschaltzeit merken
}
// Pumpensteuerung
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore > 3000) { // auf die Uhr sehen, ob die 15 Minuten schon rum sind, wenn ja
digitalWrite(RelaisHochdruckpumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore > 6000) { // auf die Uhr sehen ob die 15 Minuten und 15 Sekunden schon rum sind, wenn ja
digitalWrite (RelaisHochdruckpumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore = millis();
}
}
} else digitalWrite(RelaisHochdruckpumpe, HIGH); //HochdruckPumpe ausschalten
Ich habe das jetzt so korrigiert:
// Pumpensteuerung
unsigned long timestore_Pumpensteuerung; // Zeitmerker für Pumpensteuerung
int PumpenStatus = LOW;
// LCD- Display
unsigned long timestore_LCD; // Zeitmerker für LCD Display
void loop(){ // LCD - Display
if (millis() - timestore_LCD > 5000 ) // wenn Pausenzeit um
{
lcd.setCursor(0, 0); // Werte auf LCD anzeigen
lcd.print("Wurzelzone:");
lcd.setCursor(0, 1);
lcd. print("T:");
lcd.print(TMP);
lcd.print("\337C");
lcd. print(" Hum:");
lcd.print(HUM);
lcd.print("%");
lcd.setCursor(0, 2);
lcd.print("NL:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
lcd.print(" Dew:");
lcd.print(DEW);
sensors.requestTemperatures();
lcd.setCursor(0, 3);
lcd.print("Rasen: ");
lcd.print("T:");
lcd.print(sensors.getTempCByIndex(1));
lcd.print("\337C");
timestore_LCD = millis(); // Ausschaltzeit merken
}
// Pumpensteuerung
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore_Pumpensteuerung > 1000) { // auf die Uhr sehen, ob die Einschaltzeit schon um ist
digitalWrite(RelaisHochdruckpumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore_Pumpensteuerung = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore_Pumpensteuerung > 6000) { // auf die Uhr sehen ob die Pausenzeit schon rum sind, wenn ja
digitalWrite (RelaisHochdruckpumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore_Pumpensteuerung = millis();
}
}
} else digitalWrite(RelaisHochdruckpumpe, HIGH); //HochdruckPumpe ausschalten
}
und dann hat auch alles wie gewollt funktionert. Wenn der Schalter LOW wird geht die Pumpensteuerung aus. Dann habe ich die Werte für die Einschaltzeit und die Pausenzeit verändert, so wie es schlussendlich sein soll ( hatte die letzten Werte nur probehalber eingegeben )und dann hat es wieder nicht wie gewollt funktionert. Das verstehe ich jetzt schon wieder garnicht, kann mir das jemand erklären?
// Pumpensteuerung
unsigned long timestore_Pumpensteuerung; // Zeitmerker für Pumpensteuerung
int PumpenStatus = LOW;
// LCD- Display
unsigned long timestore_LCD; // Zeitmerker für LCD Display
void loop(){
// LCD - Display
if (millis() - timestore_LCD > 5000 ) // wenn Pausenzeit um
{
lcd.setCursor(0, 0); // Werte auf LCD anzeigen
lcd.print("Wurzelzone:");
lcd.setCursor(0, 1);
lcd. print ("T:");
lcd.print(TMP);
lcd.print("\337C");
lcd. print (" Hum:");
lcd.print(HUM);
lcd.print("%");
lcd.setCursor(0, 2);
lcd.print("NL:");
lcd.print(sensors.getTempCByIndex(0));
lcd.print("\337C");
lcd.print(" Dew:");
lcd.print(DEW);
sensors.requestTemperatures();
lcd.setCursor(0, 3);
lcd.print("Rasen: ");
lcd.print("T:");
lcd.print(sensors.getTempCByIndex(1));
lcd.print("\337C");
timestore_LCD = millis(); // Ausschaltzeit merken
}
// Pumpensteuerung
if (digitalRead(Niveauschalterminimum) == LOW) { // wenn der Niveauschaltermimum geschlossen ist
if (PumpenStatus == LOW) { // wenn der Pumpenstatus aus ist // Doc_Arduino: Die erste millis Abfrage gewinnt immer!!! aber warum läuft das Programm weiter wenn die Bedingung garnicht erfüllt ist?
if (millis() - timestore_Pumpensteuerung > 15000) { // auf die Uhr sehen, ob die Einschaltzeit schon um ist
digitalWrite(RelaisHochdruckpumpe, LOW); // Pumpe einschalten
PumpenStatus = HIGH; // notieren, dass die Pumpe angeschaltet ist
timestore_Pumpensteuerung = millis();
}
} else { // wenn die Pumpe an ist
if (millis() - timestore_Pumpensteuerung > 900000) { // auf die Uhr sehen ob die Pausenzeit schon rum sind, wenn ja
digitalWrite (RelaisHochdruckpumpe, HIGH); // Pumpe ausschalten
PumpenStatus = LOW; // notieren, der Pumpenstatus an ist
timestore_Pumpensteuerung = millis();
}
}
} else digitalWrite(RelaisHochdruckpumpe, HIGH); //HochdruckPumpe ausschalten
}
und jetzt verstehe ich: um so etwas zu verhindern empfiehlt sich das Arbeiten mit mehreren Funktionen, die im loop- Teil abgerufen werden, dann kommt es nicht dazu, dass sich aus Versehen mehrere Bereiche die selben Variablen teilen. Noch eine Frage: laufen die millis() in jeder Funktion seperat ab oder laufen sie für alle Funktionen gleich ab?
LG Leonardo