Komme im Code nicht weiter - 2 Funktionen beeinflussen sich

Hallo, ich stecke immer noch fest, in meinen Funktionen. Ich habe nun schon alles hin und her verschoben aber es will nicht funktionieren. Mein Problem ist das ich die Pumpe einschalte und gleichzeitig auch das Magnetventil am Spülkasten öffnen will, das geht , aber es darf dann nicht auch das Magnetventil für den Blumenkasten öffnen. Also es soll immr nur einer von beiden geöffnet sein, wenn die Pumpe AN ist. Mit Vorrang für den Spülkasten! Sollte der Blumenkasten gerade geöffnet sein, dann "abbruch" Ventil ZU und Spülkasten Ventil AUF. Das ganze wäre so noch irgendwie einfach aber ich möchte mit millis() gewisse Einschaltzeiten und Sicherheitsabschaltungen machen. Die beiden Funktionen werden mit unterschiedlichen Parametern aufgerufen und dann mit unterschiedlichen Zeiten gesteuert. Jetzt geht alles irgendwie durcheinander. Alle werden auf HIGH gesetzt aber nicht wieder auf LOW. Ich fische irgendwie im trüben und mache es nur schlimmer =(

Ist es vielleicht besser ich setzte alles in eine Funktion? Oder gibt es eine andere Möglichkeit das ganze in 2 Funktionen zu lassen?
Ich hoffe, das ich es so verständlich geschrieben habe. Der gesamte Code ist im Anhang.

MfG Marco

void wcspuelung()  // Steuerung des Spülkasten,  Wasserzulauf
  
  { 
	  static unsigned long WC_zeit;
	  
	 
	  
	  if (digitalRead(wcSensor) == LOW && (digitalRead(reedSensor) == LOW) )  //Kippschalter == 0  geöffnet / reedkontakt == Low wasser ausreichend 
	  {  
		  digitalWrite(pumpe, HIGH);
		  digitalWrite(wcMAG, HIGH);
		  WC_zeit = millis();
	  
	  
	  
	  if (millis() - WC_zeit > 2000)   // wenn Pumpe und Magnetvetil länger als 2s High sind, dann könnte Fehler sein und beide auf Low setzen
	  {
		  digitalWrite(pumpe, LOW);
		  digitalWrite(wcMAG, LOW);
	  }
	   }
	  //hier kommt noch ein Zähler hin, wenn 3x hinter einander Fehler dann in Notfunktion == Notaus-alle!!!!
  }


 void blumengiesen()				//Steuerung für Bewässerung der Blumenkästen, Bodensensor ermittelt Bodenfeuchte,
								// wird nur aufgerufen wenn genügend Wasser da, Messung alle 1s und 20x  durchschnitt bilden
 { static int count1, bodensum;
	 static unsigned long Startzeit_giessen;
	 
	if (millis() - zeitletzterMessung4 > 1000)
	 {
		 zeitletzterMessung4 = millis();
		 
		 
		 int boden_add = analogRead(feuchteSensor);   //Feuchte messen und Durchschnitt bilden
		 bodensum += boden_add;
		 count1++;
		
 	     }
		 if (count1 >= 20)
		 {   count1 = 0;
			 Boden = bodensum / 20;
			 bodensum = 0;
			
			 lcd.setCursor(2, 3);
			 lcd.print(Boden);
		 }
	
	 
	 if (Boden > (boden_Wert - boden_hysterese)  && millis() - Startzeit_giessen > 8000 )  // Bodenfeucht mit Hysterese und nach 8s, dann giessen 
			{
				if ((digitalRead(reedSensor) == LOW) && (digitalRead(wcSensor) == HIGH))  // Wasser da && Spülkasten voll, dann giessen
			  
				  {																			// wenn Spülkasten leer, dann nicht giessen und abbruch
				    digitalWrite(pumpe, HIGH);
				    digitalWrite(blumeMAG, HIGH);
					 Startzeit_giessen = millis();
					  
			     } 
			 
			
				
			if (millis() - Startzeit_giessen > 4000)   // nach 4s abschlten und dann wieder 8s warten damit Erde durchfeuchten kann und dann wieder messen
			 {
				
				 digitalWrite(pumpe,LOW);
				 digitalWrite(blumeMAG,LOW);
			 }
		 }
	 
 }

saalesteuerung_2014.ino (8.95 KB)

beginner34:
Ist es vielleicht besser ich setzte alles in eine Funktion?

Das beste wäre, Du trennst Dein Programm funktionell nach dem EVA-Prinzip in drei Bereiche auf:
E - Eingabe
V - Verarbeitung
A - Ausgabe

In der "Verarbeitung" der Daten stellst Du dabei nur Variablen anders ein, z.B. Statusvariablen.

Und die tatsächlichen Schaltvorgänge führst Du dann im Funktionsteil "Ausgabe" aus.

Eine Ausgabefunktion für das Öffnen und Schließen der Magnetventile könnte dann z.B. so aussehen:

void schaltenMitVorrang(int wcPin, boolean wcStatus, int blumenPin, boolean blumenStatus)
{
  digitalWrite(wcPin, wcStatus);
  if (wcStatus) blumenStatus=false;
  digitalWrite(blumenPin, blumenStatus);
}

Danke jurs, diese Version hatte ich schon und hat auch funktioniert. Nur kommen jetzt noch Zeitabfragen und intervaldauer mit dazu. Der Boden ist trocken und soll bewässert werden, (Sensor misst) jetzt wird geschaut ob Wasser da und WC-Spülung LOW, dann Pumpe an , Magnetventil Auf. Nach ca. 4s beides wieder LOW und nun soll noch 8s gewartet werden, bevor wieder gemessen wird(Boden muss erst Wasser aufnehmen). Wenn immer noch trocken, dann alles noch mal und wenn 3x gegossen wurde( ohne Erfolg) dann Notabschaltung( darf sich nicht mehr einschalten) Auch wenn kein Wasser da, nicht einschalten. Das ganze muss unterbrochen werden, wenn WC-Spülung HIGH wird ( befüllung des Spülkastens geht vor) Das ganze funktioniert beim Spülkasten ähnlich. Hier ist es wichtig das über den Füllschalter geschaltet wird UND eine feste Zeit nicht überschritten werden darf ( läuft über!) , dann abschalten. Wenn 2x, Notaus! Mein Problem ist das ich in einer Funktion die Pumpe HIGH schalte und danach LOW, aber in der anderen Funktion ich wegen der Zeit die Pumpe nicht auf HIGH setzten kann, weil ich nicht mehr in die Funktion komme (Zeit noch nicht vorbei? )
Über die Serial-Ausgabe kann ich sehen, das die Sensoren richtig schalten, also HIGH und LOW. Zur Zeit sind alle Magnetv. und Pumpe auf HIGH und können nicht auf LOW gesetzt werden.
Wenn du den ganze Code ansiehst, wird es vielleicht klarer. :slight_smile:

Irgendeine Idee :~

MfG Marco

beginner34:
Danke jurs, diese Version hatte ich schon und hat auch funktioniert. Nur kommen jetzt noch Zeitabfragen und intervaldauer mit dazu.

Um so mehr mußt Du Dein Programm funktionell nach dem EVA-Prinzip aufteilen, damit die Programmlogik überschaubar bleibt.

Eingabe: Stand der Sensoren feststellen, feststellen ob Zeiten und Zeitlimits erreicht sind
Verarbeitung: Verschiedene Zeiten und Zeitlimits neu setzen und Sollzustand der Ausgänge festlegen
Ausgabe ==> Zustand der Ausgänge so setzen wie es dem ermittelten Sollzustand entspricht

Der Trick bei der Abtrennung des Schritts "Verarbeitung" von den anderen Programmschritten ist, dass Du beim Verarbeiten die Sollzustände der Ausgänge während der Verarbeitung beliebig oft modifizieren kannst, mit Hilfe von beliebig vielen Sensordaten, Bedingungen und Zusatzbedingungen, ohne dass tatsächlich etwas geschaltet wird. Erst am Ende des Schritts "Verarbeitung", wenn alles berücksichtigt wurde, steht der zu schaltende Zustand fest. Und zwar für alle zu setzenden Ausgänge gleichzeitig. Und nur dieser eine nach endgültiger Verarbeitung feststehende und für alle Ausgänge zu diesem Zeitpunkt gültige Schaltzustand wird nach diesem Verarbeitungsschritt gesetzt.

Du darfst die "Verarbeitung" der Sensordaten, Zeiten, Bedingungen und Zusatzbedingungen NICHT mit anderen Schritten vermischen, insbesondere darfst Du nach Beginn der "Verarbeitung" von Informationen nicht noch einmal in den Zustand der Informationssammlung (Eingabe) wechseln und Du darfst auch nicht vor dem Ende der "Verarbeitung" eines Schrittes schon tatsächliche Schaltvorgänge ausführen, die sich möglicherweise im weiteren Verlauf der Verarbeitung als falsch herausstellen, wenn noch weitere Bedingungen verarbeitet werden.

Dein Programm ist vom Konzept her grundlegend falsch angelegt, weil es die Schritte vermischt und die "Verarbeitung" der Eingangsdaten und Zeiten von der Verarbeitung der Bedingungen und der Ausgabe der Schaltzustände nicht sauber getrennt ist.

Hallo, so in etwa habe ich es mir vorgestellt. Wenn ich dich richtig verstanden habe, dann sollte es in etwa so aus sehen:
-Eingabe: wert->digiRead(pin) -wert ist dann 1 oder 0 // wird mit allen Eingängen gemacht

  • Verarbeitung : ist wert 1 oder 0 ; hat sich was geändert, dann mache das // die Variablen auf Änderungen prüfen
  • Verarbeitung: die Ausgänge ändern // jetzt die Änderungen der Pins

soweit richtig?
Wie oder wann setzt du jetzt Funktionen? Schreibst du in der loop Eingabe und Verarbeitung und dann neue Funktion mit der Ausgabe? SO wäre jetzt meine Idee. Vielleicht kannst du einen kleinen psydo Code posten. Danke XD

MfG Marco

Falls es dir hilft - ich würde es wahrscheinlich etwa so zu lösen versuchen:

#define STATUS_OFF 0
#define STATUS_WC 1
#define STATUS_GARTEN 2

uint8_t status =STATUS_OFF;
unsigned long letzterStatusWechselZeitpunkt;


void loop(){
  sammleAlleRelevantenDaten();
  uint8_t newStatus=STATUS_OFF;
  if (wasserImTank()){
     if (wcBrauchtWasser()){
        newStatus=STATUS_WC;
     } else if (gartenBrauchtWasser()){
        newStatus=STATUS_GARTEN;
    }
  }
  setStatus(newStatus);
  schlafEinWeilchen();
}

void setStatus(uint8_t  newStatus){
  if (newStatus != oldStatus){
// Ventile auf/zu , Pumpe an aus ....
    letzterStatusWechselZeitpunkt=millis();
    status=newStatus;
  }
}


/*
Hier wird's etwas tricky - Die Pumpe soll nur laufen, wenn es zu trocken ist
 UND
(Bewässerung läuft seit weniger als AAA Sekunden 
ODER
Bewässerung lief BBB sekunden nicht)
*/
void gartenBrauchtWasser(){
  if (feuchtGenug()) {return false;}
  if ( (status == STATUS_GARTEN) && (millis() - letzterStatusWechselZeitpunkt) / 1000 < AAA){return true;}
  if ( (status != STATUS_GARTEN) && (millis() - letzterStatusWechselZeitpunkt) / 1000 < BBB){return true;}
  return false;
}

Schönes Wochenende :slight_smile: