Montag, 20. Mai 2013

Lange While?

Mein Arduino Code zur Ampelschaltung war, wie ich schon erwähnte, nicht der Eleganteste. Zu allem Überfluss war er sogar fehlerhaft. ;)

Als ich den Code säuberte und passende Stellen zu einer While-Schleife umbaute, fiel mir auf, dass die Logik nicht ganze passte. Die Abfrage der verstrichenen Zeit grenzte die einzelnen Ampelphasen überhaupt nicht eindeutig ab.

Die überprüfung der Phase fand nur mit einer "ist die Differenz von millis() - Zeitstempel größer als Pause?" statt. Und im nächsten Fall: "ist die Differenz von millis() - Zeitstempel größer als Pause + Pause?" Hier schlägt nun wieder einmal die Endlosschleife zu, denn wenn:

"ist die Differenz von millis() - Zeitstempel größer als Pause + Pause?"

 zutrifft, dann trifft natürlich auch die vorherige Phase zu:

"ist die Differenz von millis() - Zeitstempel größer als Pause?"

es werden also nochmal beide Phasen ausgeführt. Durch die Trägheit der LEDs war das aber nicht wirklich zu sehen. Die LEDs wirkten zwar als wäre sie aus aber die "glimmten" noch ein bisschen. ;)

Meine Logik damit das verhindert wird ist jetzt:

"ist die Differenz von millis() - Zeitstempel größer als Pause?" UND "ist die Differenz von millis() - Zeitstempel kleiner als Pause + Pause?"

Jetzt glimmt nix mehr!

Bitteschön:

/*

Ampel mit While

 */

// reichen da nicht bytes? oO
byte red = 9; // Verkehrsampel Rot
byte yel = 8; // Verkehrsampel Gelb
byte gre = 7; // Verkehrsampel Grün
byte sig = 5; // "Signal kommt" liefert dem Fußgänger zurück, ob er gedrückt hat oder nicht.
byte wred = 3; // Fußgängerampel Rot
byte wgre = 2; // Fußgängerampel Grün
byte but = 6; // Button Pin
byte safe = 0; // war butr für buttonread

// Pausen
int pred = 3000; // 3 Sekunden Rot
int pyel = 1000 ; // 1 Sekunde Gelb
int pgre = 5000; // 5 Sekunden Grün
int psafety = 1000; // Puffer für Fußgänger, bis Verkehrsampel wieder auf grün springt
unsigned long time;

// the setup routine runs once when you press reset:
void setup() {
  // die pins als output.
  pinMode(red, OUTPUT);
  pinMode(yel, OUTPUT);
  pinMode(gre, OUTPUT);
  pinMode(sig, OUTPUT);
  pinMode(wred, OUTPUT);
  pinMode(wgre, OUTPUT);
  pinMode(but, INPUT);
  time = millis(); // einmal die aktuelle Zeit festlegen
  digitalWrite(red, HIGH); // erstmal alles schön auf Rot
  digitalWrite(wred, HIGH); // erstmal alles schön auf Rot
}

// the loop routine runs over and over again forever:
void loop() {

   /* 
   Wenn der Button etwas anderes als 0 zurück gibt hat
   ihn wohl jemand gedrückt. Wenn das so ist, setze
   safe auf 1 und schalte die "Signal kommt" LED an.
   */
   
if(digitalRead(but) != 0)
{
  safe=1;
  digitalWrite(sig,HIGH);
}

   /*
   Solange wie safe kleiner oder gleich 1 ist,
   läuft die Verkehrsampel.
   */

while (safe <= 1)
    {
     digitalWrite(wred, HIGH); // Fußgängerampel auf Rot und bleibt auch so
     
     /*
     Nun vergleichen wir immer Schritt für Schritt, ob die abgelaufene Zeit
     GRÖßER ist als für diese Phase vorgesehen ABER AUCH ob sie bis jetzt
     noch UNTER der Zeit der übernächste Phase liegt.
     */
     
     if (millis() - time > pred && millis() - time < pred + pyel)digitalWrite(yel,HIGH); // LÄNGER als Pause Rot aber KÜRZER als Pause Rot + Pause Gelb? -> schalte Gelb dazu.
     if (millis() - time > pred + pyel && millis() - time < pred + pyel + pgre)  // LÄNGER als Pause Rot + Pause Gelb aber KÜRZER als Pause Rot + Pause Gelb + Pause Grün?
     {
      digitalWrite(red,LOW); // schalte Rot aus
      digitalWrite(yel,LOW); // schalte Gelb aus
      digitalWrite(gre,HIGH); // schalte Grün an
     }
     if (millis() - time > pred + pyel + pgre && millis() - time < pred + pyel + pgre + pyel) // LÄNGER als Pause Rot + Pause Gelb + Pause Grün aber KÜRZER als Pause Rot + Pause Gelb + Pause Grün + Pause Gelb
     {
      digitalWrite(gre,LOW); // schalte Grün aus
      digitalWrite(yel,HIGH); // schalte Gelb an
     }
     if (millis() - time > pred + pyel + pgre + pyel) // Hier prüfen wir nur noch obs länger ist als... denn die Anderen schließen sich ja schon vorher aus.
     {
      digitalWrite(yel,LOW); // schalte Gelb aus
      time = millis(); // Zeit reseten
      digitalWrite(red,HIGH); // schalte Rot an
      if (safe == 1)safe++; // Falls jemand den Knopf gedrückt hatte und safe damit auf 1 steht, ist es Zeit zur Fußgänger Schleife zu springen. Dazu erhöhren wir safe um 1 also auf 2.
     }
    break; // raus aus der while Schleife
    }

while (safe == 2) // wenn der Knopf gedrückt wurde (safe = 1) UND der Verkehr einmal durchlief (safe = 1 + 1) dann mache...
    {
      digitalWrite(red, HIGH); // Verkehrsampel auf Rot.. sollte sie zwar schon, aber doppelt hält besser. Geht ja schließlich um die Sicherheit ;)
      if (millis() - time > psafety && millis() - time < psafety + pgre) // LÄNGER als Sicherheitspuffer aber KÜRZER als Sicherheitspuffer + Pause Grün?
      {                                      // falls dem so ist...
        digitalWrite(wred,LOW); // Fußgänger Rot aus
        digitalWrite(sig,LOW); // "Signal kommt" aus
        digitalWrite(wgre,HIGH); // Fußgänger Grün an
      }
      if (millis() - time > psafety + pgre && millis() - time < psafety + pgre + psafety) // LÄNGER als Sicherheitspuffer + Pause Grün aber KÜRZER als Sicherheitspuffer + Pause Grün + Sicherheitspuffer?
      {                                    // falls ja
        digitalWrite(wgre,LOW); // Fußgänger Grün aus
        digitalWrite(wred,HIGH); // Fußgänger Rot an
      }
      if (millis() - time > psafety + pgre + psafety) // Wenn wieder Rot ist, warte noch die Safety Zeit ab (Safety + Grünphase + Safety)
        {
         time = millis(); // Und resete die Zeit, damit es von vorn los gehen kann
         safe = 0; // Setzte Safe auf 0 damit wieder mind. 1x der Vekehr läuft
        }
        break; // raus aus der Schleife
  }
delay(1); // kleine Pause gg. Überlastung
}

Kommentare:

  1. Schicker Hintergrund! *____*

    AntwortenLöschen
  2. ist das denn safe, jedes mal millis() aufzurufen? ist mir jetzt nur beim ueberfliegen aufgefallen. wenn du also sowas machst wie
    if (millis() - time > psafety && millis() - time < psafety + pgre)
    dann kann es passieren, dass millis() natuerlich zwei mal unterschiedliche rueckgabewerte hat.

    AntwortenLöschen
  3. Stimmt. Aber da wir uns Zeittechnisch im ms Bereich bewegen und der "aber kleiner als" Teil mindestens eine ganze Sekunde drauf gebrummt bekommt, sollte es immer passen. Aber sauber ist es nicht.

    AntwortenLöschen