Ampelanlage mit Arduino

Ob für die Modellbahn, LEGO oder den Schulunterricht, eine funktionierende Ampelanlage ist einfach super! Sie kann mit unter sehr komplex werden. Hier zeige ich dir, wie du die Ampelanlage einer einfachen Kreuzung mit Fußgängerampel mit Arduino aufbauen kannst.

Bauteile

  • LEDs (Dieses 500 LED-Set hab ich benutzt).
  • 10 Widerstände 220 Ohm

Schaltplan

Ampel Schaltplan

Natürlich können auch die anderen Ampeln der Anlage einfach parallel betrieben werden. Dazu bitte auch den Hinweis weiter unten beachten.

Ampel Schematische Darstellung, Schematic
Hier noch einmal als schematische Darstellung.

Hintergrund

Welche Ampelphasen gibt es denn bei so einer Ampel? Sehen wir uns die Kreuzung mal genauer an. 

Genau wie die Animation könnte man auch die Ampelanlage als Bild betrachten. Die einzelnen Lampen sind die Pixel und die sind entweder an oder aus (Bitmap). Und wie bei einer Animation ist jeder Zustand ein Frame, sozusagen ein Standbild. Welche Bilder sind das denn genau?

Links sind also die Bilder, rechts ist bereits ein Array-Code. Es ist ein Zweidimensionales Array. Wir können es genau so verwenden und müssen nur bestimmen, welcher »State« (oder Frame) gezeigt werden soll. 

Ampelphasen Kreuzung

Um nicht so viel Code schreiben zu müssen, legen wir eine extra Methode an:

void zeigeAmpelphase() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPins[i], ampelphasen[myState][i]);
  }
  delay(wartezeiten[myState]);
}

Die For-Schleife sorgt dafür, dass jede LED des Arrays ausgewertet wird. 

Da nicht jede Ampelphase gleich lang angezeigt wird, gibt es ein weiteres Array mit den Wartezeiten der jeweiligen Ampelphase. Diese wird ebenfalls in der zeigeAmpelphase()-Methode ausgewertet. 

Code

Der gesamte Code sieht so aus:

int ledPins[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

int ampelphasen[10][10] = {
  {1, 0, 0, 0, 1, 0, 0, 1, 1, 0},  // state 0
  {1, 0, 0, 1, 0, 0, 0, 1, 1, 0},  // state 1
  {1, 0, 0, 1, 0, 0, 1, 0, 1, 0},  // state 2
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 3
  {1, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 4
  {0, 0, 1, 1, 0, 1, 0, 0, 0, 1},  // state 5
  {0, 0, 1, 1, 0, 1, 0, 0, 1, 0},  // state 6
  {0, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 7
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 8
  {1, 0, 0, 1, 0, 1, 1, 0, 1, 0}   // state 9
};

int wartezeiten[10] = {5000, 2000, 500, 2000, 500, 5000, 2000, 500, 2000, 500};

int myState = 0;

void setup() {
  for (int i = 0; i < 10; i++) {     
    pinMode(ledPins[i], OUTPUT);
  }
}

void zeigeAmpelphase() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPins[i], ampelphasen[myState][i]);
  }
  delay(wartezeiten[myState]);
}

void loop() {
  zeigeAmpelphase();
  myState++;
  if (myState >= 10) myState = 0;
}

Hinweis: Ein digitaler Kanal des Arduino-Boards kann bis zu 60 mA liefern. Alle Pins zusammen sind für maximal 200 mA ausgelegt. Bei 5mm Signal-LEDs beträgt der Strom bei einem Vorwiderstand von 220 Ohm 12 – 15 mA. Es können also pro digitalen Pin 4 LEDs gleichzeitig betrieben werden und nicht mehr als 13 LEDs gleichzeitig leuchten. Ansonsten musst du eine Verstärkerschaltung einbauen.


Ampelanlage mit Anforderungstaster

Da in den Kommentaren danach gefragt wurde (danke an Ben und Mani), habe ich noch eine Version mit Anforderungstastern für die Fussgängerampeln erstellt.

Ampelanlage mit Arduino und Taster, Schalter, Anforderungstaster

Code

Um die Anforderungstaster nutzen zu können, muss der Code umgebaut werden. Der Befehl delay(); muss durch Timer-Funktionen ersetzt werden. Das habe ich hier mal im Detail erklärt: Timer mit Arduino – Die Alternative zu Delays.

Wird nun einer der Taster gedrückt und befindet sich gerade die kreuzende Fahrspur im Grün-Modus, wird die vorgesehene Fahrzeit auf 0 gesetzt und somit wird die nächste Ampelphase ausgeführt.

int ledPins[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

int button1Pin = 12;  // Fussgaengerschalter 1
int button2Pin = 13;  // Fussgaengerschalter 2

int ampelphasen[10][10] = {
  {1, 0, 0, 0, 1, 0, 0, 1, 1, 0},  // state 0
  {1, 0, 0, 1, 0, 0, 0, 1, 1, 0},  // state 1
  {1, 0, 0, 1, 0, 0, 1, 0, 1, 0},  // state 2
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 3
  {1, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 4
  {0, 0, 1, 1, 0, 1, 0, 0, 0, 1},  // state 5
  {0, 0, 1, 1, 0, 1, 0, 0, 1, 0},  // state 6
  {0, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 7
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 8
  {1, 0, 0, 1, 0, 1, 1, 0, 1, 0}   // state 9
};

long wartezeiten[10] = {5000, 2000, 500, 2000, 500, 5000, 2000, 500, 2000, 500};
int myState = 0;

long myTimer = 0;
long myTimeout = 0;

void setup() {
  for (int i = 0; i < 10; i++) {     
    pinMode(ledPins[i], OUTPUT);
  }
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
}

void zeigeAmpelphase() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPins[i], ampelphasen[myState][i]);
  }
}

void loop() {
  if (myTimer+myTimeout<millis()){
    myTimer=millis();
    myState++;
    if (myState >= 10) myState = 0;
    myTimeout=wartezeiten[myState];
    zeigeAmpelphase();
  }

  if ((digitalRead(button1Pin)==LOW)&&(myState==0)) myTimeout=0;
  if ((digitalRead(button2Pin)==LOW)&&(myState==5)) myTimeout=0;
  
  delay(10);
}

Hier noch eine alternative Version, in der die Fussgänger nach dem betätigen des Tasters noch etwas warten müssen:

int ledPins[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

int button1Pin = 12;  // Fussgaengerschalter 1
int button2Pin = 13;  // Fussgaengerschalter 2

int ampelphasen[10][10] = {
  {1, 0, 0, 0, 1, 0, 0, 1, 1, 0},  // state 0
  {1, 0, 0, 1, 0, 0, 0, 1, 1, 0},  // state 1
  {1, 0, 0, 1, 0, 0, 1, 0, 1, 0},  // state 2
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 3
  {1, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 4
  {0, 0, 1, 1, 0, 1, 0, 0, 0, 1},  // state 5
  {0, 0, 1, 1, 0, 1, 0, 0, 1, 0},  // state 6
  {0, 1, 0, 1, 0, 1, 0, 0, 1, 0},  // state 7
  {1, 0, 0, 1, 0, 1, 0, 0, 1, 0},  // state 8
  {1, 0, 0, 1, 0, 1, 1, 0, 1, 0}   // state 9
};

long wartezeiten[10] = {5000, 2000, 500, 2000, 500, 5000, 2000, 500, 2000, 500};
int myState = 0;

long myTimer = 0;
long myTimeout = 0;

void setup() {
  for (int i = 0; i < 10; i++) {
    pinMode(ledPins[i], OUTPUT);
  }
  pinMode(button1Pin, INPUT_PULLUP);
  pinMode(button2Pin, INPUT_PULLUP);
}

void zeigeAmpelphase() {
  for (int i = 0; i < 10; i++) {
    digitalWrite(ledPins[i], ampelphasen[myState][i]);
  }
}

void loop() {
  if (myTimer + myTimeout < millis()) {
    myTimer = millis();
    myState++;
    if (myState >= 10) myState = 0;
    myTimeout = wartezeiten[myState];
    zeigeAmpelphase();
  }

  if ((digitalRead(button1Pin) == LOW) && (myState == 0)) {
    myTimer = millis();
    myTimeout = 2000;
  }
  if ((digitalRead(button2Pin) == LOW) && (myState == 5)) {
    myTimer = millis();
    myTimeout = 2000;
  }

  delay(10);
}

Hast du weitere Fragen? Probier doch mal unser brandneues Forum zu Arduino aus!

15 thoughts on “Ampelanlage mit Arduino

  1. Hallo Stefan,
    vielen lieben Dank für den übersichtlichen Code, dank der vielen Array-Lösungen.
    Ich meine einen winzigen Fehler für die Startphase (state 0 ) entdeckt zu haben:
    state 0 wird beim ersten Durchlauf des Programms nicht korrekt angezeigt, erst ab dem zweiten Durchlauf. Es wundert mich allerdings, dass das bislang unbemerkt / unkommentiert blieb.

    Verbesserungvorschlag: myState erst nach gezeigter Ampelphase erhöhen:
    zeigeAmpelphase();
    myState++;
    if (myState >= 10) myState = 0;

  2. Hallo Stefan,

    ich finde deinen Sketch zur Ampelschaltung hervorragend und sehr clever gelöst! Die Schaltung funktioniert super!
    Ich habe jedoch noch eine Frage:
    Ich möchte einen Schalter einbauen, der die Fußgängerampel jederzeit von rot auf grün stellt. Wie könnte man dieses Problem mithilfe deiner Schaltung bewältigen?
    Liebe Grüße

    1. Hallo Mani,

      ich habe gerade das gleiche Anliegen und würde auch gerne einen Schalter einbauen. Doch ich weiss nicht wie das gehen sollte. Hast du es eventuell herausgefunden wie das geht?
      Mit freundlichen Grüsse

      1. So Ben und Mani, ich habe den Beitrag angepasst. Ihr findet nun eine Version mit Anforderungstastern. Bitte probiert das mal aus und sagt mir bescheid, ob das so klappt.

        Liebe Grüße

    1. Ich hab Deine Frage noch nicht ganz verstanden, aber gesehen, dass im Schaltplan noch ein Kabel zwischen er blauen Stromschiene des Breadboards zum GND (-) des Arduinos fehlt. Der (+) kommt ja sozusagen aus den digitalen Pins. Hilft dir das schon weiter? Ich ändere die Schaltung auch gleich noch. Liebe Grüße

  3. Hallo, habe die Schaltung mit dem Arduinio aufgebaut und sie funktioniert wunderbar.
    Nun möchte ich allerdings die Schaltung auf meiner Modellbahnanlage einsetzen und versuche, den Code auf einen ATTiny 4313 aufzuspielen. Es funktioniert aber nicht. Die LED`s leuchten teilweise nur konstant. Was mache ich falsch ? Oder kann man den Code nicht auf einen 4313 übertragen? Für kurze Info wäre ich dankbar.

    1. Hallo Wilfried, vielen Dank für Deine Frage. Klingt ja spannend. Ich würde mich über ein paar Fotos der Modellbahn-Ampel freuen ;-) Das Programm sollte eigentlich auch auf dem ATTiny 4313 laufen. Da passieren jetzt keine besonders verrückten Sachen im Code. Hast Du mal einen anderen ATTiny probiert? Funktioniert ein normales blink()-Programm wie erwartet?

      Liebe Grüße

      Stefan

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

 

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.