tabelarische I/O Schalten

Hallöchen Arduinofans,

folgende Thematik , ich habe circa 5 verschiedene Eingangssignale (alles boolsche Werte), und ca. 5 Ausgangswerte(ebenfalls boolsche Werte). Momentan werden alle Signale in If-Schleifen ausgewertet. Das bedeutet das ich ein haufen Bedingungen habe und dann einige Bits gesetzt werden. Ich würde das ganze gern übersichtlicher gestalten, möglicherweiße in einer Art Tabelle. Geht soetwas? Ich hab leider keine Idee wie ich das realisieren kann. Möglichst auch so, dass man mal was verändern kann.

if ( bitRead(Solar_Dach_state, 7) == 1 and bitRead(KFZ_state, 7) == 1 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 )   // Sonne          = 1 
    {                                                                                                                                       // D+             = 1
      digitalWrite( Trennrelaise, HIGH);                                                                                                    // Netz           = 1
      digitalWrite(CTEK_Umschalter, HIGH);                                                                                                  // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter, HIGH);                                                                                              
      digitalWrite(Solar_Umschalter, LOW);                                                                                                  // Freezer_Bat über Solar
      digitalWrite(Solar_Schalter, LOW);                                                                                                    // Komfort_Bat über Lichtmaschine
    }
  if ( bitRead(Solar_Dach_state, 7) == 0 and bitRead(KFZ_state, 7) == 1 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 )   // Sonne          = 0
    {                                                                                                                                       // D+             = 1
      digitalWrite( Trennrelaise, HIGH);                                                                                                    // Netz           = 1
      digitalWrite(CTEK_Umschalter, HIGH);                                                                                                  // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter, HIGH);
      digitalWrite(Solar_Umschalter, HIGH);                                                                                                 // Komfort_Bat über Lichtmaschine, Motor läuft
      digitalWrite(Solar_Schalter, HIGH);
    }
  if ( bitRead(Solar_Dach_state, 7) == 1 and bitRead(KFZ_state, 7) == 0 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 )   // Sonne          = 1  
    {                                                                                                                                       // D+             = 0
      digitalWrite( Trennrelaise,   HIGH);                                                                                                  // Netz           = 1
      digitalWrite(CTEK_Umschalter, HIGH);                                                                                                  // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter,   LOW);                                                                                    
      digitalWrite(Solar_Umschalter,LOW);                                                                                                   // Komfort_Bat über CTEK
      digitalWrite(Solar_Schalter,  LOW);                                                                                                   // Freezer_Bat über Solar
    }                                                                                                   /*******************************************************************/
  if ( bitRead(Solar_Dach_state, 7) == 0 and bitRead(KFZ_state, 7) == 0 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 and bitRead(Setup_state, 4) == 0 and bitRead(Solar_TFT1_state, 7) == 0 )  
                                                                                                                                        // Sonne          = 0 
    {                                                                                                                                   // D+             = 0
      digitalWrite( Trennrelaise,   HIGH);                                                                                              // Netz           = 1
      digitalWrite(CTEK_Umschalter, HIGH);                                                                                              // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter,   LOW );                                                                                              // Solar_Um       = 0
      digitalWrite(Solar_Umschalter,HIGH);                                                                                              // Doppelmodus    = 0, Button Solar Autonom Modus deaktiviert.
      digitalWrite(Solar_Schalter,  HIGH);                                                                                              // Komfort_Bat wird über CTEK geladen.
    }    /*******************************************************************/
  if ( bitRead(Solar_Dach_state, 7) == 0 and bitRead(KFZ_state, 7) == 0 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 and bitRead(Setup_state, 4) == 1 and bitRead(Solar_TFT1_state, 7) == 0 )  
                                                                                                                                      // Sonne          = 0 
    {                                                                                                                                 // D+             = 0
      digitalWrite( Trennrelaise,   HIGH);                                                                                            // Netz           = 1
      digitalWrite(CTEK_Umschalter, LOW );                                                                                            // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter,   LOW );                                                                                            // Solar_Um       = 1
      digitalWrite(Solar_Umschalter,HIGH);                                                                                            // Doppelmodus    = 0  
      digitalWrite(Solar_Schalter,  HIGH);                                                                                            // Freezer_Bat wird über CTEK geladen.
    }    /*******************************************************************/
  if ( bitRead(Solar_Dach_state, 7) == 0 and bitRead(KFZ_state, 7) == 0 and bitRead(KFZ_state, 6) == 1 and bitRead(Setup_state, 6) == 1 and bitRead(Solar_TFT1_state, 7) == 1 )  
                                                                                                                                      // Sonne          = 0 
    {                                                                                                                                 // D+             = 0
      digitalWrite( Trennrelaise,   LOW);                                                                                             // Netz           = 1
      digitalWrite(CTEK_Umschalter, LOW);                                                                                             // Bat-Auto-Modus = 1
      digitalWrite(CTEK_Schalter,   LOW);                                                                                             // Doppelmodus    = 1
      digitalWrite(Solar_Umschalter,HIGH);                                                                                            
      digitalWrite(Solar_Schalter,  HIGH);                                                                                            // Freezer_Bat und KomfortBat wird über CTEK geladen. 
    }

Hat es irgendeinen Grund weshalb du Zustände als einzelne Bits abspeicherst anstatt ganze Bytes (bool) zu verwenden?

Ansonsten gibt es Bit-Felder um Bits ansprechende Namen zu geben. Dann fällt der ganze Kram mit bitRead() weg

mach’ einfach eine Tabelle, index sind deine Eingangsbits - sind eh nur 4 bit oder 16 Zustände:

int idx=bitRead(Solar_Dach_state, 7) | (bitRead(KFZ_state, 7)<<1) | (bitRead(KFZ_state, 6)<<2) | (bitRead(Setup_state, 6)<<3);
int aTrennrelais[] = {0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0};
digitalWrite( Trennrelaise, aTrennrelais[idx]);

oder ein 4-dimensionales Array:

 int aTrennrelais[2][2][2][2]=
{ { { { 0,0 }, {0,1} }, {  { 0,0 }, {0,1} } }, {  {  { 0,0 }, {0,1} }, {  { 0,0 }, {0,1} } },
  { { { 0,0 }, {0,1} }, {  { 0,0 }, {0,1} } }, {  {  { 0,0 }, {0,1} }, {  { 0,0 }, {0,1} } }};
digitalWrite( Trennrelaise, aTrennrelais[bitRead(Solar_Dach_state, 7)][bitRead(KFZ_state, 7)][bitRead(KFZ_state, 6)][bitRead(Setup_state, 6)]);

was dir halt immer besser gefällt …

Uhh, "If-Schleife" ist einer der verbotenen Begriffe :slight_smile:
Entweder Du verwendest eine Schleife oder eine IF-Anweisung :wink:

Du könntest natürlich ein Zweidimensionales Array erstellen, welches alle Deine Fälle abdeckt.

Du setzt Deine erwarteten Eingangswerte in einem festen Schema zusammen:
Leer, Leer, Sonne, D+, Netz, Bat-Auto-Modus, Solar_Um, Doppelmodus
00001100 = 0x0C = 12

Daraus resultiert:
Leer, Leer, Leer, Trennrelais, CTEK_Umschalter, CTEK_Schalter, Solar_Umschalter, Solar_Schalter
00011011 = 0x1B = 27

uint8_t table[6][2] = { {12,27},
                    {X,Y} ... };

Nun nimmst Du die echten Eingangswerte, setzt diese zusammen, holst den passenden Eintrag aus dem Array und schaltest entsprechend die Ausgänge nach dem Wert in der 2. Dimension.

PS: Da waren zwieblum schneller, aber so gibt es eine Variante mehr :slight_smile:

Denke, über das Thema kann man trefflich philosophieren ... so viele Möglichkeiten :slight_smile:

Hallo,

da mach ich doch mit :wink:

ich kenne das mit dem BitRead() nicht , stammt das aus einer Lib ?

Eigendlich geht es Dir darum die IF abfragen übersichtlicher zu gestalten. Ob das mit einer Tabelle überschtlicher wird weiss ich nicht. Eventuell willst Du ja in 6 Monaten noch was an der Logik ändern. Ich glaube da sind die If Abfragen einfacher zu lesen. Letztlich willst Du die 5 Eingänge igendwie logisch verknüpfen und dann bestimmte Zustände setzen . Es geht mit AND aber auch mit einer Klammer und einem ODER siehe Zustand 3.

die Ausgaben für die Ausgänge hab ich jetzt mal weg gelassen.

ich habe das nach folgendem Schema gelöst.

Heinz

bool inp1;
bool inp2;
bool inp3;
bool inp4;
bool inp5;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  readInput(); // Eingänge lesen

  // Bedingung für Zustand 1
  if (inp1 & !inp2 & !inp3 & !inp4 & inp5) zustand1();

  // Bedingung für Zustand 2
  if (inp1 & inp2 & inp3 & !inp4 & !inp5) zustand2();
  
  // Bedingung für Zustand 3
  if ( inp1 & (inp2 || inp3) & !inp4 & !inp5) zustand3();

  delay(300);// nur zum testen 
}

void readInput() {
  inp1 = !digitalRead(2); // Minus schaltend also invertieren
  inp2 = !digitalRead(3);
  inp3 = !digitalRead(4);
  inp4 = !digitalRead(5);
  inp5 = !digitalRead(6);
}

void zustand1() {
  Serial.println("Zustand 1");
}

void zustand2() {
  Serial.println("Zustand 2");
}

void zustand3() {
  Serial.println("Zustand 3");
}

Eine Tabelle ist im Prinzip nichts anderes als ein 2-dimensionales Array.

Rentner:
ich kenne das mit dem BitRead() nicht , stammt das aus einer Lib ?

::slight_smile: bitRead() - Arduino Reference

Serenifly:
::slight_smile: bitRead() - Arduino Reference

Danke für den Hinweis , hab ich noch nie verwendet.

Heinz

Serenifly:
Hat es irgendeinen Grund weshalb du Zustände als einzelne Bits abspeicherst anstatt ganze Bytes (bool) zu verwenden?

Ich finde das eigentlich eine sehr gute Idee. Solche Abhängigkeiten habe ich in meinem Stellwerk für meinen Modellbahnhof zu Hauf, da dort vorbildnahe Abläufe mit Fahrstraßen, Belgtmeldern und Weichenschaltern realisiert sind. Das läuft praktisch alles tabellengesteuert. Ändern sich Abhängigkeiten, müssen meistens nur die Tabellen geändert werden.
Die Tabellen enthalten Bitmasken, die dann entsprechend einfach logisch mit den I/O-Bits verknüpft werden können. Programmtechnisch sind es eindimensionlae Tabellen, logisch aber 2-dimensionale: Die Bits in den Tabellenworten sind die Spalten, und die Tabellenworte die Reihen. Das lässt sich dann auch optisch wie eine Tabelle aufbauen, und ist daher recht übersichtlich. Ein Beispiel:

const uint32_t ZG_Trennung[ZGLANZ] = {
  //MK6_5a|MK6_14|MK6_24|MK2_12|MK13_12|MK11_22|MK2_22|MK23_22|MK3_23|MK24_23   Gleis
         0|     0|     0|MK2_12|MK13_12|      0|     0|      0|     0|      0,  // HGl12I
         0|     0|     0|     0|      0|      0|     0|      0|     0|      0,  // HGlOfI
         0|     0|     0|     0|      0|      0|     0|      0|     0|      0,  // HGlSuI
         0|     0|     0|     0|      0|MK11_22|MK2_22|MK23_22|     0|      0,  // HGl22I
         0|     0|     0|     0|      0|      0|     0|      0|MK3_23|MK24_23,  // HGl23I
         0|     0|     0|     0|      0|      0|     0|      0|     0|      0   // HGl6I
    };

Der senkrechte Strich '|' odert die Bitmasken auf, und dient gleichzeitig optisch als 'Spaltentrenner'.

Im aktuellen Fall wären 2 Tabellen möglich: Die erste enthält die Bitmasken für die relevanten Eingangskombinationen. Da die Eingänge bereits bitkodiert sind, muss man das entsprechende Eingangsmuster nur in einer Schleife mit den Tabelleneinträgen vergleichen, und bekommt den Index mit dem passenden Muster.
Die 2. Tabelle enthält die dazugehörigen Ausgangsbits. Über den ermittelten Index bekommt man die gewünschten Ausgangszustände, und muss die dann nur noch entsprechend der gesetzten Bits ein- oder ausschalten. Eine Änderung der Zusammenhänge erfordert dann nur eine Änderung in den Tabellen.
Das klassische EVA-Prinzip einer Steuerung: Am Anfang des loops die Eingänge einlesen und in Bits ablegen. Dann per Tabellenabhängigkeit Verarbeiten und am Ende die entsprechenden Ausgänge schalten.

Bei komplexeren Zusammenhängen wird es anders sehr schnell unübersichtlich. (Mach es so einfach wie möglich - komplex wird es von alleine :wink: ).
Mit uint32_t können 32 Eingangs bzw Ausgangsleitungen in einer Tabelle verwaltet werden. Für meinen Bahnhof hat das gereicht :wink:

Wenn man es richtig mit Bit-Masken macht, ok. Dann ist das in Ordnung. Aber nicht so wie im Original Code. Da bringt es rein gar nichts und macht nur den Code schwerer lesbar

Serenifly:
Hat es irgendeinen Grund weshalb du Zustände als einzelne Bits abspeicherst anstatt ganze Bytes (bool) zu verwenden?

Die Bits die ich durch die IF-Anweisung überprüfe sind in 3 Bytes angeordnet die über einen CAN-Bus verschickt werden. Um möglichst nur immer ein Byte mit 8 Informationen zu verschicken habe ich die zustände in Bits abspeichern wollen.

den Bits Namen zuzuweißen wär ganz cool. ich hab aber leider nichts dazu gefunden. kann mir dafür jemand einen link oder ne kleine Erklärung zukommen lassen, dankeschön

Vielen dank für die vielen verschiedenen Möglichkeiten, muss ich mir erstmal angucken und verstehen... manchnes ist noch nicht ganz schlüssig für mich.

Hi

Das Zauberwort heißt Bitfield (Bit-Feld) - Link gerade Keinen zur Hand, gab's hier im Forum aber schon, müsste also findbar sein.

MfG