Weichensteuerung Schritt für Schritt

Hallo Michael,
hast Du dir eigentlich mein Tutorial aus #4 angeschaut? Da wird eigentlich alles angesprochen, was Du brauchst, auch die Arrays.
Es hat mMn wenig SInn so weiter zu machen. Du solltest so schnell wie möglich auf die schon oft angesprochene Schrittkette umsteigen. Je später Du das machst, um so mehr unnötige Zeit und Aufwand geht verloren.
Gruß, Franz-Peter

Ich habe im Minischattenbahnhof tatsächlich nur 1 Weiche und 2 Gleise. Das Jeweils für einen von 2 Stromkreisen. Deshalb brauche/kann ich die beiden Weichen nicht in Beziehung zueinander setzen.

Auf der Grundebene, um deren Aufbau es hier erst einmal geht, gibt es noch 2 weitere Bereiche, die ich ähnlich steuern möchte.

Hier der Gleisplan der unteren Ebene, nicht topaktuell aber im Prinzip gleich:

Fahrtrichtungen sind in den äußeren Kreisen links herum und im Innenkreis rechts herum.
Wir haben den Bereich oben rechts gelöst. Einfahrt in den je 2-gleisigen Schattenbahnhof.

An der Unterseite des Innenkreises seht ihr 3 Gleise parallel. Das wäre dann die nächste Baustelle :smiley: Das untere ist ein Durchgangsgleis und wird zunächst nicht betrachtet. Das mittlere Gleis ist Haltegleis und das obere möchte ich als Haltegleis für 2 kleine Schienenbusse sogar in 2 Sektionen mit automatischem Nachrücken und Ausfahren per Taster einrichten. Doch das später. Erstmal hier weiter machen.

Shannon, wenn ich Dich richtig verstehe, funktioniert bool wie int, verbraucht aber nur ein Bit, ist also generell austauschbar? Dann versuche ich die Weichensteuerung ohne delay und ohne int, dafür mit millis und bool umzusetzen.

Das hatte ich nicht eingesetzt, weil nicht verstanden. Ich werde aber mit Deinem Programm mal etwas spielen. Vielleicht klappt das ja jetzt.

sollte klappen, da ich ansonsten eh keine delays habe. Mal schauen. Mache ich parallel zu millis und bool nach Vorschlag von Shannon.

Genau das hatte ich ja nicht hinbekommen :smiley: Bis der Tipp von Shannon kam.

Jaaa... Arrays. ein weiteres Unverständnis von mir :smiley: Machen die denn bei im Prinzip nur einer Weiche Sinn? Ich habe ja keine Gleisharfe.

Hi Franz-Peter.
Ich konnte Deinem Beitrag im Stummi bis zu einem gewissen Punkt folgen. Dann hat mein Hirn gestreikt. Deswegen habe ich das erstmal nicht weiter verfolgt.
Durchaus möglich, dass ich noch einmal von vorn anfange. Aber es macht doch für mich keinen Sinn, etwas über das Knie zu brechen, was ich nicht verstehe. Das, was ich bisher gemacht habe, kann ich nachvollziehen.
Was mich an den Tommy-Sketches gestört hat...ich brauche keine Ampel und keinen Wechselblnker. Und ich habe nicht gesehen, wie ich diese Programmteile bei mir implementieren konnte.
Ich habe Deinen Beitrag im Stummi im Merken und werde mir das sicher auch wieder und wieder ansehen. Nennt man das Ehrgeiz? :smiley: Vielleicht macht es da ja auch "Klick".

schau dir meinen Codeschnipsel an, im abschalten() sieht man schön warum ein Array gut ist: damit kann man über mehrere Weichenantriebe itereiren und mit einem Code alle Weichen behandeln.

schau dir deinen Code an, wie viele Codeduplikate du hast: immer wieder der gleiche Code, nur weil sich die Weichenzuordnungen/Gleiszuordnungen unterscheiden.
Imho sind Arrays essentiell.
und auch Strukturen (struct) - denn irgendwann wirst du Gleisabschnitte mit Weichen mit Reedkontakten kombinieren wollen.

Überall wo Du Variablennamen durchnumerierst kommt sofort der Gedanke für ein Array auf. Und das machst Du oft.

Wenn Du etwas nicht verstehst, könntest Du nachfragen. Dafür ist das Forum da :wink: .
Für mich macht es keinen Sinn, weiter in eine Sackgasse hineinzuspazieren. Je früher man da umkehrt, desto besser :sunglasses: .

Es geht darum, das Prinzip zu verstehen. Ob man das dann am Ende für einen Wechselblinker/Ampel braucht, oder Weichen damit stellen will ist dann egal, wenn man es einmal verstanden hat. Auch wenn Du einen Programmierkurs besuchst, wird es dort Beispiele geben, die nicht direkt zu deinem Projekt passen. Aber wenn Du erstmal weist wie es geht, kannst Du es auf alles anwenden.

Gruß, Franz-Peter

Danke für den Gleisplan von Zimmerheim.

Ein UNO langweilt sich, wenn er sich nur um zwei Weichen kümmern muß, der könnte locker mehr. Im Gegensatz dazu raucht Dein Kopf. In diesem Spannungsfeld stellt sich mir die Frage, in welche Richtung ich Dich konzeptionell schubsen möchte:

  1. Das Programm der ersten Weiche wird mit etwas anderen Namen kopiert.
  2. Beide Weichen nutzen die selbe Funktion, nur mit einem Index aufgerufen. Dazu benötigt man Felder. Also ein Feld für den einen Reedkontakt, ein zweites für den zweiten Reedkontakt usw.
  3. Wenn Du mehr vorhast, möchte Dich der erfahrenere Anfänger zu einer Klasse überreden.

Auf jeden Fall wichtig ist blockadearme Programmierung mit einer Schrittkette.

Ah, ok. Beginnt sich im Kopf durchzusetzen...obwohl jedes Verständnis fehlt :smiley: ein Wunder... Ok. Ich lese mich intensiver in Arrays ein.

Daumenhoch...

Das glaube ich gern. Momentan stehe ich noch da, wo ich sage, ich kaufe mir noch 3 davon, damit ich weitere Stellen an der Bahn ausrüsten kann und Material zum lernen habe. Obwohl ich weiß, dass der auch mit Erweiterungen wahrscheinlich die ganze Bahn locker übernehmen könnte. Einen brauche ich trotzdem noch....zum lernen. Denn ich werde weiter machen. Schließlich macht das Spaß.

Blockadearm= z.B. keine Delays, keine Programmteile, die unsinnig den Proz belasten?
Schrittkette, endlicher Automat, Arrays. Das werden meine nächsten Lernschritte sein, wenn ich das richtig verstanden habe.

davor warne ich.
Reize einen Arduino voll aus. Dann lernst du mit der Zeit auch, worauf es ankommt und kannst bessere Programme schreiben. 10 Arduino die ähnliches aber nicht gleiches tun, macht die Sache nicht einfacher. Ja kauf dir noch weiter Controller, einen für den Einsatz, einen fürs Rumprobieren, aber nutze sie voll aus. Gib so viele Pins/Reed/Taster wie möglich drauf. Schreibe schönen Code.

Hast du nun deinen Code schon aktualisiert? Funktioniert die Weichenschaltung ohne Delay?
Zeige mal deinen letzten Stand vom Code, dann kann man dich vieleicht in die nächste Richtung schubbsen.

Dieses Hobby hat Suchtpotential, so wie Modellbahn, sei gewarnt :blush:

Mehrere Pro Mini 328 Mini 3,3 5V/16M, mit einem CP2102 Modul zu programmieren, über die Anlage verteilt, fände ich vollkommen legitim.

Alternativ kannst Du den UNO um Portexpander wie z. B. den MCP23017 oder MCP23S17 um IOs erweitern, oder Du verwendest einen MEGA 2560PRO mit vielen Pins und auch mehr Speicher.

... und auch Strukturen und Klassen, wenn Du magst. Ich habe mich da lange gegen gesträubt, aber durch dieses Forum und Beispiele auch von combie finde ich das inzwischen für manche Anwendungen sinnvoll. Schau Dir bitte mal mein Beispiel an, ob es Dich anspricht.

Für die Zeiten und noch viel mehr wurde die Bibliothek MobaTools geschrieben. Eine gute Doku läßt die "Schrecken" der Millis vergessen. Die Bibliothek läßt sich über den Bibliotheksmanager der IDE installieren. Der Autor ist hier im Forum aktiv und ich teste gerade die neue Version.

Die Schrittkette konnte ich auf zwei Schritte schrumpfen. Getestet nur mit ein paar LEDs:

#include <MobaTools.h>

class Gleis {
    enum {WARTEN, IMPULSAUS};
    const byte reedPinA, reedPinG, stromRpin, weicheApin, weicheGpin;
    byte schritt = WARTEN;
    MoToTimer weichenImpuls;
    const uint32_t weichenImpulsLaenge = 300; // in Millisekunden
  public:
    Gleis(const byte reedPinA, const byte reedPinG, const byte stromRpin, const byte weicheApin, const byte weicheGpin)
      : reedPinA(reedPinA), reedPinG(reedPinG), stromRpin(stromRpin), weicheApin(weicheApin), weicheGpin(weicheGpin)
    {}
    void init() {
      pinMode(reedPinA, INPUT_PULLUP);
      pinMode(reedPinG, INPUT_PULLUP);
      digitalWrite(stromRpin, HIGH);
      pinMode(stromRpin, OUTPUT);
      digitalWrite(weicheApin, HIGH);
      pinMode(weicheApin, OUTPUT);
      digitalWrite(weicheGpin, HIGH);
      pinMode(weicheGpin, OUTPUT);
    }

    void stellen() {
      switch (schritt) {
        case WARTEN:
          if ( !digitalRead(reedPinA) ) {
            digitalWrite(stromRpin, HIGH);              // Gleis Abzweig stromlos, Gleis Gerade bestromt
            digitalWrite(weicheGpin, LOW);              // Weiche Impuls auf Gleis Gerade ein
            weichenImpuls.setTime(weichenImpulsLaenge); // "Eieruhr" aufziehen
            schritt = IMPULSAUS;
          }
          if ( !digitalRead(reedPinG) ) {
            digitalWrite(stromRpin, LOW);               // Gleis Gerade stromlos, Gleis Abzweig bestromt
            digitalWrite(weicheApin, LOW);              // Weiche Impuls auf Gleis Abzweig ein
            weichenImpuls.setTime(weichenImpulsLaenge); // "Eieruhr" aufziehen
            schritt = IMPULSAUS;
          }
          break;
        case IMPULSAUS:
          if ( weichenImpuls.expired() ) {
            digitalWrite(weicheGpin, HIGH);              // Weiche Impuls auf Gleis Gerade ein
            digitalWrite(weicheApin, HIGH);              // Weiche Impuls auf Gleis Abzweig ein
            schritt = WARTEN;
          }
          break;
        default:
          schritt = WARTEN;
      }
    }
};

Gleis gleis[] {
  //reedPinA, reedPinG, stromRpin, weicheApin, weicheGpin
  { // Gleis 1
    12, //T1	Taster1, Gleis1 Zugerkennung
    11, //T2	Taster2, Gleis2 Zugerkennung
    8,  //G1G2	Relais für Stromumschaltung Gleis1 zu Gleis2, Test LEDweiß
    7,  //W11	Relais für Weiche11 geradeaus, LEDgrün
    6   //W12	Relais für Weiche12 abbiegend, LEDgelb
  },
  { // Gleis 2
    10, //T3	Taster3, Gleis3 Zugerkennung
    9,  //T4	Taster4, Gleis4 Zugerkennung
    5,  //G3G4	Relais für Stromumschaltung Gleis3 zu Gleis4, Test LEDweiß
    4,  //W23	Relais für Weiche23 geradeaus, LEDgrün
    3   //W24	Relais für Weiche24 abbiegend, LEDgelb
  }
};

void setup() {
  for (Gleis &g : gleis) g.init();
}

void loop() {
  for (Gleis &g : gleis) g.stellen();
}

Ist jetzt möglicherweise etwas viel unterschiedlicher Input von verschiedenen Leuten, aber ich hatte jetzt gerade Zeit, meine Frau räumt auf.

Bei Fragen bitte fragen.

EDIT 20:00 Uhr:

    byte schritt = WARTEN;

EDIT 3.5.21: Kommentare korrigiert.

1 Like

Iiiiiimmer langsam Ö.Ö :smiley:
Bin ein alter Mann mit vielen Aufgaben, muss mich heute erstmal mehr um meinen "Nebenjob" kümmern und als Trennungspapi hab ich auch meinen Sohn hier. Ich setze mich daran und poste den neuen Code hier.

Jap, an Portexpander hatte ich auch gedacht...später für die Beleuchtung auf jeden Fall.
Der MEGA käme mir wegen seiner Ausgänge jetzt schon gelegen. Mir fehlt einer, um das Überholgleis unten im Außenkreis mit zu integrieren. Der UNO könnte dann zum Lernen sein...oder für den Bahnhof unten...oder... :smiley:

Danke... Auch ich werde mich entwickeln.

Ich bin gar nicht abgeneigt. Aber dieses "ichbinnochnichtsoweit-Gefühl" macht´s mir schwer.
Das Sackgassenbeispiel ist richtig und gut...aber ich denke, viele sind auch einmal in die Sackgasse gelaufen, um herauszufinden, WARUM Dieses Schild da eigentlich steht :smiley:

Boah. Das Programm schaut schon mal aufgeräumt aus. Ich schaue mir das in aller Ruhe ganz genau an. Danke!

Hallo,
für das gesamt Projekt würde ich eine Analyse, auf der Basis des EVA Prinzips, durchführen.
Das Ergebnis beschreibt alle benötigen Softwarefunktionen und die Anzahl der I/O Pins, die zur Relalisierung Gesamtfunktionbenötigt benötigt werden.
EINGABE:
Reet-Kontakt, Handsteuerung Gleisplan, Stromsensoren für die Erkennung der Fahrwegsbelegung, usw......
VERARBEITUNG:
Zeitgeber, Fahrwegsplanung, usw......
AUSGABE:
Weichen, Signale, Beleuchtung, Gleisplananzeige, usw......
Zu jedem Element innerhalb dieser Aufzählung läßt sich ein struct{} konstruieren, das von der gleichen Funktion ausgeführt wird.

Das ist es, was mich daran reizt, denn man möchte sein Programm ja auch noch nach längerer Zeit verstehen.

Eine Fahrwegsplanung, Signale, Beleuchtung, Gleisplananzeige etc wird es in der Form nicht geben. Ich halte die Bahn weitestgehend analog mit wenig Automatisierung.
Der Bereich, um den es jetzt geht, ist verdeckt.

Etwas anderes wird es sein, wenn ich den Bahnhofsbereich über 2 Ebenen erstelle. Dort ist Sichtbereich (unten rudimentär durch Arcaden geplant) und dort sollten auch Signale stehen, Beleuchtung sein etc. Dort werde ich sicher von Anfang anders programmieren... aber das jetzt erst mal lernen :wink: Also: Reset.

Und haben dann eigentlich immer festgestellt, dass es zu Recht da steht, weil es eben plötzlich nicht mehr weiter geht :wink: . Wer dem Schild glaubt, ist schneller am Ziel, auch wenn man da vermeintlich erstmal in eine andere/falsche Richtung gehen muss :sunglasses: .

Hi.
Kapitulation... Franz-Peter und Shannon: Ihr habt´s geschafft :wink:
Ich werde den Timer jetzt einmal ausprobieren und mir daheim die MoBaTools herunterladen.
Jetzt kommen die Verständnisfragen :smiley:

class Gleis {
    enum {WARTEN, IMPULSAUS};
    const byte reedPinA, reedPinG, stromRpin, weicheApin, weicheGpin;
    byte schritt = WARTEN;
    MoToTimer weichenImpuls;
    const uint32_t weichenImpulsLaenge = 300; // in Millisekunden
  public:
    Gleis(const byte reedPinA, const byte reedPinG, const byte stromRpin, const byte weicheApin, const byte weicheGpin)
      : reedPinA(reedPinA), reedPinG(reedPinG), stromRpin(stromRpin), weicheApin(weicheApin), weicheGpin(weicheGpin)
    {}

Du öffnest eine Klasse "Gleis" mit den 2 aufgezählten Aufgaben "WARTEN" (mit MotoTimer) und "IMPULSAUS".
Dann folgt der Bereich "public" . In der Reihenfolge der "allgemein angegebenen PINs" vergibst Du unter "GLEIS" die PIN-Nummern für alle Blöcke mit der gleichen Funktion...?
Wollte ich nun einen dritten Block hinzufügen...ich müsste hier nur 5 weitere PINs vergeben. Ok. Genial.
Verständnisfragen:
Warum der Doppelpunkt und das Folgende mit den ( ) ? im "public"?
Ist nach "public" eine { zu viel?

In "void stellen" definierst Du die Ablaufsteuerung ebenfalls allgemein.
Die Schrittkette, von der Du geschrieben hast, richtig?
Schrittbefehle WARTEN und IMPULSAUS lassen den entsprechenden "case" ausführen?
Und WARTEN ist nur für den Ablauf der Eieruhr?
"break" ist fixer Bestandteil von "case"?
"default" verstehe ich nicht. Herr, ich brauche mehr nutzbare Hirnmasse...

Nach

steht "default" für den Fall, dass es keine Übereinstimmung des Zustandes zu den "cases" gibt?

Beim "setup" steige ich gerade völlig aus. Tilt......... :smiley:

Mehr Erläuterungen im Thema Anleitung: Weichensteuerung mit Klasse

Das ist der Konstruktor, der die Instanzen zusammenbastelt:

      : reedPinA(reedPinA), reedPinG(reedPinG), stromRpin(stromRpin), weicheApin(weicheApin), weicheGpin(weicheGpin)
    {}

Hier habe ich gleichlautende Konstantennamen verwendet, was für mich einfach, zum Lernen aber blöd ist. Im anderen Thema habe ich daher mit einem Unterstrich versehene Namen zur Unterscheidung benutzt.

Nein, der mögliche Inhalt wird nur nicht genutzt.

Man schreibt es für eine Weiche und nutze es in jeder Instanz von Neuem, ganz getrennt.

Ja, switch/case.

Durch enum ist WARTEN==0 und IMPULSAUS == 1, das sind "sprechende" Nummern.

Nee if ( weichenImpuls.expired() ) wartet auf die Eieruhr.

Ohne break läuft der Schritt in den nächsten. Dies wäre möglich:

        case IMPULSAUS:
          if ( weichenImpuls.expired() ) {
            digitalWrite(weicheGpin, HIGH);              // Weiche Impuls auf Gleis Gerade ein
            digitalWrite(weicheApin, HIGH);              // Weiche Impuls auf Gleis Abzweig ein
        default:
          schritt = WARTEN;
      }

Wenn bei case nichts Passendes gefunden wird, ist default der "Notausstieg". Da sollte die Schrittkette nie hinkommen.

Das ist nur eine verkürzte Schreibweise einer for-Schleife, die automatisch alle Elemente von gleis[] abarbeitet. Man könnte auch schreiben:

gleis[0].init();
gleis[1].init();

oder auch

for (byte j = 0; j < 2; j++) gleis[j].init();

Vielleicht sind auch Klassen und Schrittkette ein bisschen viel auf einmal :wink: . Und dann auch noch gleich ein range based for loop :innocent:.
Erstmal die Schrittkette verstehen, und dann das Ganze in eine Klasse verpacken.
Im Prinzip sind das 3 verschiedene Techniken, die man Schritt für Schritt einzeln lernen und verstehen kann ( und sollte ) :sunglasses:

Ja, ich bitte um Nachsicht, aber mein Leben läßt mir mal mehr, mal weniger Ruhe für Arduino.

Also immer Schritt für Schritt, aber das Ziel wollte ich schon mal schmackhaft machen, weil ich denke, es lohnt sich.

Da stimme ich vollumfänglich zu :sunglasses: