Neues Projekt neue Probleme - If Abfrage mit mehreren Eingängen

Hey Leute,

ich bin im moment dabei, für meine Gartenbewässerung und "Wasserwirtschaft" eine Steuerung zu entwickeln und die dazu notwendige Software zusammen zu bauen. Nur leider stoße ich schon relativ zu Beginn auf ein Problem.

Hier erstmal der Code:

#include "PCF8574.h"

PCF8574 m1(0x20);
PCF8574 m2(0x24);

// Ausgänge definieren
int Tank_1_100 = P0;
int Tank_2_025 = P1;
int Tank_2_050 = P2;
int Tank_2_100 = P3;
int Tank_IBC   = P4;
int Reserve    = P5; // Pin noch unbenutzt
int Tank_1_025 = P6;
int Tank_1_050 = P7;


// Eingänge definieren
int Pumpe_1   = P0;
int Pumpe_2   = P1;
int Ventil_1  = P2;
int IBC_Voll  = P3;
int Reserve2   = P4; // Pin noch unbenutzt
int Voll_1    = P5; 
int Voll_2    = P6;
int WLAN      = P7;

// Zustände definieren
char z_Tank_1 = 0;
char z_Tank_2 = 0;
char z_Tank_IBC = 0;

void setup() {
  Serial.begin (9600);
  Serial.println ("Wassertanksteuerung");
  
  m1.begin();
  m2.begin();
  
  // Ausgänge setzen
  m1.pinMode(Pumpe_1, OUTPUT);
  m1.pinMode(Pumpe_2, OUTPUT);
  m1.pinMode(Ventil_1, OUTPUT);
  m1.pinMode(IBC_Voll, OUTPUT);
  m1.pinMode(Voll_1, OUTPUT);
  m1.pinMode(Voll_1, OUTPUT);
  m1.pinMode(WLAN, OUTPUT);

  // Eingängesetzen
  m2.pinMode(Tank_1_100, INPUT);
  m2.pinMode(Tank_2_025, INPUT);
  m2.pinMode(Tank_2_050, INPUT);
  m2.pinMode(Tank_2_100, INPUT);
  m2.pinMode(Tank_IBC, INPUT);
  m2.pinMode(Tank_1_025, INPUT);
  m2.pinMode(Tank_1_050, INPUT);
  
  Serial.begin (9600);
  Serial.println ("Wassertanksteuerung");
}

void loop() {
  Sensoren_abfragen();
  Serial.println("Empfange Daten");
  Serial.println(z_Tank_1);
  delay(1000);
}

void Sensoren_abfragen() {
  if (m2.digitalRead(Tank_1_100) && m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025)){
    z_Tank_1 = 3;
  }
  if (!m2.digitalRead(Tank_1_100) && m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025)){
    z_Tank_1 = 2;
  }
  if (!m2.digitalRead(Tank_1_100) && !m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025)){
    z_Tank_1 = 1;
  }
  if (!m2.digitalRead(Tank_1_100) && !m2.digitalRead(Tank_1_050) && !m2.digitalRead(Tank_1_025)){
    z_Tank_1 = 0;
  }
}

Das Problem ist in der Funktion "Sensoren_abfragen". Mein Plan war es die Variable z_Tank_1 mit einem Wert zwischen 0 und 3 zu füllen, je nachdem welcher Zustand aktuell ansteht. Klar ich kann nur auf einen Wert abfragen, aber ich spiele mit dem Gedanken daran, falls mal ein Sensor "klemmt" oder so eine Fehlermeldung raus kommt. Sprich wenn Eingänge "Tank_1_025" und "Tank_1_100" HIGH sind, aber Eingang "Tank_1_050" LOW ist, dann ist irgendwas nicht richtig.

Noch zur Erklärung, der Eingang "Tank_1_100" gibt an, dass der Tank voll ist, "Tank_1_050" zu hälfte und "Tank_1_025" das er zu einem viertel gefüllt ist. Ich weiß nicht, ob ich das mir da ggf. zu einfach mache oder einfach zu kompliziert denke.

Nur zur Erklärung, sobald die Variable > 0 ist, soll parallel zur Anzeige eine Pumpe angehen um Wasser von Tank_1 in Tank_IBC um zu pumpen. Ich muss das Wasser leider umpumpen, da ich Tank_1 und Tank_IBC nicht direkt miteinander verbinden kann. Hängt baulich zusammen, falls jemand das wissen möchte.

Vielleicht kann mir jemand dabei helfen?

Michael

PS:

Das mit der Abfrage hatte ich mir zumindest so gedacht, da ein Digitaler Eingang ja nur HIGH oder LOW haben kann und über das ! wird dieser "invertiert", soweit ich das richtig verstanden habe. Vielleicht gibt es aber auch eine Möglichkeit das "schöner" zu gestalten, da eine identische Abfrage noch für Tank_2 ansteht.

Das lässt sich sicher mit dem UND, also "&&" abfragen. Bei Oder ist es "||".
Ich hoffe deine Frage richtig verstanden zu haben.
Und die Abfragewerte sollten in Klammern () gesetzt werden.

Evtl. denkst du noch mal darüber nach, dies per SwitchCase zu erledigen.

??? Gibts da noch mehr solcher verwirrenden Kommentare?
Dann las Sie lieber ganz weg; Das wird dann aus dem Kontext erkannt.

Ein klein wenig Erfahrung im Maschinenbau ist mein eigen.
Da hat man es dauernd mit solchen Problemen zu tun.
Ein defekter Sensor kann zu schweren Folgeschäden in beliebiger Größe führen.

Ein übliches Verfahren ist, dass eine Störkette eingerichtet wird, welche völlig unabhängig von der eigentlichen Ablaufsteuerung arbeitet.

Die einzige Verbindung der beiden:
Die Störkette kann die Ablaufsteuerung stoppen, aber mehr auch nicht.

Ein Fragment der Störkette kann durchaus eine Sensor Plausibilitätsprüfung sein.
Ja, das halte ich für sehr sinnvoll!

Frage, wie kann Tank_1_050 LOW sein wen "Tank_1_025" und "Tank_1_100" HIGH sind
Oder ist das nur Fehler und sollte sein Tank_2_050 ?

Im Fehlerfall. (Der ja abgefangen und darauf reagiert werden soll)

Dafür solltest Du am Funktionsanfang z_Tank_1 = -1; setzen, denn dann bedeutet -1 eine fehlerhafte Konstellation. Tritt der Fehler auf, muß ein Merker einrasten und alle Pumpvorgänge und dergleichen verhindern.

@fony Das war nur ein möglicher Fehler. Also wenn der Sensor am Eingang "Tank_1_050" "hängt". Also nur als Beispiel war diese "kombination" gedacht.

@my_xy_projekt Ich hatte mal irgendwo gelesen Kommentare schaden nicht. Aber klar, verwirren können diese, wenn verschiedene Menschen mit verschiedenen Gedankengängen dran sitzen :wink: Ich denke manchmal um 5 Ecken und gehe davon aus, dass andere mir hinterher kommen.

@HotSystems mit && habe ich die Vergleiche ja kombiniert, Klammern habe ich nicht gesetzt weil ich wie im Code beschrieben habe es wie folgt gedacht habe:

if (m2.digitalRead(Tank_1_100) && m2.digitalRead(Tank_1_050_)...

und eben mit dem ! vor "m2.digitalRead()" sollte es ja invertiert sein, wenn ich das richtig verstanden habe.

Nur das aktuelle Problem ist, er soll zumindest im aktuellen Aufbau den Wert "z_Tank_1" auf dem SeriellenMonitor ausgeben, doch es kommt nur die Meldung "Empfange Daten" und kein Wert zwischen 0 und 3

Bau Dir eine kleine Funktion:
Tank_1_100 == voll && Tank_1_50 == leer => Fehler
Tank_1_100 == voll && Tank_1_25 == leer => Fehler
Tank_1_50 == voll && Tank_1_25 == leer => Fehler
Du kannst z.B. eine bytevariable nehmen und für jeden Fehler ein zugeordnetes bit setzen.
Ist die Variable != 0 hast Du einen Fehler und kannst drauf reagieren, indem Du wieder die bit-zustände nimmst oder einfach nur solange etwas machst, bis alle bits gelöscht sind.

Das hat nix mit gedankengang zu tun.
Nochmal:

// Ausgänge definieren
int Tank_1_100 = P0;
  // Eingängesetzen
  m2.pinMode(Tank_1_100, INPUT);

???

Der Gedanke klingt sehr interessant, nur aktuell ist ja mein Problem, dass er nicht auf die Vergleiche reagiert. Also kein Wert zwischen 0 und 3 ausgibt.

Ja okay, da hätte ich andere Formulierungen ggf. eher verwenden sollen :smiling_face_with_tear:

Dann gehören da weitere Serielle Ausgaben rein, um sicherzugehen, das wirklich irgendwas erfasst wurde und ausgegeben werden kann.

Kommt denn wenigstens die Ausgabe "Empfange daten" ?

ja das "Empfange Daten" kommt

welche PCF8574.h lib hast Du? Da gibts zuviele, das ich jetzt rate.

Warte ich gucke fix, aber ich habe den Code ohne Abfragen schon am laufen gehabt, also beim Abfragen der Eingänge und setzen der Ausgänge passiert etwas. Hatte mit meinem "Testaufbau" etwas rumgespielt und die LEDs Blinken lassen, bzw. die Eingänge abfragen lassen und direkt in Seriellenmonitor ausgegeben. Also der Teil sollte normalerweise problemlos laufen.

Es ist die "PCF8574 library" von "Renzo Mischianti" in der Version 2.3.5

Hier aber auch mal 2 Fotos zu meinem (ja etwas übertriebem) Testaufbau mit Testplatine:

Ich weiß, alles definitiv übertrieben, aber das Gehäuse soll für zukünftige andere Projekte und Weiterentwicklungen dienen. Klar ein Steckbrett hätte es auch getan, aber bei 7 Eingängen und 7 Ausgängen wirds manchmal etwas "wackelig".

Ah, ok: GitHub - xreef/PCF8574_library: PCF8574 library. i2c digital expander for Arduino, Raspberry Pi Pico and rp2040 boards, esp32, SMT32 and ESP8266. Can read write digital values with only 2 wire. Very simple to use and encoder support.

compiliert fehler- und warnungsfrei.
Es wird jeder Pin zur Anzeige gebracht - ich schau zwischenzeitlich mal in die lib, denn das wird vermutlich auch steckenbleben...

#include "PCF8574.h"

PCF8574 m1(0x20);
PCF8574 m2(0x24);

// Ausgänge definieren
int Tank_1_100 = P0;
int Tank_2_025 = P1;
int Tank_2_050 = P2;
int Tank_2_100 = P3;
int Tank_IBC   = P4;
int Reserve    = P5; // Pin noch unbenutzt
int Tank_1_025 = P6;
int Tank_1_050 = P7;


// Eingänge definieren
int Pumpe_1   = P0;
int Pumpe_2   = P1;
int Ventil_1  = P2;
int IBC_Voll  = P3;
int Reserve2  = P4; // Pin noch unbenutzt
int Voll_1    = P5;
int Voll_2    = P6;
int WLAN      = P7;

// Zustände definieren
uint8_t z_Tank_1 = 0;
uint8_t z_Tank_2 = 0;
uint8_t z_Tank_IBC = 0;

void setup()
{
  Serial.begin (9600);
  Serial.println ("Wassertanksteuerung");
  // Ausgänge setzen
  m1.pinMode(Pumpe_1, OUTPUT);
  m1.pinMode(Pumpe_2, OUTPUT);
  m1.pinMode(Ventil_1, OUTPUT);
  m1.pinMode(IBC_Voll, OUTPUT);
  m1.pinMode(Voll_1, OUTPUT);
  m1.pinMode(Voll_1, OUTPUT);
  m1.pinMode(WLAN, OUTPUT);
  // Eingängesetzen
  m2.pinMode(Tank_1_100, INPUT);
  m2.pinMode(Tank_2_025, INPUT);
  m2.pinMode(Tank_2_050, INPUT);
  m2.pinMode(Tank_2_100, INPUT);
  m2.pinMode(Tank_IBC, INPUT);
  m2.pinMode(Tank_1_025, INPUT);
  m2.pinMode(Tank_1_050, INPUT);
  m1.begin();
  m2.begin();
}

void loop()
{
  Sensoren_abfragen();
  Serial.println("Empfange Daten");
  Serial.println(z_Tank_1);
  delay(1000);
}

void Sensoren_abfragen()
{
  z_Tank_1 = 0;
  Serial.print(F("Lese Pins: "));
  Serial.print(m2.digitalRead(Tank_1_100));
  Serial.print(' ');
  Serial.print(m2.digitalRead(Tank_1_050));
  Serial.print(' ');
  Serial.println(m2.digitalRead(Tank_1_025));
  if (m2.digitalRead(Tank_1_100) && m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025))
  {
    bitSet(z_Tank_1, 0);
  }
  if (!m2.digitalRead(Tank_1_100) && m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025))
  {
    bitSet(z_Tank_1, 1);
  }
  if (!m2.digitalRead(Tank_1_100) && !m2.digitalRead(Tank_1_050) && m2.digitalRead(Tank_1_025))
  {
    bitSet(z_Tank_1, 2);
  }
  if (!m2.digitalRead(Tank_1_100) && !m2.digitalRead(Tank_1_050) && !m2.digitalRead(Tank_1_025))
  {
    bitSet(z_Tank_1, 3);
  }
}

EDIT! - Ich hab das setup() mal neu gemacht.

Hallo raspido

Woher kommt die Notwendigkeit für die Verwendung eines Portexpanders?

Habe ich etwas überlesen ?

@paulpaulson Ich wollte möglichst wenige Pins belegen, da ich ggf. noch das ein oder andere ergänzen möchte (Temp. Sensoren, Luftfeuchtesensoren, oder ähnliches). Und zum anderen könnte ich so mein Projekt von Beginn an mit einer option für ein "Erweiterungsplatine" ausstatten, falls noch ein Tank 3 und 4 dazukommen sollte. Also kann da ein Anschluß einplanen um i2c mit Vcc und GND an ein Connector weiter zu geben und fertig.

Also sonst gibt es eigentlich kein besonderen Grund. Und selbst so würden die Pins die vorhanden sind, langsam etwas mager werden.

@my_xy_projekt Irgendwie bekomme ich auf die Ausgabe von "z_Tank_1" immer nur eine 8 ausgegeben. Egal wie die Schalter stehen.

Du hast keine Widerstände dran, oder diese falsch angeschlossen? Die 8 sagt Dir, das bit 4 gesetzt ist.