2 kleine Probleme mit einer Ampelsteuerung (Interruptsteuerung / Timer im Inte.)

Hey Leute,

ich hoffe man kann mir bei meinem Problem ein wenig helfen. Mit dem unten stehenden Code möchte ich eine einfache Ampelsteuerung gestalten. Im großen und ganzen läuft an sich alles wie geplant. Nur 2 Probleme gibt es noch:

  1. Wenn der Interrupt verlassen wird, möchte ich eine gewisse Ausgangssituation hervorrufen. Also einfach gesagt, es soll die Grüne Lampe leuchten und warten bis Taster gedrückt wurde und die Funktion wieder normal aufgerufen wird.

  2. Die Delay - Zeit im Interrupt musste ich mächtig hoch setzen um 3 Sekunden zu erhalten, was normal ein Wert von 3.000 bedeutet, doch diesmal musste ich 30.000 eingeben, gibt es dafür einen Grund?

int interrupcion = 0;            // Interrupttaster für Aufrufen der "Störrungsfunktion" Gelbes blinken

int gruenPin = 4;                // Grüne LED
int gelbPin = 6;                 // Gelbe LED
int rotPin = 8;                  // Rote LED
int taster = 3;                  // Fußgängertaster
int buttonState = 0;

volatile int numInterrupt = 0;

void setup() {
  pinMode(gruenPin, OUTPUT);
  pinMode(gelbPin, OUTPUT);
  pinMode(rotPin, OUTPUT);
  pinMode(taster, INPUT);
  digitalWrite(taster, HIGH);
  digitalWrite(gruenPin, HIGH);
  attachInterrupt(interrupcion, funcionInterrupcion, LOW);
  Serial.begin(9600);
  
}

void loop() {
  Serial.println("taster");
  buttonState = digitalRead(taster);
  
  if (buttonState == LOW) {
    ampel();
  }
}
  
void ampel() {                      // Ampelfunktion wenn Fußgänger Knopf drückt
  delay(1500);
  digitalWrite(gelbPin, HIGH);
  digitalWrite(gruenPin, LOW);
  delay(1500);
  digitalWrite(rotPin, HIGH);
  digitalWrite(gelbPin, LOW);
  delay(5000);
  digitalWrite(gelbPin, HIGH);
  delay(1500);
  digitalWrite(gruenPin, HIGH);
  digitalWrite(rotPin, LOW);
  digitalWrite(gelbPin, LOW); 
}

void funcionInterrupcion() {          // Störungsfunktion bei Ausfall der Ampelsteuerung [simuliert] (Gelbes Licht Blinkt)
  Serial.print("Interrupt numero ");
  Serial.println(numInterrupt);
  numInterrupt++;
  digitalWrite(rotPin, LOW);
  digitalWrite(gruenPin, LOW);
  digitalWrite(gelbPin, HIGH);
  delay(30000);
  digitalWrite(gelbPin, LOW);
  delay(30000);
}

Danke schonmal für Eure Hilfe. Ich hoffe die einfachen Kommentare reichen um einfach durch zu blicken.

Der Code selbst soll auch nur für eine Einfache Ampel sein für nen Junior meines Bekannten. Also muss nicht 100% real sein.

Michael

Um Taster einzulesen braucht man keine Interrupts. Wenn die Taster nicht per Hardware entprellt sind geht das auch nicht richtig da sie prellen.

In Interrupts geht kein delay() weil diese Funktion auf einen Timer Interrupts angewiesen ist. Serial Ausgaben funktionieren auch nicht richtig, da die Ausgabe selbst interruptgesteuert ist. delay() widerspricht auch dem Sinn von Interrupts. Die sollen das Programm nur kurz unterbrechen und den Ablauf möglichst wenig stören

Schau dir millis() und das BlinkWithoutDelay Beispiel an um zu sehen wie man Zeiten behandeln kann ohne einfach nur zu Warten und damit das Programm anzuhalten.

Endlicher Automat, Zustandsautomat, bzw. Finite State Machine sind andere Stichwörter wie man das einfach lösen kann.

Zum Thema Ampelsteuerung gibt es hier schon recht viele und auch gute Lösungen. Zwei davon haben Kollege "agmue" und ich vor gut einem Jahr geschaffen. Einmal in OOP, einmal prozedural. Schau dir mal folgende Seite an und teste die Beispiele. Dort ist auch das Entprellen der Buttons ohne Interupt zu finden:

Welchen Arduino hast Du?
Ich hoffe einen mit ATmega32U4 wie den Leonardo da Du ansonsten den Taster an den falschen Pin angeschlossen hast.
Die Betätigungen der Tasten sind soooo langsam daß es keinen Interrupt braucht. Es braucht nur einen Sketch der die Zeiten mit millis() macht anstattt delay(). Außerdem ist es extrem schwierig in einer Interruptroutine den Tasters zu entprellen.

Grüße Uwe

Es ist nur ein Nano,

aber naja das mit dem Interrupt klappt ja wie gewollt. Nur wenn Ereigenis nicht mehr ansteht was zu dessen auslösen führt, beendet er die Interruptaufgabe und hängt irgendwo dran.

Aber ich werde es nochmal umkalkulieren bzw. bisschen umplanen. Dann kann ich wo möglich auf Interrupt verzichten.

Michael

Der Nano hat die serielle Schnittstelle an den pins D0 ind D1 und die Interrupteingänge an D2 (Interrupt 0) und D3 Intterupt 1).

Du hast nichts an Pin D2 angeschlossen und so wird der Interrupt zufällig durch Störungen ausgelöst.
https://www.arduino.cc/en/Reference/AttachInterrupt

Grüße Uwe

nochmal umkalkulieren bzw. bisschen umplanen

Versuche besser einen komplett anderen Ansatz:

Wenn du Taster in loop() einliest (was gut ist), darfst du nicht mehrere delays von mehreren Sekunden Dauer verwenden. (Während eines delays wird der Taster ignoriert.)
delay() ist gut für manche kleine Demos, oder für Entprell-Zeiten von wenigen Millisekunden. Aber nicht für Ablaufsteuerungen.

loop() ist nicht der Programm-Ablauf, sondern die Beschreibung was in jedem Moment passiert.
loop dauert keine Zeit und kommt unendlich oft dran. Ganz selten wird erkannt, dass ein Taster betätigt wurde, und wenn die passende Zeit reif ist, wird eine andere LED eingeschaltet. Aber meist passiert einfach nichts, weil 16 MHz wahnsinnig schnell ist für solch eine Aufgabe. Dann kann beliebig viel parallel und unabhängig ablaufen.

BlinkWithoutDelay ist der erste Schritt, das solltest du verstehen und verinnerlichen :wink:

Da wie bei BlinkWithoutDelay loop() andauernd neu drankommt, muss bei deiner Ampel neben der Zeit der letzten Änderung auch der aktuelle Zustand gemerkt werden. Das wird hier gern "endlicher Automat" genannt. ( finite state machine, wenn du dich weltweit darüber unterhalten willst )