Anfänger benötigt Unterstützung mit millis

Anfänger benötigt etwas Unterstützung oder einen Anschubser

Mein Problem ist das ich eine Warnbalkenbeleuchtung basteln möchte aber without delay

Mit der Delay Funktion klappt alles aber ich bremse mich aus und kann nichts anderes mehr laufen lassen.

Es handelt sich hier um 6 LED´s nun habe ich schon ein wenig gesucht und auch ausprobiert.
Mein letzter Code auf den ich gestoßen war hatte Einträge mit Intervallzeiten.
Irgendwie steige ich da aber nicht durch vorallem da ich den Ablauf brauche 1-6 an und dann alle aus (Pause)

Vielleicht kann mir hier jemand einen Tipp geben wie ich eine Verzögerung einbaue und zum Schluss eine Pause.

// Which pins are connected to which LED
const byte LED1 = 13;
const byte LED2 = 12;
const byte LED3 = 11;
const byte LED4 = 10;
const byte LED5 = 9;
const byte LED6 = 8;
 
// Assigning delays. 
const unsigned long LED1_interval = 3000;
const unsigned long LED2_interval = 2500;
const unsigned long LED3_interval = 2000;
const unsigned long LED4_interval = 1000;
const unsigned long LED5_interval = 1000;
const unsigned long LED6_interval = 1000;
 
// Declaring the variables holding the timer values for each LED. 
unsigned long LED1_timer;
unsigned long LED2_timer;
unsigned long LED3_timer;
unsigned long LED4_timer;
unsigned long LED5_timer;
unsigned long LED6_timer;
 
// Setting 3 digital pins as output pins and resetting timer
void setup () 
  {
  pinMode (LED1, OUTPUT);
  pinMode (LED2, OUTPUT);
  pinMode (LED3, OUTPUT);
  pinMode (LED4, OUTPUT);
  pinMode (LED5, OUTPUT);
  pinMode (LED6, OUTPUT);
  LED1_timer = millis ();
  LED2_timer = millis ();
  LED3_timer = millis ();
  LED4_timer = millis ();
  LED5_timer = millis ();
  LED6_timer = millis ();
  }  // end of setup
 
 
//LED1 loop that turns it ON if it is OFF and vice versa
void toggle_LED1 ()
  {
   if (digitalRead (LED1) == LOW)
      digitalWrite (LED1, HIGH);
   else
      digitalWrite (LED1, LOW);
 
 
  // remember when we toggled it
  LED1_timer = millis ();  
  }  // end of toggleLED_1
 
 

//LED2 loop
void toggle_LED2 ()
  {
   if (digitalRead (LED2) == LOW)
      digitalWrite (LED2, HIGH);
   else
      digitalWrite (LED2, LOW);
 
 
  // remember when we toggled it
  LED2_timer = millis ();  
  }  // end of toggle_LED2
 

 
  //LED 3 loop
void toggle_LED3 ()
  {
   if (digitalRead (LED3) == LOW)
      digitalWrite (LED3, HIGH);
   else
      digitalWrite (LED3, LOW);
 
 
  // remember when we toggled it
  LED3_timer = millis ();  
  }  // end of toggle_LED3



//LED 4 loop
void toggle_LED4 ()
  {
   if (digitalRead (LED4) == LOW)
      digitalWrite (LED4, HIGH);
   else
      digitalWrite (LED4, LOW);
 
 
  // remember when we toggled it
  LED4_timer = millis ();  
  }  // end of toggle_LED4
 


//LED 5 loop
void toggle_LED5 ()
  {
   if (digitalRead (LED5) == LOW)
      digitalWrite (LED5, HIGH);
   else
      digitalWrite (LED5, LOW);
 
 
  // remember when we toggled it
  LED5_timer = millis ();  
  }  // end of toggle_LED5



//LED 6 loop
void toggle_LED6 ()
  {
   if (digitalRead (LED6) == LOW)
      digitalWrite (LED6, HIGH);
   else
      digitalWrite (LED6, LOW);
 
 
  // remember when we toggled it
  LED6_timer = millis ();  
  }  // end of toggle_LED6
 

void loop ()
  {
 
 
  // Handling the blink of LED1.
  if ( (millis () - LED1_timer) >= LED1_interval)
     toggle_LED1 ();
 
 
  // Handling the blink of LED2.
  if ( (millis () - LED2_timer) >= LED2_interval) 
    toggle_LED2 ();
    
// Handling the blink of LED3.
  if ( (millis () - LED3_timer) >= LED3_interval) 
    toggle_LED3 ();

// Handling the blink of LED4.
  if ( (millis () - LED4_timer) >= LED4_interval) 
    toggle_LED4 ();

// Handling the blink of LED5.
  if ( (millis () - LED5_timer) >= LED5_interval) 
    toggle_LED5 ();

// Handling the blink of LED6.
  if ( (millis () - LED6_timer) >= LED6_interval) 
    toggle_LED6 ();
    
/* Other code that needs to execute goes here.
   It will be called many thousand times per second because the above code
   does not wait for the LED blink interval to finish. */
 
 
}  // end of loop

Und so läuft die Sache mit Delay:

int led = 13;
int led2 = 12;
int led3 = 11;
int led4 = 10;
int led5 = 9;
int led6 = 8;
void setup(
) {
  // put your setup code here, to run once:

pinMode(led,OUTPUT);
pinMode(led2,OUTPUT);
pinMode(led3,OUTPUT);
pinMode(led4,OUTPUT);
pinMode(led5,OUTPUT);
pinMode(led6,OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
digitalWrite(led,HIGH);
delay(400);
digitalWrite(led2,HIGH);
delay(350);
digitalWrite(led3,HIGH);
delay(350);
digitalWrite(led4,HIGH);
delay(350);
digitalWrite(led5,HIGH);
delay(350);
digitalWrite(led6,HIGH);
delay(1500);
digitalWrite(led,LOW);
digitalWrite(led2,LOW);
digitalWrite(led3,LOW);
digitalWrite(led4,LOW);
digitalWrite(led5,LOW);
digitalWrite(led6,LOW);
delay(1000);
}

Mit Dank im Vorraus

Schau dir das BlinkWithoutDelay Beispiel an. Da fehlt der Vergleich ob die Zeit abgelaufen ist

Wobei dieser Code auch geradezu danach schreit dass man das in eine Klasse, bzw. ein Funktionsobjekt packt. Anstatt für jeden Pin immer den gleichen Code hinzuschreiben

Nur für die erste led als Bsp.

// Which pins are connected to which LED
const byte LED1 = 13;
const byte LED2 = 12;
const byte LED3 = 11;
const byte LED4 = 10;
const byte LED5 = 9;
const byte LED6 = 8;
 
// Assigning delays.
const unsigned long LED1_interval = 3000;
const unsigned long LED2_interval = 2500;
const unsigned long LED3_interval = 2000;
const unsigned long LED4_interval = 1000;
const unsigned long LED5_interval = 1000;
const unsigned long LED6_interval = 1000;
 
// Declaring the variables holding the timer values for each LED.
unsigned long LED1_timer=0;
unsigned long LED2_timer;
unsigned long LED3_timer;
unsigned long LED4_timer;
unsigned long LED5_timer;
unsigned long LED6_timer;
 
// Setting 3 digital pins as output pins and resetting timer
void setup ()
  {
  pinMode (LED1, OUTPUT);
  pinMode (LED2, OUTPUT);
  pinMode (LED3, OUTPUT);
  pinMode (LED4, OUTPUT);
  pinMode (LED5, OUTPUT);
  pinMode (LED6, OUTPUT);
 // LED1_timer = millis ();
  LED2_timer = millis ();
  LED3_timer = millis ();
  LED4_timer = millis ();
  LED5_timer = millis ();
  LED6_timer = millis ();
  }  // end of setup
 
 
//LED1 loop that turns it ON if it is OFF and vice versa
void toggle_LED1 ()
  {
   if (digitalRead (LED1) == LOW)
      digitalWrite (LED1, HIGH);
   else
      digitalWrite (LED1, LOW);
 
 
  // remember when we toggled it
 //LED1_timer = millis (); 
  }  // end of toggleLED_1
 
 

//LED2 loop
void toggle_LED2 ()
  {
   if (digitalRead (LED2) == LOW)
      digitalWrite (LED2, HIGH);
   else
      digitalWrite (LED2, LOW);
 
 
  // remember when we toggled it
  LED2_timer = millis (); 
  }  // end of toggle_LED2
 

 
  //LED 3 loop
void toggle_LED3 ()
  {
   if (digitalRead (LED3) == LOW)
      digitalWrite (LED3, HIGH);
   else
      digitalWrite (LED3, LOW);
 
 
  // remember when we toggled it
  LED3_timer = millis (); 
  }  // end of toggle_LED3



//LED 4 loop
void toggle_LED4 ()
  {
   if (digitalRead (LED4) == LOW)
      digitalWrite (LED4, HIGH);
   else
      digitalWrite (LED4, LOW);
 
 
  // remember when we toggled it
  LED4_timer = millis (); 
  }  // end of toggle_LED4
 


//LED 5 loop
void toggle_LED5 ()
  {
   if (digitalRead (LED5) == LOW)
      digitalWrite (LED5, HIGH);
   else
      digitalWrite (LED5, LOW);
 
 
  // remember when we toggled it
  LED5_timer = millis (); 
  }  // end of toggle_LED5



//LED 6 loop
void toggle_LED6 ()
  {
   if (digitalRead (LED6) == LOW)
      digitalWrite (LED6, HIGH);
   else
      digitalWrite (LED6, LOW);
 
 
  // remember when we toggled it
  LED6_timer = millis (); 
  }  // end of toggle_LED6
 

void loop ()
  {
 
 
  // Handling the blink of LED1.
  if ( (millis () - LED1_timer) >= LED1_interval){
  LED1_timer=millis();
     toggle_LED1 ();
  }
 
  /* Handling the blink of LED2.
  if ( (millis () - LED2_timer) >= LED2_interval)
    toggle_LED2 ();
   
// Handling the blink of LED3.
  if ( (millis () - LED3_timer) >= LED3_interval)
    toggle_LED3 ();

// Handling the blink of LED4.
  if ( (millis () - LED4_timer) >= LED4_interval)
    toggle_LED4 ();

// Handling the blink of LED5.
  if ( (millis () - LED5_timer) >= LED5_interval)
    toggle_LED5 ();

// Handling the blink of LED6.
  if ( (millis () - LED6_timer) >= LED6_interval)
    toggle_LED6 ();
   
/* Other code that needs to execute goes here.
   It will be called many thousand times per second because the above code
   does not wait for the LED blink interval to finish. */
 
 
}  // end of loop

Immer noch unnötig duplizierter Code. Das ist nicht der Sinn von Funktionen. Man sollte wenigstens das Umschalten des Pins in einer Funktion erledigen. Und den Pin und eine Referenz auf die Zeit-Variable als Parameter übergeben

EDIT:
Folgendes sind unabhängig blinkende LEDs. Kein laufender Balken. Ich hatte mich da nur an den Code ohne Delay gehalten was thematisch nicht ganz passt

Oder gleich so:

class Led
{
public:
  Led(byte pin, unsigned long interval) : pin(pin), interval(interval), lastMillis(0)
  {
    //pinMode(pin, OUTPUT);
  }

  void operator()()
  {
    if (millis() - lastMillis > interval)
    {
      lastMillis = millis();

      //hier Aktion ausführen
      Serial.print("LED ");
      Serial.println(pin);
    }
  }

private:
  const byte pin;
  const unsigned long interval;
  unsigned long lastMillis;
};

Led led1(8, 3000);
Led led2(9, 1000);

void setup()
{ 
  Serial.begin(9600);
}

void loop()
{
  led1();
  led2();
}

Ohne LED blinken. Statt dessen schreibe ich kurz was auf die serielle Schnittstelle damit man was sieht.

Die Pins auf Ausgang schalten kann man auch bequem im Konstruktor erledigen (ist nur auskommentiert)

Nachtrag:
Man kann hier auch schön seine Objekte in ein Array packen und über diese mit einer for-Schleife iterieren:

Led leds[] = { { 8, 1000 }, { 9, 3000 } };

void loop()
{
   for (Led& led : leds)   //Stichwort: range based for-loop. In anderen Sprachen als "for each" bekannt
      led();
}

@Serenifly

War nur zum verdeutlichen wo das Problem mit den millis liegt ,der Rest sieht mir auch etwas wild aus.
Die idee mit der Klasse werde ich mal aufgreifen da ich mir Literatur zu c++ gekauft habe und am lernen
bin.

Mit der Delay Funktion klappt alles

Das ist fein!

aber ich bremse mich aus

Durchaus!

und kann nichts anderes mehr laufen lassen.

Das ist falsch!

Denn, es gibt ja noch yield() und Interrupts.
Aber spätestens dann ist Schluss mit delay(), denn delay() in yield(), führt zur einer indirekten Rekursion. Und in Interrupts funktioniert delay() nicht.

Also:
Den Umgang mit "ohne Delay" solltest du auf jeden Fall lernen.

Hier also ein Beispiel, wie du es nicht unbedingt machen solltest:

const byte taster     = 3;
const byte led        = LED_BUILTIN;
bool BlinkAnforderung = false;



//---------------------------------------------


void yield()
{
  BlinkAnforderung = !digitalRead(taster);
}



//---------------------------------------------


void setup() 
{
  pinMode(led,OUTPUT);
  pinMode(taster,INPUT_PULLUP);
}
 
void loop() 
{
  if(BlinkAnforderung) digitalWrite(led,!digitalRead(led));
  delay(500);
}

Hallo,

der TO sollte erstmal den Umgang mit millis() lernen. Dann ergibt sich die Lösung schon von alleine. Bevor man den Spielkram mit yield() unterliegt und das Problem nur kaschiert ... :wink:

Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung

Da ist er wieder der "Doc_Arduino"...
Herabwürdigen, der Aussagen anderer: "Spielkram".

Merksatz:

Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem Brunnenrand.

Wer jetzt wen "herabwürdigt", sollten wir mal ignorieren.

combie:
Aber spätestens dann ist Schluss mit delay()

... und deshalb sollte man interrupts erst gar nicht als sinnvolle Lösung für das Problem mit delay (dass der sketch dann festhängt) vorschlagen ...

Meine Meinung. Auch wenn es natürlich Tricks gibt, die da was möglich machen.
Aber wer über delay stolpert, weil er nicht weiß wie er ohne auskommt, sollte nicht mit yield verwirrt werden.

Hi

Es schadet aber nicht, Wissen zu sähen.
Wenn der Fragende um Gottes Willen ja nicht mit neuen Informationen konfrontiert werden darf, kann Er auch direkt bei delay() bleiben ...

Hier funktioniert delay() nicht mehr, deshalb fragt der TO nach Alternativen.
Klar gehen Interrupts auch, man muß aber nicht gleich mit Kanonen auf Spatzen schießen - man kann auch direkt ganze Panzer werfen.

millis() wurde ja bereits genannt - so lange nicht die ganze Zeit geschlafen werden soll, um Strom einzusparen, wäre Das genau mein Weg.
Beim Stromsparen wohl eher ein Interrupt, Der den Arduino alle spätestens 8 Sekunden (WDT) aufweckt, damit Dieser 'nach dem Rechten' sehen kann.
Wobei Stromsparen beim eigentlichen Arduino auch eher witzlos ist, für einen nackten AVR macht Das dann schon wieder mehr Sinn - lässt sich mit einem Arduino_as_ISP aber ja ebenfalls 'programmieren'.

MfG

Hallo,

hab mir mal Gedanken gemacht. Sieht zwar umfangreich aus, aber das ist ja meistens so wenn es blockierfrei laufen soll. :wink:
Magnusol wird vielleicht erstmal mit vielen Neuen erschlagen, aber kann sich anschauen wie man for Schleifen nutzt, wie man mit Zuständen den Ablauf steuert und wie man millis nutzt. Dazu lokale Variablen einsetzt zur Zeitensteuerung.
Die seriellen Ausgaben können dann raus wenn alles klar ist. Viel Spass.

/*
  Doc_Arduino - german Arduino Forum
  IDE 1.8.5
  Arduino Mega2560
  23.03.2018
*/

// Anzahl der Pins und Zeiten müssen gleich sein!
const byte ANZAHL = 8;            // deswegen diese Konstante zur zusätzlichen Sicherheit
const byte pin_Warnbalken [ANZAHL] = {30,31,32,33,34,35,36,37};                   // Pins
const unsigned int zeiten_Warnbalken [ANZAHL] = {0,250,230,210,190,170,150,130};  // Zeiten
const unsigned int einzeit = 1500;
const unsigned int auszeit = 1000;
byte sum_leds;
byte sum_zeiten;

typedef enum {LAUF, WAIT_EIN, WAIT_AUS} state;
state phase = LAUF;



void setup()
{
  Serial.begin(9600);

  sum_leds = sizeof(pin_Warnbalken)/sizeof(pin_Warnbalken[0]);  
  sum_zeiten = sizeof(zeiten_Warnbalken)/sizeof(zeiten_Warnbalken[0]); 

  pinMode(LED_BUILTIN, OUTPUT);
  
  for (byte i=0; i<sum_leds; i++) {
    pinMode(pin_Warnbalken[i],OUTPUT);
  }
  
}

void loop() {

  Steuerung();

  heartbeat();
}


void Steuerung ()
{
  static unsigned long last_millis = 0;
  
  switch (phase) {
      case LAUF:
                if (Warnbalken_Lauflicht() == true) {
                  last_millis = millis();
                  phase = WAIT_EIN;
                  Serial.print("last LED on"); Serial.print('\t');  // Debug
                  Serial.println(millis());
                }
                break;

      case WAIT_EIN:
                if (millis()-last_millis > einzeit) {
                  last_millis = millis();
                  Warnbalken_ausschalten();
                  phase = WAIT_AUS;
                  Serial.print("ausgeschalten"); Serial.print('\t');  // Debug
                  Serial.println(millis());
                }
                break;

      case WAIT_AUS:
                if (millis()-last_millis > auszeit) {
                  last_millis = millis();
                  phase = LAUF;
                  Serial.print("neuer Lauf"); Serial.print('\t');  // Debug
                  Serial.println(millis());
                }  
                break;          
  } 
                       
}


bool Warnbalken_Lauflicht ()
{
  static unsigned long last_millis = 0;
  static byte i = 0;
  bool state = false;
  
  if (millis() - last_millis < zeiten_Warnbalken[i])  return state;
  last_millis = millis();

  digitalWrite(pin_Warnbalken[i], HIGH);      // nächste LED einschalten
  
  Serial.print(pin_Warnbalken[i]); Serial.print('\t');   // Debug
  Serial.print(i); Serial.print('\t');
  Serial.println(millis());
      
  i++;                                        // index um eins erhöhen

  if (i >= sum_leds) {                        // letzte LED eingeschalten
    i = 0;
    Serial.println("Null");
    state = true;
  }
  
  return state;
}



void Warnbalken_ausschalten()
{
  for (byte i=0; i<sum_leds; i++) {
   digitalWrite(pin_Warnbalken[i], LOW);
  }
}


void heartbeat ()
{
  static unsigned long last_millis = 0;
  static bool state = LOW;

  if (millis() - last_millis > 500) {
    last_millis = millis();
    state = !state;
    digitalWrite(LED_BUILTIN, state);
  }
}
const byte pin_Warnbalken [ANZAHL] = {30,31,32,33,34,35,36,37};                   // Pins
const unsigned int zeiten_Warnbalken [ANZAHL] = {0,250,230,210,190,170,150,130};  // Zeiten

Das geht zwar, aber ich halte es nicht für eine gute Idee Anfängern sowas beizubringen. Daten die zusammengehörigen, sollten in die gleiche Datenstruktur. Man muss nicht wie ich oben gleich eine Klasse daraus machen, aber hier wäre mindestens ein Array aus structs angebracht. Das ändert am restlichen Code nichts, und man hätte eine sinnvolle und übersichtliche Strukturierung der Daten

Doc_Arduino:
hab mir mal Gedanken gemacht.

Ich auch, zwei Kreative, zwei Lösungen, hier meine:

const byte LEDS[] = {13, 12, 11, 10, 9, 8}, ANZLEDS = sizeof(LEDS);

const unsigned long LED_interval[] = {350, 350, 350, 350, 350, 1500, 1000};
const byte ANZINT = sizeof(LED_interval) / sizeof(LED_interval[0]);
unsigned long aktMillis, blinkMillis, blinkIntervall;
byte led;

void setup ()
{
  for (byte j = 0; j < ANZLEDS; j++)
  {
    pinMode (LEDS[j], OUTPUT);
  }
}  // end of setup

void loop ()
{
  aktMillis = millis();
  if ( (aktMillis - blinkMillis) >= blinkIntervall)
  {
    blinkMillis = aktMillis;
    blinkIntervall = LED_interval[led];
    if (led < ANZLEDS)
    {
      digitalWrite(LEDS[led], HIGH);
    } else {
      for (byte j = 0; j < ANZLEDS; j++)
      {
        digitalWrite(LEDS[j], LOW);
      }
    }
    ++led %= ANZINT;
  }
}  // end of loop

Hallo,

ich staune agmue, kurzer Code und Startwartezeit der ersten LED umgangen. Das war mein Problem, deswegen benötige ich die erste 0 im Zeitenarray.

Serenifly, hast recht, mit struct gehts noch sicherer bzw. besser.

Edit:
mir fehlt im Moment der rote Faden um das struct sinnvoll einzusetzen.
Wenn ich ein struct namens led definiere

struct t_name
{
  byte pin[ANZAHL];
  unsigned int zeit[ANZAHL];
} led;

Jetzt ist das struct immer noch leer. Jetzt würde ich das über eine for Schleife mit den Werten der Pinnummer und Wartezeit füllen. Nur sehe ich aktuell dadurch keine Verbesserung. Aktuell stehe ich auf dem Schlauch. :o

struct Led
{
  const  byte pin;
  const unsigned long wartezeit;
  unsigned long zeitmerker;
  Led(const byte pin,const unsigned long wartezeit):pin(pin),wartezeit(wartezeitzeit),merker(0){}

  void tuWas(){}
};


Led leds[] = {{12,3333},{13,6666}};

ungetestet

@Doc_Arduino
Ein Array aus structs! Nicht ein struct aus Arrays. Jedes struct enthält einen Pin und eine Zeit.

@combie
Die Variante habe ich schon in #3 ausgearbeitet.

Allerdings ohne Array (vielleicht mal ergänzen :slight_smile:

Hallo,

aha, Danke, ich denke drüber nach ... :slight_smile:

Sind eure Sketche (Serenifly & combie) nicht nur einzelne LED Blinker? Also alle LEDs blinken unabhängig?
Der TO wollte laut meinem Verständnis ein Lauflicht. Oder reden wir aneinander vorbei?

Doc_Arduino:
Der TO wollte laut meinem Verständnis ein Lauflicht.

Mhhh, ich hatte mich an seinen ursprünglichen Code gehalten.

Aber da war da war ja noch das:

Irgendwie steige ich da aber nicht durch vorallem da ich den Ablauf brauche 1-6 an und dann alle aus (Pause)

Wo wir dann wieder bei Thema Zustandsautomat wären

Hallo,

“Ein Array aus structs.” Meinst du das so vom Grundaufbau?

const byte ANZAHL = 8;            // deswegen diese Konstante zur zusätzlichen Sicherheit
const byte pin_Warnbalken [ANZAHL] = {30,31,32,33,34,35,36,37};                   // Pins
const unsigned int zeiten_Warnbalken [ANZAHL] = {0,250,230,210,190,170,150,130};  // Zeiten


struct t_name
{
  byte pin;
  unsigned int zeit;
} led[ANZAHL];


void setup()
{
  Serial.begin(9600);
  for (byte i=0; i<8; i++) {
    led[i].pin = pin_Warnbalken[i];
    led[i].zeit = zeiten_Warnbalken[i];
    Serial.print(led[i].pin); Serial.print('\t');
    Serial.print(led[i].zeit);
    Serial.println();
  }
}

void loop() {
  
}

wenn ja, müsstest du mir nochmal den Vorteil bitte erklären, aktuell sehe ich keinen, nur mehr Code

Doc_Arduino:
nur mehr Code

Nur weil du die zwei alten Arrays nicht entfernt hast und das eine neue Array gar nicht verwendest

Es geht darum dass Daten die zusammengehören (wie eine Zeit und ein Pin) auch zusammenstehen und nicht an verschiedenen Stellen stehen. Das ist bei diesem Beispiel noch recht harmlos, aber hier sieht man immer wieder mal dass Leute versuchen Arrays zu verwenden (entweder mehrere oder gar mehr-dimensionale) wo Strukturen die korrekte Wahl sind.