Einsteigerhilfe für DCC Kommunikation

Hallo.
Ich möchte einen Decoder für meine Modelleisenbahn bauen. Mit DCC und mit dem Arduino.
Hardware hab ich mir dazu schon gekauft, den Arduino natürlich... Und zusätzlich das DCC Power Shild von Nico Teering aus NL.
Dieses hab ich zusammengebaut und glaube es funktioniert auch so wie es soll..
Dann hab ich mir aus dem Internet via YouTube und Forum die nötige Software zusammengesucht, bzw wie man den Sketch programmiert...:
Vor allem " Let's learn together - DCC Decoder!" von Luca D. hat mir als Vorbild gedient.
Es sah so einfach aus...
Ich hab mir die Nmra DCC Library insalliert und den Sketch aus dem Video möglichst exakt kopiert...
Funktionieren tut nix und verstehen tuhe ich auch nur Bahnhof (Damit kenne ich mich auch aus als Lokführer..) :wink:

Sicher gibt es auch schon fertige Lösungen mit und für den Arduino, da kann man sich bequem ein PC Programm runterladen und diverse Sachen einstellen per Häkchen und Werten, dann übersetzt der das alles passend für den Arduino. Ich wollte aber gerne selbst ein Projekt erstellen und später gewisse Abhängikeiten schaffen.
Dabei wollte ich ganz einfach anfangen, so wie in dem Video...

Mit dem Arduino arbeite ich allerdings nur gelegentlich und bin daher etwas unbeholfen, auch meine Sketches sind da eher simi proffesionell, andere schlagen die Hände über dem Kopf zusammen, aber meine LEDs blinken dann doch irgendwann immer so wie ich wil... Lach

Nun hab ich als Anweisungen und Hilfen und fertige Projekte im Internet leider immer nur sehr komplexe und spezielle Sachen gefunden. Damit bin ich sehr schnell überfordert.
Ähnlich verhält es sich bei Beiträgen in Foren wie diesem hier. Die DCC-Themen sind immer sehr speziell und meist auf Englisch. Der Code der gezeigt wird, wird meist nicht so gut erklärt, dass einer wie ich das auch verstehen würde...

Hat einer von euch einen Tipp, wo mann wirklich von Anfang an das erklärt bekommt, am besten dann auch noch auf deutsch?
So dass wirklich nur die DCC.h eingebunden werden muss, eine feste Adresse definiert und bei Aufruf der Adresse die interne Led an Pin 13 an und aus geht wenn man den entsprechenden Befehl auf der Zentrale gibt...

Wenn man so will ein DCC blink.ino
Lach
Das wäre perfekt.
Und dann kann man sich davon Schritt für Schritt hoch arbeiten und verstehen welcher Befehl denn eigentlich was macht und welchen ich brauche.

Denn bis jetzt schaut immer alles ganz anders aus wenn ich mir fertige ino Projekte ansehe oder die h Datein von Nmra auf Github aufmache...
Die haben das geschrieben, die anderen haben jenes geschrieben...
Kann mir das mal einer zum lernen auf das absolute Minimum reduzieren?

Ich hoffe man konnte mein Problem einigermaßen verstehen...
Gruß Bernd

Hallo Bernd, kensst Du openDCC? Da wird eigentlich alles zu DCC von der Pike auf erklärt - und auch noch auf deutsch :wink:. Die nmraDCC library ist auf jeden Fall schonmal ein guter Anfang - die nimmt dir viel Arbeit ab. Zeig doch mal deinen Sketch, der nicht funktioniert.

Ich habe auch einen frei konfigurierbaren DCC-Decoder für den Arduino geschrieben - mit Anleitung auf deutsch.
Vielleicht einen Blick wert - auch wenn Du es ja eigentlich alles selbst machen willst.

Gruß, Franz-Peter

Moin.
Ja, Open DCC ist schon mal eine gute Hilfe, das kannte ich soo noch nicht.
Dort kann man viel erfahren, sogar wie man Heizungsventile austauscht.. Lach
Aber dort geht es hauptsächlich um die Frage was welcher Zustand im DCC Signal bedeutet und welche Standarts es gibt und wie das SIgnal geformt ist oder sein muss...

Und ich dachte, Verständnisfrage:
Das genau das mir die Nmra DCC Library abnimmt...
Das ich mich darum gar nicht kümmern brauche...
Das sie da für da ist um aus den ankommenden 0 und 1 am Pin 2 die DCC Pakete rauszufiltern und zu übersetzen, das bedeutet dies und das edeutet jenes..
Adresse X mach bitte Aktion Y..

Und das ich genau DAS dann nur noch in meinen Sketch eintragen muss...
Also Adresse X mach bitte bei Zustand Y Aktion Z...
So sah es zumindest in dem Beispiel in dem Video aus...

Ich trage den Sketch hier mal vor (keine Garantie auf Vollständigkeit)
Und ich werde ihn aus Verständnissgründen zum erklären hier in FALSCHER Reihenfolge aufführen...:

Sketch:

void loop() {
       Dcc.process();
     }

Kommentar:
Dies ist klar, glaube ich, das ruft immer wieder die Nmra DCC Library auf und prüft ob neue DCC Befehle eingegangen sind.. Wenn er dann einen Befehl verarbeitet steigt er hier aus, kehrt aber nach der Verarbeitung immer wieder dahin zurück, prüft dann also weiter auf neue Befehle...

Sketch:

void setup() {
       pinMode(RED_LED, OUTPUT);	
       pinMode(GREEN_LED, OUTPUT);	
       Serial.begin(115200);		
      Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, false);	
  Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER FLAGS_OUTPUT_ADDRESS_MODE, 0);
}

Kommentar:
Hier werden zwei Pins als Ausgang definiert, weil in dem Video ja immer eine von beiden LED leuchten soll, je nach Zustand der Adresse. Also zwei Ausgänge...
Serielle Kommunikaton mit DCC wird gestartet und muss diesen Wert haben.. Ist das eigentlich auch die Zeitvorgabe an Pin 2, nee, nur für die Ausgabe der Befehle an den seriellen Monitor, oder? Das ist auf jeden Fall das...
Dann wird eine Funktion aufgerufen, in der die Parameter übergeben werden, an welchem Pin nach DCC Befehlen gelauscht wird, (Nummer2), warum auch immer das 2 mal übergeben wird...
Ich könnte hier auch einfach 2 schreiben... oder? das letzte da gehts drum ob der interne Wiederstand genutzt wird oder nicht, false wenn ein extrener verwendet wird..
Was auf dem Shild ja der Fall ist...
Bei der nächsten Funktion bin ich mir schon nicht mher ganz so sicher, denn hier weiß ich nur, dass vorne der Wert der CV für den "Hersteller" festgelegt wird, im Fall von selbstgebauten Decodern soll eine 13 verwendet werden, was auch als fester Wert eingetragen werden kann, oder man schreibt MAN_ID_DIY == DIY irgendwas hin, geht glaub ich auch.. OK, aber bei dem Rest bin ich mir nicht sicher, soll dem Dekoder hier gesagt werden, ob er ein Funktionsdecoder ist, stellt er sich bei 1 am Ende auf Multi Funktions Decoder um?

Sketch:

#include <NmraDcc.h>	
     #define DCC_PIN 2	 
    #define RED_LED 4	 
    #define GREEN_LED 5	
    NmraDcc Dcc;
   void notifyDccAccTurnoutOutput(uint16_t Addr, uint8_t Direction, uint8_t OutputPower) { 
     if(Addr == 4) { 
      if(Direction == 0) {
         digitalWrite(RED_LED, HIGH);	
         digitalWrite(GREEN_LED, LOW);	 
       }					
      else {				  
       digitalWrite(RED_LED, LOW);		
       digitalWrite(GREEN_LED, HIGH);
     }
   }

   Serial.print("Addr: "); Serial.println(Addr);
   Serial.print("Direction: "); Serial.println(Directon);
   Serial.print("OutputPower: "); Serial.println(OutputPower);
   Serial.print("----------------------");
}

Kommentar:
Hier passiert die ganze Magie.. Warum auch immer das alles noch vor dem Setup steht.
Bei define klar, aber die Funktionen könnte ich doch auch unter Loop stellen, oder müssen die da oben sein?

Als erstes die Nmra DCC.h, damit man dann auf vorgefertigte Befehle zurückgreifen kann.
Und laut meinem Verständniss die Kommunikation/ Lauschen auf DCC Befehle aktiviert...

Dann wird der Pin deklariert über den die DCC Befehle rein kommen, muss aber ein Interrupt PIN sein als Pin 2 oder 3... Könnte ich da genauso int DCC_PIN = 2; schreiben?

Dann wird einfach nur ein Ausgang definiert der später geschaltet wird... Hier 4 und 5, da gilt das gleiche, oder? Also int RED_LED = 4; würde es auch tun?
So gilt es ja Ersatz, vor dem Compilieren wird einfach RED_LED immer gegen 4 ausgetauscht..
Da der Sketch kurz ist könnte ich mir das sparen und einfach direkt die 3 bis 4 mal eine 4 in den Sketch schreiben..

NmraDcc Dcc; wofür ist das um die Art des Protokolls festzulegen ob DCC oder M4 oeder FMX oder was? Richtig geraten? Was gäbe es als Alternative?

Dann geht es los mit dem was ich langsam nicht mehr verstehe. Das ist ein Programm das aufgerufen wird aber wo ist es definiert und was bedeuten die Deffinitionen?
Darunter geht es dann wieder gewohnt weiter und das ist ja das was für mich interessant ist:
Wenn Adresse 4 ist, dann schau wie die Richtung ist, bei der einen Richtung grünes Licht anschmeißen und bei der anderen Richtung rotes Licht...
Damit kann ich arbeiten... :wink:

Dann wird einfach nur das ausgegeben was empfangen wurde, aber ich frag mich ein bisschen wie das funktioniert...
Der PC auch, denn er sagt mir immer das Addr und Direction gar nicht definiert wurde...
Womit er auch recht hat.. Kann ich dem Abhilfe schaffen, indem ich oben einfach noch int Addr und int Direction dazu schreibe oder haben die dann einen willkürlichen Wert...

Beste Grüße Bernd

Ja, da nimmt dir die NmraDcc das 'auseinaderpflücken' der DCC-Befehle schon ab. Trotzdem solltes Du die Grundlagen der DCC-Befehle verstanden haben, sonst verstehst Du eben auch einige Parameter, die die DCC-Lib braucht, und Ergebnisse, die sie liefert nicht richtig.

'Aussteigen' ist wohl nicht der richtige Begriff. Wenn er ein DCC-Telegramm empfangen und interpretiert hat, ruft er eine dazu passende Funktion auf. Der Name und die Aufrufparameter dieser Funktion sind festgelegt, nicht aber was darin passiert. Deshalb musst Du diese Funktion im Sketch selbst programmieren. ( Sowas nennt man 'Callback' Funktion. Du schreibst eine Funktion, aufgerufen wird sie aber von der Lib ). das ist auch ein Grund, weshalb Du die Grundlagen der DCC-Telegramme kennen solltest, damit Du nachvollziehen kannst, wann welche Funktion aufgerufen wird.

Meinst Du das Serial.begin() ? Das hat mit DCC gar nichts zu tun, sondern dient -wie Du schreibst - der Kommunikation mit dem seriellen Monitor der IDE auf deinem PC. Die Baudrate 115200 muss im seriellen Monitor auch auf diesen Wert gestellt werden.

Ja ist der Historie geschuldet und der Tatsache, dass die Interruptnummer eines Pins und die Pin-Nummer bei vielen Boards nicht übereinstimmen.

Gewöhn dir das garnicht erst an, 'magic Numbers' zu verwenden. Also im Sketch direkt mit festen Zahlen zu arbeiten. Ordne einem Pin immer einen Namen zu, und verwende im Sketch dann nur noch diesen Namen. Wenn Du einmal - aus welchen Grunden auch immer ) einen Pin ändern musst, wirst Du an mich denken ...
Gilt auch z.B. für das MAN_ID_DIY. Das ist in der Lib schon vordefiniert, und solange Du keine kommerziellen Decoder baust und verkaufst, solltest Du da auch nichts ändern.

Ja, die weiteren Parameter bestimmen das Verhalten des Decoders. In dem Fall ist es ein Zubehördecoder mit linearer Adressierung.

Der ist aber bei weitem nicht vollständig. Poste mal den ganzen Sketch - so funktioniert das nicht.

Das mit der Aktion Y musst Du schon selbst programmieren. Die Lib sagt dir nur, dass ein Paket mit der Adresse X angekommen ist. Was Du damit machen willst, kann die Lib nicht wissen. Dazu sind eben diese Callback-Funktionen da. Wenn ein Paket mit Adresse X angekommen ist, ruft sie die entsprechende Funtkion auf, und Du programmierst darin, was passieren soll. Deshalb solltest Du auch wissen und verstehen, welche Informationen in den verschiedenen DCC-Telegrammen drin stehen, damit Du entsprechend reagieren kannst. Wie diese Information dort codiert ist, das brauchst Du nicht wissen, das fieselt die Lib auseinander.

Guten Abend.

Open DCC:
Dann muss ich wohl noch mal auf die Schulbank und DCC Vokabeln lernen..
:wink:
Also gut, es ist zwar ein bisschen trocken aber ich werde mich Stück für Stück durch die Beschreibung arbeiten.
Kann aber sein, dass dann auch häufiger Nachfragen von mir kommen :wink:

Lib:
Wieder etwas gelernt, Callback Funktionen... Aha... Deswegen hab ich wohl auch nix richtiges gefunden, als ich mir die Lib mal aufgemacht habe. Ich dachte ja, dass die Befehle alle da drin stehen und ich das passende einfach raus kopieren kann...
War auch erstanlich kurz mit "nur" knapp 700 Codezeilen die Lib.

Was passiert denn mit Funktionen, die in der oder von der Lib aufgerufen werden aber in meinem Sketch gar nicht aufzufinden sind.. Führt das zu Fehlern oder geben die dann einfach ein Fals zurück?

Wie viele unterschiedliche Befehle gibt es denn? Ist das eine übersichtliche Liste? Gibt es irgendwo eine Liste, alla Reference?

Seriell beginn:
Bei der seriellen Kommunikation meinte ich eigentlich die Bautrate, dass ich meine gelesen zu haben dass die Rate von 115200 mit DCC zusammenhängt. Sonst könnte ich diese ja wie immer auf 9600 oder was das war stellen, hauptsache die ist im Sketch und am PC auf dem seriellen Monitor gleich...
Dachte das hängt irgendwie mit den getimmten Flankenwechsel oder anderen bestimmten Abständen des Signals zusammen... Oder gibt es sonst einen guten Grund dafür genau 115200 zu nehmen?

Magic Numbers:
Das mit dem Pin war genau was ich schrieb: Semi professionelle Sketche.. Lach.. Grundsätzlich also möglich das so zu machen, würde auch funktionieren, aber nicht gerne gesehen und auf die Finger gehauen.. Hab ich verstanden, ich gelobe Besserung...

Achso, ja und was den Sketch angeht..
Sorry, ich hab nicht mehr! :open_mouth:

Ich verlinke hier mal das Video von dem ich das habe:
[YouTube Video DCC Decoder] https://www.youtube.com/watch?v=aA6cgGWZWBE)

Etwa ab 5 Minuten 30 kann man den Sketch sehen.
Der scheint auch so in dieser Kürze zu funktionieren, zu mindest in dem Video.
Deswegen dachte ich ja, die ganze Sache wäre viel einfacher...
:slight_smile:

Leider kann man den Sketch nicht irgendwie in der Videobeschreibung runterladen oder hat einen Link dahin... Musste ihn vom Bildschirm abtippen...

Ich hoffe ihr könnt mich und andere dahin führen, dass es so wie da gezeigt auch tatsächlich bei uns zu Hause funktioniert..

Gute Nacht Bernd

Gar nichts. Die Lib prüft ob die Funktion vorhanden ist, und wenn nicht wird auch nichts aufgerufen.

In der NmraDcc.h sind alle Methoden der Lib mit einer kurzen Erklärung der Parameter aufgeführt und auch alle Callbacks, die Du - je nach Bedarf - in deinem Sketch definieren kannst. Du musst darauf achten, das die Namen und Aufrufparameter exakt so sind, wie sie in der .h beschrieben sind. Die Namen der Callbacks fangen alle mit notify... an

Die Baudrate hat nichts mit DCC zu tun. 9600 Baud ist halt sehr langsam. Mit 115200 funktioniert die Übertragung zum seriellen Monitor wesentlich schneller.

Ab der Zeit wird der Sketch vom Autor schrittweise aufgebaut. Erst zum Schluß des Videos ist er komplett, passt dann aber nicht mehr ins Fenster und ist nur teilweise zu sehen. Du müsstest das also alles mitverfolgen und parallel so eingeben wie er das tut. Ein Grund weshalb ich solche Video-Tutorials gar nicht mag. Mir ist ein geschriebener Beitrag, den ich in 'meinem Tempo' lesen kann lieber. Da sind dann ( normalerweise :wink: ) auch die Sketches komplett enthalten und können rauskopiert werden.

Am einfachsten ist es, die Beispiele der Lib auszuprobieren - die sind jedenfalls komplett.

Wieso abschreiben? unter ...mehr sind doch die ganzen Links, z.B. zum first DCC Decoder

Gruß Tommy

Edit: Link korrigiert. Danke @MicroBahner

Hallo Tommy, dein Link funktioniert leider nicht. Hier ist er komplett.

Ich sende zu später Stunde
ein Hallo hier in die Runde.

Danke für eure Hilfe, dank eurer Unterstützung hatte ich heute Erfolg mit dem Sketch.

Der Code aus dem Link ist allerdings schon der Sketch aus dem nächsten Video, da werden dann schon CVs eingefügt. Da ich den beschriebenen Pin bei mir auf dem DCC Shild nicht habe, glaube den nicht zu haben..
Der ist um in den Programmiermodus zu gehen, oder wie soll ich das verstehen?

void notifyCVAck(void) {

  digitalWrite(ACK_PIN, HIGH);
  delay(10);  
  digitalWrite(ACK_PIN, LOW);
}

Naja, auf jeden Fall hab ich alles was ich nicht benötige rausgestrichen da ich auf das absolut minimalste runter wollte, was tatsächlich nicht viel mehr ist als:

#include <NmraDcc.h>

#define DCC_PIN 2
#define RED_LED 13
#define GREEN_LED 5

#define DECODER_ADDR 4

NmraDcc Dcc;

void notifyDccAccTurnoutOutput(uint16_t Addr, uint8_t Direction, uint8_t OutputPower) {

  if(Addr == DECODER_ADDR) {
    if(Direction == 0) {
      digitalWrite(RED_LED, HIGH);
    } else {
      digitalWrite(RED_LED, LOW);   
    }
  }
    
  Serial.print("Address: "); Serial.println(Addr);
  Serial.print("Direction: "); Serial.println(Direction);
  Serial.print("OutputPower: "); Serial.println(OutputPower);
  Serial.println("--------------------");
}


void setup() {

  Serial.begin(115200);
  pinMode(RED_LED, OUTPUT); 
  Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, false);
  Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER FLAGS_OUTPUT_ADDRESS_MODE, 0);
  Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE, 0);
}

void loop() {

  Dcc.process();
}

Nur das der Sketch dann funktioniert hat, die Zentrale schaltet jetzt die interne Led des Arduino an und aus.
Super, Danke nochmal dafür!

Nur warum funktioniert das jetzt und bei mir gab es nur frustrierende Fehlermeldungen..?

Zum einen hatte ich nicht:

#define DECODER_ADDR 4
und
if(Addr == DECODER_ADDR)

sondern so dirty Numbers mäßig statt dessen

if(Addr == 4)

Aber das sollte ja auch funktionieren..

Aber ich hatte statt:

Serial.print("Address: "); Serial.println(Addr);
nur
Serial.print("Addr: "); Serial.println(Addr);

und bei einem Direction fehlte ein "i" ... :open_mouth: :woozy_face:
deswegen hieß es hier immer not defiend... :face_with_monocle:

und außerdem hatte ich einen Schreibfehler in der Callbackfunktion:

Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER   FLAGS_OUTPUT_ADDRESS_MODE, 0);
was richtig so ausschaut
Dcc.init(MAN_ID_DIY, 1, FLAGS_DCC_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE, 0);

Allerdings war ich beim abtippen des Sketch auch nicht in der Lage dieses Zeichen auf der Tastatur zu erzeugen. Bin ich jetzt auch noch nicht... Ist es ein großes I? Nee.. Wie bekomme ich so ein Zeichen geschrieben?
Das war auf jeden Fall der Hauptgrund.
Jetzt funktioniert mein DCC_blink.ino und ich kann mich jetzt von hier aus hocharbeiten zu dem Funktionsumfang, den ich für mich persönlich brauche.
Bestimmt werde ich mich aber noch mit vielen Fragen an euch wenden..!
:wink:

Gute Nacht
Bernd

ALT GR + <

Links neben dem Y

So kann das aber noch nicht funktionieren, denn die falsche Zeile muss noch raus.

Das Dcc.init ist übrigens keine Callback Funktion. Das ist ja eine Methode aus der Lib, die Du aufrufst. Bei den callback Funktionen ist es umgekehrt, da ist es eine Funktion aus dem Sketch, die die Lib aufruft.

Die folgende Routine wird immer dann durchlaufen, wenn der Dekoder auf dem Programmiergleis programmiert wird und von der DCC-Zentrale einen CV-Befehl empfangen hat (insbesondere wichtig, um Dekoder-CVs zu lesen). Es ist quasi eine Bestätigung vom Dekoder. Dabei wird mit einer entsprechenden Schaltung ein kurzer höherer Strom erzeugt, den die Zentrale erkennen kann. Das wiederum erkennt die Zentrale als Bestätigung vom Dekoder.

void notifyCVAck(void) {

  digitalWrite(ACK_PIN, HIGH);
  delay(10);  
  digitalWrite(ACK_PIN, LOW);
}

Dafür braucht es zusätzliche Hardware.

Hier habe ich mal einen DCC-Monitor veröffentlicht, der alle Befehle der Zentrale im seriellen Monitor darstellt. Hier ist auch eine Schaltung für die Acknowledgements integriert.

https://www.stummiforum.de/t176550f5-DCC-Monitor-auf-Arduino-Basis.html

Hier der sketch: RE: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.4 - 2

Guten Morgen.

Ahh, so macht man das Zeichen. Danke für die Hilfe.
Man lernt nie aus...

Ich hatte die Codezeilen zum Vergleich rein kopiert, das hab ich dann natürlich wieder gelöscht bevor ich das compiliert habe. Hab das hier wohl vergessen raus zu nehmen.
Also so wie das jetzt ist funktioniert es prima für meine Zwecke.
Ich kann jetzt stumpf nach diesem Muster andere Pins und andere Adressen in den Sketch eintragen, für die Ausstellung dieses Jahr soll es so erst mal genügen, dann kann ich das über "Winter" dann immer noch verfeinern und neue Funktionen dazu bringen.

Dann war es ja genau richtig

notifyCVAck

raus zuschmeißen, wenn ich die entsprechende Hardware nicht habe...
Mit CVs wollte ich mich auch erst mal nicht beschäftigen, denn ich kann ja alle Werte die ich ändern will über den Sketch oder den seriellen Monitor eintragen.

Das Projekt aus dem Stummiforum schau ich mir gleich mal an. Ich hatte in dem Forum auch nach passenden Themen gesucht aber entweder keins gefunden oder es wird einem ja immer gleich so viel angezeigt... Und dann muss man sich durch 8 Seiten lesen bis was entscheidendes kommt...

Hier an dieser STelle erst mal vielen Dank. Im Moment sind keine Fragen offen.
Ich melde mich wenn sich das ändert..
:wink:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.