In einer Schleife trotz Blinken unterbrechen

Soweit richtig, das bekommt der Threadersteller sicher hin. Was ergänzend genannt werden sollte: Schau dir das Beispiel BlinkWithoutDelay an, du darfst deinen Code nicht blockierend schreiben. Das heißt du darfst schon, es hilft dir aber nicht bei der Lösung des Problems. :wink:

#include <IRremote.h>

const byte Recv_PIN = 11;
const byte Hp0 = 2;
const byte Hp0r = 3;
const byte Hp1 = 4;
const byte Hp2 = 5;
const byte Ra121 = 6;
const byte Ra122 = 7;
const byte Zs7 = 8;
const byte IR_Empf = 11;
//int Blink = 0;

bool blinkanforderung;

const byte ledPin = 6;
bool ledState = LOW;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
const unsigned long interval = 1000;

IRrecv irrecv (IR_Empf);
decode_results results;

/// functions ///
void setLed(bool hp0, bool hp0r, bool hp1, bool hp2, bool ra121, bool ra122, bool zs7)
{
  digitalWrite (Hp0, hp0);
  digitalWrite (Hp0r, hp0r);
  digitalWrite (Hp1, hp1);
  digitalWrite (Hp2, hp2);
  digitalWrite (Ra121, ra121);
  digitalWrite (Ra122, ra122);
  digitalWrite (Zs7, zs7);
}

////////
void setup()
{
  // put your setup code here, to run once:
  irrecv.enableIRIn ();
  Serial.begin (9600);
  pinMode (Hp0 , OUTPUT);
  digitalWrite (Hp0, HIGH);
  pinMode (Hp0r, OUTPUT);
  digitalWrite (Hp0r, HIGH);
  pinMode (Hp1, OUTPUT);
  digitalWrite (Hp1, LOW);
  pinMode (Hp2, OUTPUT);
  digitalWrite (Hp2, LOW);
  pinMode (Ra121, OUTPUT);
  digitalWrite (Ra121, LOW);
  pinMode (Ra122, OUTPUT);
  digitalWrite (Ra122, LOW);
  pinMode (Zs7, OUTPUT);
  digitalWrite (Zs7, LOW);
  pinMode (13, OUTPUT);
  digitalWrite (13, LOW);


}

void irZeugs()
{
  if (irrecv.decode(&results))
  {
    Serial.println (results.value, DEC);
    switch (results.value)
    {
      case 16750695: setLed(1, 1, 0, 0, 0, 0, 0); blinkanforderung = false; break; //0
      case 16753245: setLed(0, 0, 1, 0, 0, 0, 0); break; //1
      case 16736925: setLed(0, 0, 1, 1, 0, 0, 0); break; //2
      case 16769565: setLed(1, 0, 0, 0, 1, 1, 0); break; //3
      case 16720605: setLed(1, 1, 0, 0, 0, 0, 1); break; //4
      case 16712445: setLed(1, 0, 0, 0, 1, 0, 0); blinkanforderung = true; break; //5
      case 16756815: setLed(1, 1, 1, 1, 1, 1, 1); break; //#
      case 16738455: setLed(0, 0, 0, 0, 0, 1, 0); break; //*
      case 16748655: setLed(1, 0, 1, 0, 1, 0, 0); break; //9
    }
    irrecv.resume();
  }
}

void blinker()
{
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;
    ledState = not ledState;
  }
  digitalWrite (ledPin, ledState && blinkanforderung);
}

void loop()
{
  currentMillis = millis();
  irZeugs();
  blinker();

}

** ungetestet **

Oh Vielen Dank da war ich gerade selber auf einem Holzweg mit meinem Versuch.

 void Blink (bool Blinken)
  {
    Blinken = false;
  }

hab ich versucht :sweat_smile: hat nicht so funktioniert

Also Blinken tut es jetzt korrekt, aber
Beim Fall 3, 9 und hashtag leuchtet die LED nur kurz aus und bleibt dann aber Dunkel dort bräuchte man die LED wiederum im Dauerlicht

Tja...

So ist das , wenn ich kein Eisenbahner bin.
Und so kryptischen Bezeichner verwendet werden.....

Da wirste dann wohl noch eine Extrawurst backen müssen...

Da hast du recht ich bin gerade dabei und versuche das zu korregieren

Das ist wohl eine der Programmierer Todsünden.

Ach, nun wurde hier schon viel geschrieben, das habe ich nicht alles gelesen.

Die Notwendigkeit eines Merkers wurde ja schon erwähnt, dazu habe ich einen Vorschlag, bei dem ich mich an #5 orientiert habe:

#include <IRremote.h>

const byte Hp0 = 2;          // Rote LED
const byte Hp0r = 3;         // Rote LED
const byte Hp1 = 4;          // Grüne LED
const byte Hp2 = 5;          // Gelbe LED
const byte Ra121 = 6;        // Weiße LED
const byte Ra122 = 7;        // Weiße LED
const byte Zs7 = 8;          // Gelbe LED
const byte IR_Empf = 11;
bool blinkenRa121 = false;   // Merker für Blinken

//                                0,        1,        2,        3,        4,        5,        #,        *,        9
//constexpr uint32_t IRCODE[] = {16750695, 16753245, 16736925, 16769565, 16720605, 16712445, 16756815, 16738455, 16748655};
constexpr uint32_t IRCODE[] = {0xFF6897, 0xFF30CF, 0xFF18E7, 0xFF7A85, 0xFF10EF, 0xFF38C7, 0xFF5AA5, 0xFF42BD, 0xFF52AD}; // Car mp3 Fernbedienung

IRrecv irrecv (IR_Empf);
decode_results results;

/// functions ///
void setLed(bool hp0, bool hp0r, bool hp1, bool hp2, bool ra121, bool ra122, bool zs7, bool _blinkenRa121) {
  digitalWrite (Hp0, hp0);
  digitalWrite (Hp0r, hp0r);
  digitalWrite (Hp1, hp1);
  digitalWrite (Hp2, hp2);
  digitalWrite (Ra121, ra121);
  digitalWrite (Ra122, ra122);
  digitalWrite (Zs7, zs7);
  blinkenRa121 = _blinkenRa121;
}

void blinken (void)
{
  if (blinkenRa121)
  {
    const uint32_t INTERVALL = 500;
    uint32_t jetzt = millis();
    static uint32_t vorhin = -INTERVALL;
    if (jetzt - vorhin >= INTERVALL)
    {
      vorhin = jetzt;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }
  }
}
////////
void setup()
{
  // put your setup code here, to run once:
  irrecv.enableIRIn ();
  Serial.begin (9600);
  Serial.println ("\nStart");
  pinMode (Hp0 , OUTPUT);
  digitalWrite (Hp0, HIGH);
  pinMode (Hp0r, OUTPUT);
  digitalWrite (Hp0r, HIGH);
  pinMode (Hp1, OUTPUT);
  digitalWrite (Hp1, LOW);
  pinMode (Hp2, OUTPUT);
  digitalWrite (Hp2, LOW);
  pinMode (Ra121, OUTPUT);
  digitalWrite (Ra121, LOW);
  pinMode (Ra122, OUTPUT);
  digitalWrite (Ra122, LOW);
  pinMode (Zs7, OUTPUT);
  digitalWrite (Zs7, LOW);
  pinMode (13, OUTPUT);
  digitalWrite (13, LOW);
}

void loop() {
  blinken();

  if (irrecv.decode(&results))
  {
    uint32_t fbcode = results.value;
    Serial.print(fbcode, HEX); Serial.print ('\t'); Serial.println (fbcode, DEC);
    switch (fbcode)
    {
      case IRCODE[0]: //0
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 1, 0, 0, 0, 0, 0, 0);
        break;

      case IRCODE[1]: //1
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(0, 0, 1, 0, 0, 0, 0, 0);
        break;

      case IRCODE[2]: //2
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(0, 0, 1, 1, 0, 0, 0, 0);
        break;

      case IRCODE[3]: //3
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 0, 0, 0, 1, 1, 0, 0);
        break;

      case IRCODE[4]: //4
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 0, 0, 0, 1, 0, 0, 0);
        break;

      case IRCODE[5]: //5
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 0, 0, 0, 0, 0, 0, 1);
        break;

      case IRCODE[6]: //#
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 1, 1, 1, 1, 1, 1, 0);
        break;

      case IRCODE[7]: //*
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(0, 0, 0, 0, 0, 1, 0, 0);
        break;

      case IRCODE[8]: //9
        // Hp0, Hp0r, Hp1, Hp2, Ra121, Ra122, Zs7, blinkenRa121
        setLed(1, 0, 1, 0, 1, 0, 0, 0);
        break;
    }
    irrecv.resume();
  }
}

Das Feld IRCODE[] habe ich eingeführt, um schneller zwischen Deiner und meiner Fernbedienung wechseln zu können.

Ob ein Lokführer damit glücklich wäre, weiß ich nicht, aber Leuchten tut etwas, Blinken auch.

EDIT: Funktion blinken() hinsichtlich Blinkzeit verändert: vorhin = jetzt;

Da hasste aber dem Nachtwächter eine Falle gestellt...

:japanese_ogre:

Was du da an die Funktion übergibst wird in die lokale Variable Blinken kopiert. Was du dann darin veränderst ist Außen nicht sichtbar. Stichwort "call by value"

Außerdem ist es in diesem Fall generell etwas übertrieben dafür eine Funktion zu schreiben. Sowas macht man bei Klassen. Aber aus anderen Gründen

Zur Info!


Das wollte ich nicht, habe ich mir was falsch gemerkt?

Sonst habe ich das immer so gemacht:

    if (jetzt - vorhin >= INTERVALL)
    {
      vorhin = jetzt;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }

Das wurde mir aber als ungenau angekreidet, daher die neue Variante. Da das Programm funktioniert, wo könnte der Nachtwächter stolpern?

Wie ist es denn nun richtig?

Naja....
Es wird der Zeitpunkt etwas verschleppt, aber ob das hier wichtig ist....


if (jetzt - vorhin >= INTERVALL)
    {
      vorhin += INTERVALL;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }

Das unterbindet die Verschleppung(so gut es geht).
Ich nenne es den Aufholtimer, eben, weil er Zeitverluste wieder aufholt.
Zumindest addieren sich verlorene Millis nicht auf.


Weiß nicht...
Durch die Addition der Zeiten, fängst du dir einen Überlauf ein, welcher dir nach 49,x Tagen einen Stock in die Speichen schiebt.

Natürlich nicht, aber ich würde mir gerne nur eine Variante merken, die in den meisten Fällen funktioniert.

Da ich Deine Variante auf die Schnelle nicht zum Laufen bekomme, falle ich zunächst auf die Verschleppungs-Variante zurück. Das ändere ich in #27.

Aber ich melde mich :roll_eyes:

Meine Timer basieren auch alle auf der "Verschleppungsmethode" bzw. dem Nachtwächter
.
Das andere Verfahren wende ich nur an, wenn muss.

Das genaueste geht halt nur mit Hardwaretimern.


Das wundert mich....

Da #27 als Lösung markiert wurde, werde ich nun hemmumgslos hier weitermachen :blush:

Mich erst. Ich werde versuchen, es Dir deutlich zu machen.

Die Verschleppungsvaraiante:

void blinken (void)
{
  if (blinkenRa121)
  {
    const uint32_t INTERVALL = 500;
    uint32_t jetzt = millis();
    static uint32_t vorhin = -INTERVALL;
    if (jetzt - vorhin >= INTERVALL)
    {
      Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
      vorhin = jetzt;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }
  }
}

Monitor:

17:25:14.737 -> Start
17:25:21.544 -> 6805	4294966796
17:25:22.046 -> 7305	6805
17:25:22.547 -> 7805	7305
17:25:23.049 -> 8305	7805
17:25:23.551 -> 8805	8305
17:25:24.052 -> 9305	8805
17:25:24.554 -> 9805	9305
17:25:25.050 -> 10305	9805
17:25:25.535 -> 10805	10305
17:25:26.032 -> 11305	10805
17:25:26.533 -> 11805	11305
17:25:27.035 -> 12305	11805
17:25:27.536 -> 12805	12305
17:25:28.038 -> 13305	12805
17:25:28.540 -> 13805	13305
17:25:29.041 -> 14305	13805
17:25:29.543 -> 14806	14305
17:25:30.071 -> 15306	14806
17:25:30.572 -> 15806	15306
17:25:31.074 -> 16306	15806
17:25:31.574 -> 16806	16306

So weit so bekannt.

Nun die Variante ohne Verschleppung:

void blinken (void)
{
  if (blinkenRa121)
  {
    const uint32_t INTERVALL = 500;
    uint32_t jetzt = millis();
    static uint32_t vorhin = -INTERVALL;
    if (jetzt - vorhin >= INTERVALL)
    {
      Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
      vorhin += INTERVALL;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }
  }
}
17:29:51.583 -> Start
17:30:02.967 -> 11386	4294966796
17:30:02.967 -> 11387	0
17:30:03.021 -> 11388	500
17:30:03.021 -> 11388	1000
17:30:03.021 -> 11389	1500
17:30:03.021 -> 11389	2000
17:30:03.068 -> 11397	2500
17:30:03.068 -> 11409	3000
17:30:03.068 -> 11421	3500
17:30:03.068 -> 11433	4000
17:30:03.121 -> 11447	4500
17:30:03.121 -> 11459	5000
17:30:03.121 -> 11471	5500
17:30:03.121 -> 11484	6000
17:30:03.168 -> 11496	6500
17:30:03.168 -> 11509	7000
17:30:03.168 -> 11522	7500
17:30:03.168 -> 11534	8000
17:30:03.222 -> 11546	8500
17:30:03.222 -> 11558	9000
17:30:03.222 -> 11571	9500
17:30:03.222 -> 11584	10000
17:30:03.268 -> 11597	10500
17:30:03.268 -> 11611	11000
17:30:03.569 -> 12000	11500
17:30:04.071 -> 12500	12000
17:30:04.573 -> 13000	12500
17:30:05.074 -> 13500	13000
17:30:05.576 -> 14000	13500
17:30:06.077 -> 14500	14000
17:30:06.579 -> 15000	14500
17:30:07.080 -> 15500	15000

Hier stimmt wohl der Startwert nicht, da vorhin zunächst den aktuellen Zeitwert einholen muß. Das ergibt ein paar ungewollte Durchläufe der Funktion, die immer den Ausgang umschaltet.

Ein neuer Versuch mit Änderungsmerker:

void blinken (void)
{
  const uint32_t INTERVALL = 500;
  uint32_t jetzt = millis();
  static uint32_t vorhin;
  static bool altblinkenRa121 = blinkenRa121;
  if (altblinkenRa121 != blinkenRa121)
  {
    altblinkenRa121 = blinkenRa121;
    vorhin = jetzt - INTERVALL;
  }
  if (blinkenRa121)
  {
    if (jetzt - vorhin >= INTERVALL)
    {
      Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
      vorhin += INTERVALL;
      digitalWrite (Ra121, !digitalRead(Ra121));
    }
  }
}

Monitor:

17:44:17.077 -> Start
17:44:25.407 -> 8335	7835
17:44:25.909 -> 8835	8335
17:44:26.410 -> 9335	8835
17:44:26.912 -> 9835	9335
17:44:27.414 -> 10335	9835
17:44:27.915 -> 10835	10335
17:44:28.417 -> 11335	10835
17:44:28.918 -> 11835	11335

Die PC-Uhr scheint nicht synchron mit dem UNO, aber bezogen auf millis() könnte es so stimmen. Aber was passiert in 49 Tagen?

17:50:03.066 -> Start
17:50:03.715 -> 4294962981	4294962481
17:50:04.216 -> 4294963481	4294962981
17:50:04.718 -> 4294963981	4294963481
17:50:05.220 -> 4294964481	4294963981
17:50:05.721 -> 4294964981	4294964481
17:50:06.223 -> 4294965481	4294964981
17:50:06.724 -> 4294965981	4294965481
17:50:07.226 -> 4294966481	4294965981
17:50:07.727 -> 4294966981	4294966481
17:50:08.229 -> 185	4294966981
17:50:08.731 -> 685	185
17:50:09.232 -> 1185	685
17:50:09.734 -> 1685	1185
17:50:10.235 -> 2185	1685
17:50:10.737 -> 2685	2185
17:50:11.243 -> 3185	2685
17:50:11.745 -> 3685	3185

@combie: Bist Du so einverstanden?

Weiß nicht....
Mir ist das schon fast zu kompliziert.....

z.B. irritiert mich ein wenig, dass du if (jetzt - vorhin >= INTERVALL) hinter einem if versteckst.
Das bedingt dann wohl, dass du die Zeiten zurechtmogeln willst
--> vorhin = jetzt - INTERVALL;

Irgendwie habe ich wohl noch nicht verstanden, was du "wirklich" erreichen möchtest....

Hallo,

das if (jetzt - vorhin >= INTERVALL) ist doch korrekt.
Das entspricht if (millis() - lastMillis >= INTERVALL)
Nur die Subtraktion mit vorhin darüber ist Unsinn. Das bringt alles durcheinander.

void blinken (void)
{
  const uint32_t INTERVALL {500};
  uint32_t jetzt {millis()};
  static uint32_t vorhin {0};
  
  if (jetzt - vorhin >= INTERVALL)
  {
    Serial.print(jetzt); Serial.print ('\t'); Serial.println (vorhin);
    vorhin += INTERVALL;
  }
}

Die Unterscheidung zwischen ohne oder mit "Verschleppung" ist nur davon abhängig was man genau möchte. Möchte man ein genaues Intervall unabhängig des Aufrufzeitpunktes einhalten. Oder möchte man den zeitlichen Aufrufabstand auf eine Mindestzeit festlegen. Mehr ist das nicht.

Edit:
Vielleicht so besser was agmue laut meiner Glaskugel testen möchte.

void blinken (void)
{
  const uint32_t INTERVALL {500};
  uint32_t jetzt {millis()};
  static uint32_t vorhin {0};
  
  if (jetzt - vorhin >= INTERVALL)
  {
    Serial.print(jetzt); Serial.print('\t'); Serial.print(vorhin); Serial.print('\t');
    vorhin += INTERVALL;
    Serial.println(vorhin);
  }
}

Für mich tun sich mehrere Themen auf, "was ist der Unterschied" ist hiermit schon beantwortet:

Hier kann ich nicht zustimmen:

Bei kurzen Intervallen fällt es nicht auf, doch die Zeit zwischen Reset und INTERVALL bedarf einer speziellen Betrachtung.

Später nach Reset ist jetzt - vorhin >= INTERVALL wahr, wenn die Bedingung zum Blinken erfüllt ist. Die LED wird also sofort umgeschaltet.

In der Zeit zwischen Reset und INTERVALL ist die Bedingung aber nicht erfüllt, weshalb die LED erst nach der Zeit INTERVALL umschaltet.

Gegenmaßnahme ist, jetzt in die Vergangenheit zu verlegen. Mittels static uint32_t vorhin = -INTERVALL; von einer vorzeichenlosen Variablen etwas abzuziehen ist meine Lösung.

Die auch völlig legitim und richtig ist.

Gruß Tommy

Wenn ich das mal ein wenig abstrahiere, dann gibt es 2 Varianten, das Intervall abzuhandeln. Einmal den Aufholtimer und den verschleppenden.

Es gibt 2 mögliche Aktionszeitpunkte. Einmal vor dem Intervall und einmal danach

Somit sind es 4 mögliche Timer Varianten.


Das waren in etwa meine Gedanken, als ich meine(n) Timer entworfen habe.
Sie scheinen auch hier zuzutreffen.
Nach langem prüfen, habe ich mich dazu entschlossen den verschleppenden zu wählen. Zudem die Aktion nach dem Intervall.
z.B. der CombieTimer ist per default, auf stehend/inaktiv, als abgelaufen konfiguriert.

Damit lassen sich die wichtigsten Anwendungen abdecken.
In den meisten Fällen, ist es nicht schlimm, wenn es etwas verschleppt.
Auch der Fall, dass die Aktion bei Intervall Start stattfinden soll, geht damit.

Das ist etwas, was mich stört.
Nicht , dass es falsch wäre, in der Form, dass es Probleme macht, aber "emotional" werde ich damit nicht fertig. Für mich haben sich millis, in jeder Form, an die Kausalität zu halten.
Keine Zeit Sprünge rückwärts.
Wie gesagt, keine technische, sondern eine emotionale Hürde für mich, das zuzulassen, oder dem zuzustimmen.

Eins meiner Beispiele
Die Task blink() führt die Aktion vor dem Intervall durch
Task showLoops() nach dem Intervall

#include <TaskMacro.h>


/**
 * Auf Tastendruck wird 5 mal geblinckt 
*/




const byte taster            = 4;   // Taster zwischen Pin und GND
const byte led               = 13;  // Led zwischen Pin und GND
const unsigned long interval = 500; // ms
const byte zyklen            = 5;   // Anzahl Blinker

bool blinkAnforderung        = false; // Merker für Blink Anforderung

Task blink() 
{
  static byte i = 0;  // Wiederholungszaehler
  taskBegin();
  while(1)
  {
    taskWaitFor(blinkAnforderung);
    for(i=0;i<zyklen;i++)
    {
      digitalWrite(led, HIGH); // leuchte an
      taskPause(interval);
      digitalWrite(led, LOW); // leuchte aus
      taskPause(interval);
    }
    blinkAnforderung = false ; // Anforderung konsumieren
  }
  taskEnd();
}


Task tastenAuswertung() 
{
  taskBegin();
  while(1)
  {
    taskWaitFor(!digitalRead(taster));
    blinkAnforderung = true;
  }  
  taskEnd();
}


Task showLoops()
{
  static unsigned long loops = 0;
  loops++;
  taskBegin();
  for(;;)
  {
    taskPause(1000);
    Serial.print("Loops pro Sekunde: ");
    Serial.println(loops);
    loops = 0;
  }
  taskEnd();
}




void setup()
{
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(taster,INPUT_PULLUP);
}

void loop()
{
  blink();
  tastenAuswertung();
  showLoops();
}

Vergleichbares geht auch mit den Datenflussorienten CombieTimer.

Auch das INTERVAL Makro hat diese Erweiterung bekommen, sofort mit der Aktion zu starten, in dem man ihm eine Startzeit mitgibt.

INTERVAL(500) macht nach 500ms die erste Aktion, danach alle 500ms
INTERVAL(500,2000) macht nach 2s die erste Aktion, danach alle 500ms
INTERVAL(500,0) macht sofort die erste Aktion, danach alle 500ms

Alles ohne Zeit Sprung rückwärts.
Man kann also schon dem Zeitparadox aus dem Weg gehen.

Danke, dann bin ich ja nicht vollkommen auf dem Holzweg :slightly_smiling_face:

Gut, für blinkende LEDs werde ich diese Variante beibehalten.

Da stimme ich Dir zu!

Das ist genau das, wonach Anfänger suchen. Nur kann ich die CombieTimer leider nicht erklären, weshalb ich sie vorsichtshalber nicht verwende.

Wer kann, der kann :wink:

Wer nicht kann, muß sich mit der Nichtlinearität der Zeit trösten. Aber das ist ein ganz anderes Thema und für blinkende LEDs glücklicherweise wenig relavant.

Danke an Alle, die mir ermöglicht haben, wieder etwas klarer in den Programmiernebel zu schauen!

@primehgn: Danke, daß Du mich hast machen lassen :slightly_smiling_face: