Modellbahn Hausbeleuchtung

Sicherlich keine der anspruchvollsten Aufgaben, aber vielleicht kann es ja jemand brauchen.

Um eine abwechslungsreiche Beleuchtung von Modellhäusern hinzubekommen, sollen verschiedene Lampen hinter Fenstern an- und ausgehen, um anzudeuten, wo die Bewohner gerade sind. Das ist mit dem Programm realisiert. Zusätzlich gibt es 2 Ausgänge die LEDs unterschiedlich flackern lassen (für Fernsehn, Schweißlicht o.a). Ein weiterer Ausgang steuert ein Blinklicht. Der Rest sind 10 Ausgänge um Lampen in (verschiedenen) Häusern/Zimmern beleuchten zu können.

Um die LEDs an- und auszuschalten gibt es 2 Felder: LOW_Ablauf (Flackern1,Flackern2,Blinken1,Zimmer 1-5), HIGH_Ablauf (Zimmer 6-10). Soll eine Lampe eingeschaltet werden, wird das Bit gesetzt. Soll die Lampe ausgehen, wird das Bit gelöscht.
Sollen mehr als 8 Stufen durchlaufen werden, muss die Variable geändert werden.

Über ein Angeschlossenes Potentiometer lässt sich die Ablaufgeschwindigkeit von 200ms bis ca. 10 Sekunden pro Takt verändern. Die Flacker- und Blinkgeschwindigkeiten sind davon nicht beeinflusst.
Der Taster lässt alle angeschlossenen Lampen aufleuchten. So ist schnell zu prüfen, ob noch alle Lampen funktionieren.

Im Anhang gibt es den Schaltplan.

Hier ein kleines Video vom fertigen Resultat. YouTube

// UNBEDINGT VOR DEM AUFSPIELEN DES CODES IN DEN ARDUINO DIE DIGITAL PINS 0 (RX) UND 1 (TX) FREILASSEN. ERST DANACH DIE KABEL ANSCHLIEßEN!
/*
  Schaltet die Beleuchtung für ein Haus
  in Abhängigkeit von der am Poti eingestellten Geschwindigkeit.
  Die Flacker- und Blinkgeschwindigkeit bleibt immer gleich.
  Wenn Taster auf HIGH gezogen wird, werden alle Lampen eingeschaltet
 */
const int FlackerDelay = 100; // Flackern in 100ms
const int CFlackern1 = 30301; // Muster1 um das Flackern an- und auszustellen
const int CFlackern2 = 28021; // Muster2
const int CBlinker1 =  255; // Blinker-Muster

unsigned long Zeit; // speichert die Zeit zu Anfang des Durchlaufs
unsigned long aktuelleZeit; // liefert die aktuelle Zeit zurück

int ledDelay; // Zeit zwischen den Durchläufen
int Poti = 2; // Potentionmeter für den ledDelay ist an AnalogPin 2 angeschlossen
int Taster = 13; // Taster auf DigitalPin 13

// ******************************************
// Ablauf
// Hier steht wann, was eingeschaltet wird in Binärformat
// Zimmer10|
const byte AblaufAnzahl = 8; // speichert aus wie vielen Einzelschritten ein Ablauf besteht

// Zimmer5||Zimmer4|Zimmer3|Zimmer2|Zimmer1|Blinker1|Flackern2|Flackern1
byte LOW_Ablauf[] = {B00001111,B00010111,B00100111,B01000111,
                     B01000111,B00100111,B00010111,B00001111}; // B = Binär
// Zimmer10|Zimmer9|Zimmer8|Zimmer7|Zimmer6
byte HIGH_Ablauf[] = {B11111,B11111,B11111,B11111,
                      B11111,B11111,B11111,B11111}; // B = Binär                 
// Ende Ablauf
// ******************************************
// *** Block 1 ***
// Flackern
int Flackern1 = 0; 
int Flackern2 = 1;
// Blinker
int Blinker1 = 2;
// Lampen
int Zimmer1 = 3;
int Zimmer2 = 4;
int Zimmer3 = 5;
int Zimmer4 = 6;
int Zimmer5 = 7;
// ***Block 2 ***
int Zimmer6 = 8;
int Zimmer7 = 9;
int Zimmer8 = 10;
int Zimmer9 = 11;
int Zimmer10 = 12;

byte FlackernDurchlauf = 0; // speichert in welchen Durchlauf das Fernsehflackern ist


void setup() // Hauptschleife
{                
  // Pins werden auf Output geschaltet
  pinMode(Flackern1, OUTPUT);
  pinMode(Flackern2, OUTPUT);
  pinMode(Blinker1, OUTPUT);
  pinMode(Zimmer1, OUTPUT);
  pinMode(Zimmer2, OUTPUT);
  pinMode(Zimmer3, OUTPUT);
  pinMode(Zimmer4, OUTPUT);
  pinMode(Zimmer5, OUTPUT);
  pinMode(Zimmer6, OUTPUT);
  pinMode(Zimmer7, OUTPUT);
  pinMode(Zimmer8, OUTPUT);
  pinMode(Zimmer9, OUTPUT);
  pinMode(Zimmer10, OUTPUT);
  // Pins werden auf INPUT geschaltet
  pinMode(Taster,INPUT);
  digitalWrite(Taster,LOW); // Pull Down
}

void loop() {
  
  
  for (byte Durchlauf = 0; Durchlauf < AblaufAnzahl; Durchlauf++) // Ablauf starten
  {
    ledDelay = analogRead(Poti)*10; // Potentiometerwert holen und mit 10 multiplizieren. Längest ledDelay 10230ms (10*1023)
    if (ledDelay < 200) {ledDelay=200;} // ledDelay soll aber niemals kleiner 200ms werden  
    Zeit = millis(); // hole die aktuelle Zeit vor Begin des Durchlaufs
    
    // Lichter setzen
    
      aktuelleZeit = millis();
      while (aktuelleZeit < (Zeit + ledDelay))
      {
        if (bitRead(LOW_Ablauf[Durchlauf],0) == 1) {if (bitRead(CFlackern1,FlackernDurchlauf) == 1) {digitalWrite(Flackern1, HIGH);} else {digitalWrite(Flackern1, LOW);}}
        if (bitRead(LOW_Ablauf[Durchlauf],1) == 1) {if (bitRead(CFlackern2,FlackernDurchlauf) == 1) {digitalWrite(Flackern2, HIGH);} else {digitalWrite(Flackern2, LOW);}}
        if (bitRead(LOW_Ablauf[Durchlauf],2) == 1) {if (bitRead(CBlinker1,FlackernDurchlauf) == 1) {digitalWrite(Blinker1, HIGH);} else {digitalWrite(Blinker1, LOW);}}
        AlleAn(Durchlauf); // Hier werden alle Lampen außer dem Fernsehn/Flackern gesetzt
        delay(FlackerDelay);
        FlackernDurchlauf++;
        if (FlackernDurchlauf == 16) {FlackernDurchlauf = 0;}
        aktuelleZeit = millis();
      }
  } 
}


void AlleAn(byte TempDurchlauf)
{
  if (digitalRead(Taster) != LOW) // Ist der Taster gedrückt
    {
     // JA
     // Alle Lampen an
     digitalWrite(Flackern1, HIGH);
     digitalWrite(Flackern2, HIGH);
     digitalWrite(Blinker1, HIGH);
     digitalWrite(Zimmer1, HIGH);
     digitalWrite(Zimmer2, HIGH);
     digitalWrite(Zimmer3, HIGH);
     digitalWrite(Zimmer4, HIGH);
     digitalWrite(Zimmer5, HIGH);
     digitalWrite(Zimmer6, HIGH);
     digitalWrite(Zimmer7, HIGH);
     digitalWrite(Zimmer8, HIGH);
     digitalWrite(Zimmer9, HIGH);
     digitalWrite(Zimmer10, HIGH);
    }
    else
    {
      // NEIN
      // *** Block 1 ***
      // Sonderfall Flackern/Blinker
      if (bitRead(LOW_Ablauf[TempDurchlauf],0) == 0) {digitalWrite(Flackern1, LOW);} // Nur wenn das Fernsehen/Flackern im Ablauf ausgeschaltet ist wird es ausgeschaltet.
      if (bitRead(LOW_Ablauf[TempDurchlauf],1) == 0) {digitalWrite(Flackern2, LOW);} // Nur wenn das Fernsehen/Flackern im Ablauf ausgeschaltet ist wird es ausgeschaltet.
      if (bitRead(LOW_Ablauf[TempDurchlauf],2) == 0) {digitalWrite(Blinker1, LOW);} // Nur wenn das Fernsehen/Flackern im Ablauf ausgeschaltet ist wird es ausgeschaltet.
      // Dann setze die Lampen so, wie im Ablauf gesetzt
      if (bitRead(LOW_Ablauf[TempDurchlauf],3) == 1) {digitalWrite(Zimmer1, HIGH);} else {digitalWrite(Zimmer1, LOW);}
      if (bitRead(LOW_Ablauf[TempDurchlauf],4) == 1) {digitalWrite(Zimmer2, HIGH);} else {digitalWrite(Zimmer2, LOW);}
      if (bitRead(LOW_Ablauf[TempDurchlauf],5) == 1) {digitalWrite(Zimmer3, HIGH);} else {digitalWrite(Zimmer3, LOW);}
      if (bitRead(LOW_Ablauf[TempDurchlauf],6) == 1) {digitalWrite(Zimmer4, HIGH);} else {digitalWrite(Zimmer4, LOW);}  
      if (bitRead(LOW_Ablauf[TempDurchlauf],7) == 1) {digitalWrite(Zimmer5, HIGH);} else {digitalWrite(Zimmer5, LOW);}
      // *** Block 2 ***
      if (bitRead(HIGH_Ablauf[TempDurchlauf],0) == 1) {digitalWrite(Zimmer6, HIGH);} else {digitalWrite(Zimmer6, LOW);}
      if (bitRead(HIGH_Ablauf[TempDurchlauf],1) == 1) {digitalWrite(Zimmer7, HIGH);} else {digitalWrite(Zimmer7, LOW);}
      if (bitRead(HIGH_Ablauf[TempDurchlauf],2) == 1) {digitalWrite(Zimmer8, HIGH);} else {digitalWrite(Zimmer8, LOW);}
      if (bitRead(HIGH_Ablauf[TempDurchlauf],3) == 1) {digitalWrite(Zimmer9, HIGH);} else {digitalWrite(Zimmer9, LOW);}
      if (bitRead(HIGH_Ablauf[TempDurchlauf],4) == 1) {digitalWrite(Zimmer10, HIGH);} else {digitalWrite(Zimmer10, LOW);}   
    }
}

Schöne Anwendung, kannst du mal ein Video davon machen?
Das Schaltungsdesign finde ich nicht gerade glücklich gewählt, RX und TX hätte ich frei gelassen und statt dessen die Analogpins als Ausänge genutzt. Natürlich kann man sich noch streiten, ob pro Haus wirklich ein Arduino gebraucht wird, oder ob man nicht sogar die gesamte Beleuchtung der Anlage über diesen einen Mikrocontroller laufen lassen kann. Spontan käme mir der Einsatz von Schieberegistern in den Sinn.

Ja, RX und TX zu nutzen ist nur suboptimal. Kommt vielleicht bei der nächsten Version. Ich wollte den Aufbau möglichst einfach gestalten für Quereinsteiger, die mehr mit der Modellbahn, als mit dem Arduino zu tun haben. Deshalb auch keine Schieberegister. Das würde die Anwendung deutlich komplizierter machen - gerade die "Programmierung" des Ablaufs. So ist die Beziehung zwischen Digital Pin (LED) und gesetztem Bit am klarsten.
Ein Arduino pro Haus macht wenig Sinn. Die Idee ist eher: ein Arduino pro Modellbahnsegment oder Teilbereich einer Anlage. Da die meisten Beleuchtungsartikel eher dauerhaft leuchten (Straßenlaternen oder Lichter im Bahnhofsgebäude), müssen nur wenige zeitabhängig (z.B. über meine Arduino-Lösung) gesteuert werden.

Einfach halten ist immer gut. Und RX und TX zu verwenden finde ich auch nicht verwerflich. Allerdings würde ich die vielen IFs ein wenig zusammendrücken. Also statt

      if (bitRead(LOW_Ablauf[TempDurchlauf],5) == 1) {digitalWrite(Zimmer3, HIGH);} else {digitalWrite(Zimmer3, LOW);}

kürzer

digitalWrite(Zimmer3, bitRead(LOW_Ablauf[TempDurchlauf],5));

Hier das Video:

@Udo Klein
Der verkürzte Code wird sicherlich in der nächsten Version eingebaut. Danke!

Schaut schon nicht schlecht aus. Allerdings ist das Fernsehflackern etwas arg unrealistisch. Besser wäre es vermutlich wenn die LED permanent an wäre und in der Helligkeit bis auf max. 50% runtergehen würde.

Hallo,
auf der Suche nach einer Hausbeleuchtungs-Schaltung für die Modelleisenbahn bin ich auf diesen Thread gestoßen, und nach 10 Minuten war klar: Mache ich auch so!

Bestellt habe ich mir so einen Arduino-Nachbau ("SainSmart Mega2560 R3 ATmega2560 +ATmega16U2"), der hat 54 Ein/Ausgänge.
Durch Apnpassungen an den hier vorgstellten Programm-Code sollten ja dann auch mehr als 8 LED's steuerbar sein. EIne 8-fach Relaisleiste habe ich dazubestellt, falls mehr als eine LED an einen Kanal angeschlossen werden soll (max. Strom 30-.50mA).

Gibt es mittlerweile eine neuere Version des Codes, oder auch andere Programme, die ein "bewohntes Haus/Siedlung" simulieren?

Ich hoffe, der bestellte "SainSmart Mega2560 R3 ATmega2560 +ATmega16U2" ist OK und ist nutzbar, oder besser canceln und was anders holen?

So denn, dann heißt es jetzt erstmal, paar Tage reinlesen bis die HW da ist ...

VG,
Martin

Warum neue Programmversion, tut doch was sie soll. Wenn du dich eh einlesen willst, dann arbeite dich in Blink Without Delay ein. Das ist kein Hexenwerk, sowas selber zu machen :wink:

hi,

könnt Ihr Euch noch an diesen thread erinnern? mit schönem video und bauanleitung...
http://forum.arduino.cc/index.php?topic=159117.msg1194476#msg1194476
gruß stefan

Hallo, tolles Programm, und für mich als Einsteiger optimal! Allerdings läuft bei mir das Programm nur, wenn ich pin 13 auf Masse lege. Habe ich was übersehen?

towi:
Allerdings läuft bei mir das Programm nur, wenn ich pin 13 auf Masse lege. Habe ich was übersehen?

Ja, da hast Du wohl was übersehen:

Wenn Taster auf HIGH gezogen wird, werden alle Lampen eingeschaltet
...
...
int Taster = 13; // Taster auf DigitalPin 13
...