DCC-Monitor auf Arduino-Basis: --> N E U Version 1.4

Bereich für alle Themen rund um Digitaltechnik und digitale Umbauten.
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

DCC-Monitor auf Arduino-Basis: --> N E U Version 1.4

#1

Beitrag von Domapi »

Im Netz geistern ja einige Arduino-Projekte herum, die die DCC-Gleissignale auswerten und am seriellen Monitor darstellen.
Da manche (zumindest bei mir) nicht sauber liefen, teilweise Auswertungsfehler enthalten waren und ein paar Features fehlten, habe ich mir kurzerhand einen eigenen DCC-Monitor, DCC-Sniffer oder DCC-Schnüffler auf Basis der DCC-NMRA-Library programmiert.

Über ein kleines Menü lässt sich die Darstellung am seriellen Monitor des Arduino beeinflussen, also z.B. welche Befehle überhaupt angezeigt werden und ob alle Befehle oder nur diejenigen mit neuen Kommandos. So eine Zentrale wiederholt sich nämlich fortlaufend. Vor allem bei Loks werden permanent Geschwindigkeitsbefehle und die Funktionen F0 - F4 gesendet. Etwas seltener folgen die anderen Funktionsbefehle etc. So kann man sich z.B. auf Lok-Befehle oder nur auf das Zubehör fokussieren.

Schaltet man bei Loks "nur neue Lok-Pakete …" (Option 4) aus, wird ein endloser Stream von DCC-Befehlen angezeigt. So schnell kann man gar nicht lesen, wie die Textzeilen am Bildschirm durchlaufen - Matrix-Effekt eben.

Ganz interessant ist auch, welche und wieviele DCC-Befehle beim CV-Lesen und -Schreiben aufs Gleis gelegt werden.

Ganz hinten im Programm kann nach Belieben die Liste der Loknamen angepasst werden. Dann wird´s nicht ganz so kryptisch.

So sieht das Ganze am Bildschirm aus (beispielhafte Ausgabe):

Code: Alles auswählen

Domapi´s DCC Monitor V 1.0

S t a t i s t i k
-----------------
Zeitraum [sec]         :      315
Anzahl empfangene Bytes:   140455
Gültige Kommandos      :    38626
Ungültige Kommandos    :        0
Idle-Pakete            :    12002
Geschwindigkeitsbefehle:    13723
F0 - F4 Funktionen     :    10476
F5 - F8 Funktionen     :     1494
F9 - F12 Funktionen    :      236
F13 - F20 Funktionen   :      234
F21 - F28 Funktionen   :      182
F29 - F36 Funktionen   :       26
Zubehör-Befehle        :       40
Dekoder-Reset-Befehle  :      162
Zubehör-CV-Befehle     :        0
Lok-CV-Befehle         :        0
Programmiergleisbefehle:       51
Acknowledgments        :       36
Counter Lok            :      208
Counter Acc            :        2
 
 

Tastaturbefehle für den seriellen Monitor:

1 = Anzeige Loks ein/aus                     ein
2 = Anzeige Zubehör ein/aus                  ein
3 = Anzeige CV-Befehle ein/aus               ein
4 = Nur neue Lok-Pakete anzeigen ein/aus     ein
5 = Nur neue Zubehör-Pakete anzeigen ein/aus ein
6 = Nur neue CV-Befehle ein/aus              ein
7 = Statistik anzeigen
? = Befehle anzeigen


Lok     4   P4 KPEV FLM         F0   f1   f2   f3   f4                  0000-0100  1001-0000  1001-0100 
Lok    23   BR 23 Trix         -->> 116                                 0001-0111  0011-1111  1111-0101  1101-1101 
Lok    23   BR 23 Trix          F0   f1   f2   f3   f4                  0001-0111  1001-0000  1000-0111 
Lok  3910   BR 39 105 grün     -->> 115                                 1100-1111  0100-0110  0011-1111  1111-0100  0100-0010 
Lok  3910   BR 39 105 grün      F0   f1   f2   f3   f4                  1100-1111  0100-0110  1001-0000  0001-1001 
Lok   280   BR280 Trix         -->> 104                                 1100-0001  0001-1000  0011-1111  1110-1001  0000-1111 
Lok   280   BR280 Trix          f0   f1   f2   f3   f4                  1100-0001  0001-1000  1000-0000  0101-1001 
Lok    80   BR 80 Trix         -->> 115                                 0101-0000  0011-1111  1111-0100  1001-1011 
Lok    80   BR 80 Trix          F0   f1   f2   f3   f4                  0101-0000  1001-0000  1100-0000 
Lok  3918   BR 39-186 FLM      -->> 104                                 1100-1111  0100-1110  0011-1111  1110-1001  0101-0111 
Lok  3918   BR 39-186 FLM       F0   f1   f2   f3   f4                  1100-1111  0100-1110  1001-0000  0001-0001 
Lok   100   VT10-1              f5   f6   f7   f8                       0110-0100  1011-0000  1101-0100 
Lok    60   V 60 ESU            f5   f6   F7   f8                       0011-1100  1011-0100  1000-1000 
Lok    36   S3/6 Roco Zimo      f5   f6   f7   f8                       0010-0100  1011-0000  1001-0100 
Lok    98   VT 98               f5   f6   f7   f8                       0110-0010  1011-0000  1101-0010 
Lok  5501   G 5/5 Bay.          F5   f6   f7   f8                       1101-0101  0111-1101  1011-0001  0001-1001 
Lok  1016   T16 KPEV FLM        F5   f6   f7   f8                       1100-0011  1111-1000  1011-0001  1000-1010 
Lok    10   P10 Trix            F5   f6   f7   f8                       0000-1010  1011-0001  1011-1011 
Lok    79   V80 Roco            f5   f6   f7   f8                       0100-1111  1011-0000  1111-1111 
Lok   236   V 236 Bawa Zimo     f5   f6   f7   f8                       1100-0000  1110-1100  1011-0000  1001-1100 
Lok  4417   BR 44 Trix          F5   f6   f7   f8                       1101-0001  0100-0001  1011-0001  0010-0001 
Lok  5031   BR 50-319 Roco      F5   f6   f7   f8                       1101-0011  1010-0111  1011-0001  1100-0101 
Lok  3624   S3/6 Trix           F5   F6   f7   f8                       1100-1110  0010-1000  1011-0011  0101-0101 
Weichen-Adresse  6 ( 2 : 2) B On                                        1000-0010  1111-1010  0111-1000 
Weichen-Adresse  6 ( 2 : 2) B Off                                       1000-0010  1111-0010  0111-0000 
Weichen-Adresse  6 ( 2 : 2) A On                                        1000-0010  1111-1011  0111-1001 
Weichen-Adresse  6 ( 2 : 2) A Off                                       1000-0010  1111-0011  0111-0001 
Weichen-Adresse  7 ( 2 : 3) A On                                        1000-0010  1111-1101  0111-1111 
Weichen-Adresse  7 ( 2 : 3) A Off                                       1000-0010  1111-0101  0111-0111 
Weichen-Adresse  6 ( 2 : 2) B On                                        1000-0010  1111-1010  0111-1000 
Weichen-Adresse  6 ( 2 : 2) B Off                                       1000-0010  1111-0010  0111-0000 
Weichen-Adresse  7 ( 2 : 3) B On                                        1000-0010  1111-1100  0111-1110 
Weichen-Adresse  7 ( 2 : 3) B Off                                       1000-0010  1111-0100  0111-0110 
Lok     5   EP5 bayr. FLM      -->> 118                                 0000-0101  0011-1111  1111-0111  1100-1101 
Lok     5   EP5 bayr. FLM      -->> 120                                 0000-0101  0011-1111  1111-1001  1100-0011 
Lok     5   EP5 bayr. FLM      -->> 121                                 0000-0101  0011-1111  1111-1010  1100-0000 
Lok     5   EP5 bayr. FLM      -->> 119                                 0000-0101  0011-1111  1111-1000  1100-0010 
Lok     5   EP5 bayr. FLM      -->> 118                                 0000-0101  0011-1111  1111-0111  1100-1101 
Lok     5   EP5 bayr. FLM      -->> 116                                 0000-0101  0011-1111  1111-0101  1100-1111 
Lok     5   EP5 bayr. FLM      -->> 115                                 0000-0101  0011-1111  1111-0100  1100-1110 
Lok     5   EP5 bayr. FLM      -->> 114                                 0000-0101  0011-1111  1111-0011  1100-1001 
Lok     5   EP5 bayr. FLM      -->> 115                                 0000-0101  0011-1111  1111-0100  1100-1110 
Lok     5   EP5 bayr. FLM      -->> 116                                 0000-0101  0011-1111  1111-0101  1100-1111 
Prg   CV1    Lese    Bit #0                                             0111-1000  0000-0000  1110-0000  1001-1000 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #1                                             0111-1000  0000-0000  1110-0001  1001-1001 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #2                                             0111-1000  0000-0000  1110-0010  1001-1010 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #3                                             0111-1000  0000-0000  1110-0011  1001-1011 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #4                                             0111-1000  0000-0000  1110-0100  1001-1100 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #5                                             0111-1000  0000-0000  1110-0101  1001-1101 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #6                                             0111-1000  0000-0000  1110-0110  1001-1110 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese    Bit #7                                             0111-1000  0000-0000  1110-0111  1001-1111 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Lese CV                                                    0111-0100  0000-0000  0001-0000  0110-0100 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Prg   CV1    Schreibe CV =  16                                          0111-1100  0000-0000  0001-0000  0110-1100 
Prg   Dekoder-Reset-Befehl                                              0000-0000  0000-0000  0000-0000 
Im Programmcode habe ich einiges dokumentiert. Ich habe nur die Ausgaben getestet, die für mich wichtig sind. DCC verwendet nämlich einen ganzen Sack an Kommandos.
Wer schon immer wissen wollte, wie die Kommandos aufgebaut sind, wird im Code ebenfalls fündig. Weitere Doku findet man im Netz.

Viel Spaß bei Schnüffeln :fool:

Update 17.12.2020:
Es gibt eine neue Version des DCC-Monitors, siehe:
https://www.stummiforum.de/viewtopic.ph ... 5#p2208635
Zuletzt geändert von Domapi am Do 17. Dez 2020, 16:59, insgesamt 6-mal geändert.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

fbstr
EuroCity (EC)
Beiträge: 1162
Registriert: So 28. Aug 2016, 21:04
Nenngröße: H0
Stromart: digital
Steuerung: DR5000, Lenz LZV100
Gleise: Peco Code 75, Trix C
Wohnort: Stuttgart
Kontaktdaten:
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#2

Beitrag von fbstr »

Hallo Martin,

durch die MobaLedLib bin ich gerade wieder im Arduino-Fieber und stolperte wieder über Deinen DCC-Sniffer.

Gleich mal heute einen Test gemacht
Bild

und es funktioniert!
Bild

Vielen Dank!
Gruss
Frank
---------------------------------------------------------------------------------------------------------------------
MobaLedLib Wiki
Projekt "Bahnpark Augsburg"
Stummitreff BB: normalerweise jeden 3. Freitag im Monat im Haus Sommerhof in Sindelfingen
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#3

Beitrag von Domapi »

fbstr hat geschrieben: Mi 8. Apr 2020, 22:25
und es funktioniert!
Sagˋ ich doch :clap:

Erfolgreiches Schnüffeln :!:
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

moppe
ICE-Sprinter
Beiträge: 5587
Registriert: So 7. Aug 2011, 08:16
Nenngröße: H0
Stromart: DC
Steuerung: G&R ana/digi - Z21/Lenz/ESU
Gleise: 2L
Wohnort: Norddeutsche Halbinsel.
Kontaktdaten:
Dänemark

Re: DCC-Monitor auf Arduino-Basis

#4

Beitrag von moppe »

Martin

Wenn ist der DCC Ack nötig?

Ich will ihren DCC-Monitor probiere - und vielleicht optimieren und ein kleines Display anhängen.


Klaus
"Meine" Modellbahn: http://www.modelbaneeuropa.dk
Dänisches Bahnforum: http://www.baneforum.dk
PIKO C4 "Horror Gallery": http://moppe.dk/PIKOC4.html
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#5

Beitrag von Domapi »

Der ACK-Schaltungsteil ist nur notwendig, wenn man den Monitor am Programmiergleis betreibt und CVs lesen/schreiben will.
Du kannst ihn auch weglassen, da der Monitor selbst ja keine sinnvollen CVs hat.
Ich habe den Code und die Schaltung gelassen, da ich diese Komponenten für meinen Servodekoder verwendet habe.

Allerdings gibt die NRMA-Library beim Lesen einer CV den Wert des entsprechenden EEPROM-Bytes aus.
Beispielsweise bei CV1 den Wert der EEPROM Speicherstelle #0. Bei einem neuen Nano steht dort normalerweise 255.
Falls der Nano schon anderweitig in Betrieb war, ggf. ein anderer Wert.

Der Monitor sendet dann bei empfangenen CV-Befehlen 6ms - Acknowledgement Impulse.
Die Zentrale wertet diese aus und kann dann z.B. einen CV-Wert ausgeben.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

moppe
ICE-Sprinter
Beiträge: 5587
Registriert: So 7. Aug 2011, 08:16
Nenngröße: H0
Stromart: DC
Steuerung: G&R ana/digi - Z21/Lenz/ESU
Gleise: 2L
Wohnort: Norddeutsche Halbinsel.
Kontaktdaten:
Dänemark

Re: DCC-Monitor auf Arduino-Basis

#6

Beitrag von moppe »

Martin

Ich hab deiner DCC Monitor gestohlen!
Und natürlich weiterbearbeitet für meiner Zweck, wer ist ein kleines DCC display, wo ich hab ein 4x20 char LCD.

Es gibt natürlich Änderungen. Einer die erste ist ein bisschen mehr kompaktes Anschict der daten.
Ein andere ist Leerzeichen und F zu nutzen für Funktionen und nicht f/F.
Weichenbefehle hab seiner eigenen platz auf der Display.

Ihren Monitor funktioniert auch durch der serieller Schnittstelle mit alle funktionen.

Ich hab ein Problem mit DCC mit 28 fahrstufen. Es reagiert nicht immer, aber es ist die selber mit ihren Monitor....

Bild
Geschwindigkeit und richtung

Bild
Funktionen F5 bis F8

Bild
Funktionen F21 bis 28 (F28 ein)

Bild
Funktionen F21 bis 28 (F28 aus)

Klaus
"Meine" Modellbahn: http://www.modelbaneeuropa.dk
Dänisches Bahnforum: http://www.baneforum.dk
PIKO C4 "Horror Gallery": http://moppe.dk/PIKOC4.html
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#7

Beitrag von Domapi »

Hallo Klaus,

:gfm:

Die 28 Fahrstufen habe ich ehrlich gesagt nie getestet, da alle meine Loks 128 Fahrstufen nutzen.
Evtl. Ist da noch ein Fehler in der Auswertung. Werde ich mir gelegentlich ˋmal ansehen.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#8

Beitrag von Domapi »

Hier die Korrekturen:

In Zeile 527 hilft eine zusätzliche "0":

else if (((Befehls_Byte & B11000000) == 0) && (pktByteCount == 3))
{
Befehl = 0; // 00RSSSSS
Funktion = Befehls_Byte; // Speed 28 Stufen
z_lok_speed++;

}

Und ab Zeile 1072 stimmen die Berechnungen nicht, korrekt ist (einmal oben 3 abziehen und unten die "-1" löschen):

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 2:
// Reverse speed step 28 Stufen
// 01xx-xxxx Basis Geschwindigkeits- und Richtungsbefehl
// speed = ((Befehls_Byte & B00001111) << 1) - 3 + bitRead(Befehls_Byte, 4);
speed = ((Befehls_Byte & B00001111) << 1) + ((Befehls_Byte & 0x10) >> 4) - 3;
if (speed == 253 || speed == 254) Serial.print(" Stopp ");
else if (speed == 255 || speed == 0) Serial.print(" Nothalt");
else
{
Serial.print(" <<-- ");
Serial.print(speed);
}
print_spaces(31);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 3: // Forward speed step 28 Stufen
// speed = ((Befehls_Byte & B00001111) << 1) - 3 + bitRead(Befehls_Byte, 4);
speed = ((Befehls_Byte & B00001111) << 1) + ((Befehls_Byte & 0x10) >> 4) - 3;
if (speed == 253 || speed == 254) Serial.print(" Stopp ");
else if (speed == 255 || speed == 0) Serial.print(" Nothalt");
else
{
Serial.print(" -->> ");
Serial.print(speed);
}
print_spaces(31);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

moppe
ICE-Sprinter
Beiträge: 5587
Registriert: So 7. Aug 2011, 08:16
Nenngröße: H0
Stromart: DC
Steuerung: G&R ana/digi - Z21/Lenz/ESU
Gleise: 2L
Wohnort: Norddeutsche Halbinsel.
Kontaktdaten:
Dänemark

Re: DCC-Monitor auf Arduino-Basis

#9

Beitrag von moppe »

Hallo Martin

Deiner email hat mir erreicht, und ich hab ihn antwortet, aber der Antwort könnte nicht liefert werden....

Es gibt Problemen mit 28 Fahrstufen, aber weil ich nicht nutze 28 Fahrstufen, ist es egal für mich.

Ich hab auf Version 1.8 geendet.

Code: Alles auswählen

//-------------------------------------------------------------------------------------------------------
/*
DCC-Monitor zur Ausgabe der DCC-Befehle auf dem seriellen Monitor und 4x20 LCD display
======================================================================================

V 1.0, 18.01.2020 domapi
erweitert bis V 1.7 mit LCD, bei Moppe 19.04.2020

Features:
---------
- Ausgabe der Lok-Befehle
- Ausgabe der Lok-CV-Kommandos
- Ausgabe der Accessory-Befehle
- Ausgabe der Accessory-CV-Kommandos
- Ausgabe der CV-Befehle auf dem Programmiergleis
- Eingaben über seriellen Monitor zur Steuerung der Anzeige
- DCC-Paket-Speicher zum Verhindern der mehrfachen Ausgabe von Befehlen
- einstellbar getrennt nach Loks, Accessories und CVs
- Wurde ein gültiges Paket gefunden und im seriellen Monitor ausgegeben, wird es in einer Tabelle gespeichert
- Vor jeder Paketausgabe wird geprüft, ob es in der Tabelle bereits enthalten ist, d.1h. schon ausgegeben wurde
- Die Tabelle umfasst für Loks 240 x 4 Bytes, ohne Präambel und ohne Check-Byte; für Zubehörbefehle nur 5 x 4 Bytes
(Lok-Befehle werden sehr häufig und vor allem periodisch wiederholt, Zubehör mehrfach, aber nur bei Änderungen )
- Die Tabelle wird sukzessive aufgefüllt, wenn sie voll ist, wird der erste Eintrag gelöscht und alle anderen Einträge nach vorne geschoben
Das neue Paket wandert dann an die letzte Stelle
- Die Tabellengröße sollte für ca. 70 Loks reichen
- Über das Menü kann die Speicherung ein-/aus-geschaltet werden (separat für Acc, CVs, Loks)
- Ausgabe der Lokname in Klartext
- Ausgabe einer Statistik über die detektierten DCC-Befehle

- LCD kann letzter Lok oder Weichen befehl zeigen

Hardware:
---------
- Schaltplan, siehe: https://www.stummiforum.de/viewtopic.php?t=165060&start=225#p1957001
- DCC-Signal-Auswertung über 6N137 Optokoppler, Schutzdiode (1N4148) und Vorwiderstand (1k). Oder über Brückengleichrichter (siehe Link).
Pin 6 Optokoppler mit 10 kOhm an 5V reicht aus. Pin 7 muss nicht an 5V angeschlossen sein, er kann unbelegt bleiben.
- ACK-Signal über Optokoppler CNY17 und Transistor BC557 anschließen, erzeugt Stromimpuls an +/- des Brückengleichrichters.


Arduino Nano:
//                      +-----+
//         +------------| USB |------------+
//         |            +-----+            |
//         | [ ]D13/SCK        MISO/D12[ ] |
//         | [ ]3.3V           MOSI/D11[ ]~|
//         | [ ]V.ref     ___    SS/D10[ ]~|
//         | [ ]A0       / N \       D9[ ]~|
//         | [ ]A1      /  A  \      D8[ ] |
//         | [ ]A2      \  N  /      D7[ ] |
//         | [ ]A3       \_0_/       D6[ ]~|
//         | [ ]A4/SDA               D5[ ]~|
// ACK-Pin | [ ]A5/SCL               D4[ ] |
//         | [ ]A6              INT1/D3[ ]~|
//         | [ ]A7              INT0/D2[ ] |   DCC-Eingang über Optokoppler Pin 6
//         | [ ]5V                  GND[ ] |
//         | [ ]RST                 RST[ ] |
//         | [ ]GND   5V MOSI GND   TX1[ ] |
//         | [ ]Vin   [ ] [ ] [ ]   RX1[ ] |
//         |          [ ] [ ] [ ]          |
//         |          MISO SCK RST         |
//         | NANO-V3                       |
//         +-------------------------------+

LCD:
LCD RS pin to digital pin 12
LCD Enable pin to digital pin 11
LCD D4 pin to digital pin 6
LCD D5 pin to digital pin 5
LCD D6 pin to digital pin 4
LCD D7 pin to digital pin 3
LCD R/W pin to ground
LCD VSS pin to ground
LCD VCC pin to 5V
10K Pot:
ends to +5V and ground
wiper to LCD VO pin (pin 3)


Todos:

- Komplettanzeige für eine Lok auf Basis Puffer
- Anzeige auf bestimmte Adressen beschränken
*/
//-------------------------------------------------------------------------------------------------------

#include <NmraDcc.h>
#include <LiquidCrystal.h>

NmraDcc  Dcc ;

//-------------------------------------------------------------------------------------------------------
// Mit diesen Variablen kann man einstellen, was auf dem seriellen Monitor ausgegeben wird
// Die Einstellungen können während des laufenden Betriebs des DCC-Monitors später im seriellen Monitor geändert werden
//-------------------------------------------------------------------------------------------------------
byte Anzeige_Loks = 1;           // Lok-Befehle für Lok-Dekoder und funktionsdekoder
byte Anzeige_Acc  = 1;           // Zubehör-Befehle für Weichendekoder
byte Anzeige_CV   = 1;           // Ausgabe von CV-Aktionen (Lesen und Schreiben etc.)

byte puffern_Lok  = 1;           // Schaltet die Speicherung und Prüfung bereits empfangener DCC-Pakete ein/aus
byte puffern_Acc  = 1;
byte puffern_CV   = 1;
//-------------------------------------------------------------------------------------------------------

const byte DccAckPin        = A5;    // Arduino-Pin zur Erzeugung eines ACK-Signals

byte blinker                =  5;    // toggelt die LED an Pin 13 jedes 5. Mal, wenn ein DCC-Paket gefunden wurde --> zeigt DCC-Signal an

const byte bufferSizeAcc    = 5;     // Schaltartikelbefehle werden nicht andauernd wiederholt; hier reichen ein paar Pufferplätze aus
const byte bufferSizeLok    = 240;
byte Acc_counter            = 0;     // läuft von 1 - bufferSizeAcc
byte Paket_bekannt_A        = 0;
byte Lok_counter            = 0;     // läuft von 1 - bufferSizeLok
byte Paket_bekannt_L        = 0;

// Strukturen zur Speicherung der bereits empfangenen Werte
typedef struct
{
int ADR;
byte DIR;
byte COIL;
} ACC_Befehl;

typedef struct
{
int ADR;
byte ORDER;
byte FUNC;
} Lok_Befehl;


ACC_Befehl Acc_received [bufferSizeAcc];
Lok_Befehl Lok_received [bufferSizeLok];


byte pktByteCount                = 0;
unsigned int decoderAddress;
unsigned int decoderAddress_alt  = 0;
unsigned int weichenadresse;
byte Ausgang;
byte Spule;
byte Befehl;
byte Funktion;

byte Befehls_Byte;
byte decoderType; //0=Lok, 1=Zubehör/Accessory

byte command;
int  CV_address;
byte CV_value;

byte command_alt      = 0;
int CV_address_alt    = 0;
byte CV_value_alt     = 0;

byte speed;

byte checksum = 0;

// Zähler für die Statistik
unsigned long start_time = 0;
unsigned long z_bytes = 0;
unsigned long z_invalid = 0;
unsigned long z_idle = 0;
unsigned long z_lok_speed = 0;
unsigned long z_lok_F0 = 0;
unsigned long z_lok_F5 = 0;
unsigned long z_lok_F9 = 0;
unsigned long z_lok_F13 = 0;
unsigned long z_lok_F21 = 0;
unsigned long z_lok_F29 = 0;
unsigned long z_acc = 0;
unsigned long z_dec_reset = 0;
unsigned long z_acc_cv = 0;
unsigned long z_lok_cv = 0;
unsigned long z_prg_CV = 0;
unsigned long z_ack = 0;

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

// these constants won't change.  But you can change the size of
// your LCD using them:
const int numRows = 4;
const int numCols = 20;
const int splashdelay = 5000;

//-------------------------------------------------------------------------------------------------------
void setup()
//-------------------------------------------------------------------------------------------------------
{
pinMode(13, OUTPUT);                              // eingebaute LED
Serial.begin(115200);

pinMode(DccAckPin, OUTPUT);                       // Configure the DCC CV Programing ACK pin for an output

Serial.println(F("Domapi´s DCC Monitor V 1.0"));
Serial.println(F("und Moppes DCC display"));

// set up the LCD's number of columns and rows:
lcd.begin(numCols, numRows);

lcd.setCursor(0, 0);
lcd.write("Domapi's DCC-Monitor ");
lcd.setCursor(0, 1);
lcd.write("   erweitert bis:");
lcd.setCursor(0, 2);
lcd.write(" Moppes DCC display");
lcd.setCursor(0, 3);
lcd.write(" von stummiforum.de");
delay(splashdelay);
lcd.clear();
lcd.write("Moppes DCC display  ");

Dcc.pin(0, 2, 1);                                 // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up

Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );        // Call the main DCC Init function to enable the DCC Receiver

start_time = millis();



}


//-------------------------------------------------------------------------------------------------------
void loop()
//-------------------------------------------------------------------------------------------------------
{
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process();

if (Serial.available())
{
// Tastatur-Befehle via seriellen Monitor des Arduinos:

// 1 = Anzeige Loks ein/aus
// 2 = Anzeige Zubehör ein/aus
// 3 = Anzeige CV-Befehle ein/aus
// 4 = Nur neue Lok-Pakete ein/aus
// 5 = Nur neue Zubehör-Pakete ein/aus
// 6 = Nur neue CV-Befehle ein/aus
// 7 = Statistik
// ? = Befehle anzeigen

switch (Serial.read())
{
case 49: // 1
Serial.print(F("1 Anzeige Loks ein/aus = "));
Anzeige_Loks = !Anzeige_Loks;
if (Anzeige_Loks) Serial.println("ein");
else Serial.println("aus");
break;
case 50:  //2
Serial.print(F("2 Anzeige Zubehör ein/aus = "));
Anzeige_Acc = !Anzeige_Acc;
if (Anzeige_Acc) Serial.println("ein");
else Serial.println("aus");
break;
case 51:  // 3
Serial.print(F("3 Anzeige CV-Befehle ein/aus = "));
Anzeige_CV = !Anzeige_CV;
if (Anzeige_CV) Serial.println("ein");
else Serial.println("aus");
break;
case 52:  // 4
Serial.print(F("4 Nur neue Lok-Pakete anzeigen ein/aus = "));
puffern_Lok = !puffern_Lok;
if (puffern_Lok) Serial.println("ein");
else Serial.println("aus");
break;
case 53:  // 5
Serial.print(F("5 Nur neue Zubehör-Pakete anzeigen ein/aus = "));
puffern_Acc = !puffern_Acc;
if (puffern_Acc) Serial.println("ein");
else Serial.println("aus");
break;
case 54:  // 6
Serial.print(F("6 Nur neue CV-Befehle anzeigen ein/aus = "));
puffern_CV = !puffern_CV;
if (puffern_CV) Serial.println("ein");
else Serial.println("aus");
break;
case 55:  // 7
Serial.println();
Serial.println(F("S t a t i s t i k"));
Serial.println(F("-----------------"));
Serial.print(F("Zeitraum [sec]         :")); print_Zahl_rechts_ln((millis() - start_time) / 1000);

Serial.print(F("Anzahl empfangene Bytes:")); print_Zahl_rechts_ln(z_bytes);
Serial.print(F("Gültige Kommandos      :"));
print_Zahl_rechts_ln(z_invalid + z_idle + z_lok_speed + z_lok_F0 + z_lok_F5 + z_lok_F9 + z_lok_F13 + z_lok_F21 + z_lok_F29 + z_acc + z_dec_reset + z_acc_cv + z_lok_cv + z_prg_CV);
Serial.print(F("Ungültige Kommandos    :")); print_Zahl_rechts_ln(z_invalid);
Serial.print(F("Idle-Pakete            :")); print_Zahl_rechts_ln(z_idle);

Serial.print(F("Geschwindigkeitsbefehle:")); print_Zahl_rechts_ln(z_lok_speed);
Serial.print(F("F0 - F4 Funktionen     :")); print_Zahl_rechts_ln(z_lok_F0);
Serial.print(F("F5 - F8 Funktionen     :")); print_Zahl_rechts_ln(z_lok_F5);
Serial.print(F("F9 - F12 Funktionen    :")); print_Zahl_rechts_ln(z_lok_F9);
Serial.print(F("F13 - F20 Funktionen   :")); print_Zahl_rechts_ln(z_lok_F13);
Serial.print(F("F21 - F28 Funktionen   :")); print_Zahl_rechts_ln(z_lok_F21);
Serial.print(F("F29 - F36 Funktionen   :")); print_Zahl_rechts_ln(z_lok_F29);

Serial.print(F("Zubehör-Befehle        :")); print_Zahl_rechts_ln(z_acc);

Serial.print(F("Dekoder-Reset-Befehle  :")); print_Zahl_rechts_ln(z_dec_reset);
Serial.print(F("Zubehör-CV-Befehle     :")); print_Zahl_rechts_ln(z_acc_cv);
Serial.print(F("Lok-CV-Befehle         :")); print_Zahl_rechts_ln(z_lok_cv);
Serial.print(F("Programmiergleisbefehle:")); print_Zahl_rechts_ln(z_prg_CV);
Serial.print(F("Acknowledgments        :")); print_Zahl_rechts_ln(z_ack);

Serial.print(F("Counter Lok            :")); print_Zahl_rechts_ln(Lok_counter);
Serial.print(F("Counter Acc            :")); print_Zahl_rechts_ln(Acc_counter);
break;
case 63:  // ?
Serial.println(); Serial.println(F("Tastaturbefehle für den seriellen Monitor:")); Serial.println();
Serial.print  (F("1 = Anzeige Loks ein/aus                     "));
if (Anzeige_Loks) Serial.println("ein");
else Serial.println("aus");
Serial.print  (F("2 = Anzeige Zubehör ein/aus                  "));
if (Anzeige_Acc) Serial.println("ein");
else Serial.println("aus");
Serial.print  (F("3 = Anzeige CV-Befehle ein/aus               "));
if (Anzeige_CV) Serial.println("ein");
else Serial.println("aus");
Serial.print  (F("4 = Nur neue Lok-Pakete anzeigen ein/aus     "));
if (puffern_Lok) Serial.println("ein");
else Serial.println("aus");
Serial.print  (F("5 = Nur neue Zubehör-Pakete anzeigen ein/aus "));
if (puffern_Acc) Serial.println("ein");
else Serial.println("aus");
Serial.print  (F("6 = Nur neue CV-Befehle ein/aus              "));
if (puffern_CV) Serial.println("ein");
else Serial.println("aus");
Serial.println(F("7 = Statistik anzeigen"));
Serial.println(F("? = Befehle anzeigen"));
break;
}
Serial.println(" ");
}
}


//-------------------------------------------------------------------------------------------------------
// This function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
void notifyCVAck()
//-------------------------------------------------------------------------------------------------------
{
digitalWrite( DccAckPin, HIGH );
delay( 6 );
digitalWrite( DccAckPin, LOW );
z_ack++;
}


//-------------------------------------------------------------------------------------------------------
void notifyDccMsg(DCC_MSG * Msg)
//-------------------------------------------------------------------------------------------------------
{
// LED toggeln
blinker--;
if (blinker == 0)
{
digitalWrite(13, !digitalRead(13));
blinker = 5;
}

//-------------------------------------------------------------------------------------------------------------------------------
// Alle gefunden Bytes XOR-verknüpfen; muss 0 ergeben, dann wurde ein gültiger Befehl gefunden!
//-------------------------------------------------------------------------------------------------------------------------------

pktByteCount = Msg->Size;                       // Anzahl gefundene Bytes ohne Präambel aber incl. Prüfbyte !!!
checksum = 0;                                   // Wir starten mit 0
z_bytes = z_bytes + pktByteCount;

for (byte n = 0; n < pktByteCount; n++)
{
checksum ^= Msg->Data[n];
}
if (checksum)
{
z_invalid++;
return; // Ungültige Checksumme --> nix tun !
}

//-------------------------------------------------------------------------------------------------------------------------------
// Start Dekodierung
//-------------------------------------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------------------------------------
// Idle Kommando
//-------------------------------------------------------------------------------------------------------------------------------
if (Msg->Data[0] == B11111111)
{
z_idle++;
return;                  // Idle packet
}





//-------------------------------------------------------------------------------------------------------------------------------
// Reset Befehl zur Einleitung der CV-Programmierung
//-------------------------------------------------------------------------------------------------------------------------------
if (Msg->Data[0] == 0)
{
z_dec_reset++;

command    = Msg->Data[0];
CV_address = Msg->Data[1];
CV_value   = Msg->Data[2];

// Nur verarbeiten, wenn neuer Befehl!
if (!(((CV_value == CV_value_alt) && (CV_address == CV_address_alt) && (command == command_alt)) && puffern_CV))
{
Serial.print(F("Prg   Dekoder-Reset-Befehl"));
print_spaces(43);
printPacket(Msg);

command_alt    = command;
CV_address_alt = CV_address;
CV_value_alt   = CV_value;
}
return;
}
//-------------------------------------------------------------------------------------------------------------------------------
// Programmiermodus auf dem Programmiergleis ohne Adresse !
//-------------------------------------------------------------------------------------------------------------------------------
if ((Msg->Data[0] & B11110000) == B01110000)
{
/*  Service Mode.Prog: [preamble] 0 [0111CCVV] 0 [VVVVVVVV] 0 [DDDDDDDD] 0 [EEEEEEEE] 1
                         CC = Command
                           VV VVVVVVVV = 10 bit CV Number
                                               DDDDDDDD = New Value (8 bit)
                                                            EEEEEEEE = Checksum
Lesen/Schreiben auf dem Prg.gleis geht ohne Dekoderadresse !

Schreiben: z.B. CV 6, Wert 20 (--> 4 Bytes ohne Präambel und Trennbits!)
Byte 0   Byte 1   Byte 2   Byte 3
01111100 -----101 ---10100 10000001

0111CCVV VVVVVVVV DDDDDDDD EEEEEEEE
11 = Schreiben
01 = Lesen/Überprüfen
10 = 10 Bit Manipulation
V = CV - 1 --> 5 = CV 5 + 1 = CV6 !
               D = 20                */
z_prg_CV++;

// Nur verarbeiten, wenn neuer Befehl!
command    = Msg->Data[0] & B00001100;                                    // 2 Bits enthalten den Schreib-/ Verify-Befehl etc.
CV_address = ((Msg->Data[0] & B00000011) * 256) + Msg->Data[1] + 1;       // Nummer der CV
CV_value   = Msg->Data[2];                                                // CV-Wert für das Schreiben

if (!(((CV_value == CV_value_alt) && (CV_address == CV_address_alt) && (command == command_alt)) && puffern_CV))
{
decoderType = 255;      // vorsichtshalber mal auf einen dämlichen Wert setzen, damit weiter unten nix passiert

Serial.print("Prg   CV");

CV_address = ((Msg->Data[0] & B00000011) * 256) + Msg->Data[1] + 1;
Serial.print(CV_address);
if (CV_address < 1000) Serial.print(" ");
if (CV_address < 100) Serial.print(" ");
if (CV_address < 10) Serial.print(" ");
Serial.print(" ");

switch (Msg->Data[0] & B00001100)
{
/*  Die für den Befehlstyp (xxxx-KKxx) im ersten Befehlsbyte festgelegten Werte sind:
KK = 00 – reserviert
KK = 01 – Byte Überprüfen
KK = 11 – Byte Schreiben
KK = 10 – Bit Manipulation*/

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00000100: // Verify Byte
Serial.print(F("Lese CV"));
print_spaces(49);
break;

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00001100: // Write Byte

Serial.print(F("Schreibe CV ="));
if (Msg->Data[2] < 100) Serial.print(" ");
if (Msg->Data[2] < 10) Serial.print(" ");
Serial.print(" ");
Serial.print(Msg->Data[2]);
print_spaces(39);
break;

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00001000: // Bit Write
// 0111-10VV VVVV-VVVV 111K-DBBB EEEE-EEEE --> im Programmiermodus für Zugriffe auf einzelne Bits
// K = 1 – Bit Schreiben
// K = 0 – Bit Überprüfen
if (Msg->Data[2] & B00010000)
{
Serial.print("Schreibe Bit #");
Serial.print(Msg->Data[2] & B00000111);
Serial.print(" = ");
Serial.print((Msg->Data[2] & B00001000) >> 3);
print_spaces(36);
}
else
{
Serial.print("Lese    Bit #");
Serial.print(Msg->Data[2] & B00000111);
print_spaces(42);
}
break;
}
printPacket(Msg);

command_alt    = command;
CV_address_alt = CV_address;
CV_value_alt   = CV_value;

return;
}
}
else
{
//-------------------------------------------------------------------------------------------------------------------------------
// 0xxx-xxxx -->  bit7=0 -> Lok Dekoder kurze Adresse
//-------------------------------------------------------------------------------------------------------------------------------
if (!bitRead(Msg->Data[0], 7))
{
decoderType = 0;                                    // Lok
decoderAddress = Msg->Data[0];                      // kurze Adresse
Befehls_Byte = Msg->Data[1];

// Aufteilung der gefundenen Bytes auf Befehle (Was soll der Dekoder tun?) und Funktionen (Wie soll er es tun?)

if ((Befehls_Byte & B11100000) == B10000000)
{
Befehl = B00000100;                             // 100 = F0 - F4
Funktion = Befehls_Byte & B00011111;            // x-xxxx = F0 F4 - F1
z_lok_F0++;
}

else if ((Befehls_Byte & B11110000) == B10110000)
{
Befehl = B00001011;                             // 1011 = F5 - F8
Funktion = Befehls_Byte & B00001111;            // xxxx = F8 - F5
z_lok_F5++;
}

else if ((Befehls_Byte & B11110000) == B10100000)
{
Befehl = Befehls_Byte >> 4;                     // 1010 = F9 - F12
Funktion = Befehls_Byte & B00001111;            // xxxx = F12 - F9
z_lok_F9++;
}

else if (Befehls_Byte == B11011110)
{
Befehl = Befehls_Byte;                          // 1101-1110 = F13 - F20
Funktion = Msg->Data[2];                        // xxxx-xxxx = F20 - F13
z_lok_F13++;
}
else if (Befehls_Byte == B11011111)
{
Befehl = Befehls_Byte;                          // 1101-1111 = F21 - F28
Funktion = Msg->Data[2];                        // xxxx-xxxx = F28 - F21
z_lok_F21++;
}
else if (Befehls_Byte == B11011000)
{
Befehl = Befehls_Byte;                          // 1101-1000 = F29 - F36
Funktion = Msg->Data[2];                        // xxxx-xxxx = F36 - F29
z_lok_F29++;
}
else if (((Befehls_Byte & B11000000) == 0) && (pktByteCount == 3))
{
Befehl = 0;                                     // 00RSSSSS
Funktion = Befehls_Byte;                        // Speed 28 Stufen
z_lok_speed++;

}
else if (((Befehls_Byte & B11000000) == 64) && (pktByteCount == 4))  // Adr 10000 ???
{
Befehl = 0;                                    // 00RSSSSS
Funktion = Befehls_Byte;                       // Speed 28 Stufen
z_lok_speed++;
}

else if ((Befehls_Byte == B00111111) && (pktByteCount == 4))
{
Befehl = Befehls_Byte;                         // 00111111
Funktion = Msg->Data[2];                       // RSSSSSSS Speed 127 Stufen
z_lok_speed++;
}
}
else
{
//-------------------------------------------------------------------------------------------------------------------------------
// 11xx-xxxx -->  bit7 = 1 AND bit6 = 1 -> Lok Dekoder lange Adresse
//-------------------------------------------------------------------------------------------------------------------------------
if (bitRead(Msg->Data[0], 6))
{
// 11xx-xxxx
decoderAddress = 256 * (Msg->Data[0] & B00111111) + Msg->Data[1];
Befehls_Byte = Msg->Data[2];
decoderType = 0;

// Aufteilung der gefundenen Bytes auf Befehle und Funktionen

if ((Befehls_Byte & B11100000) == B10000000)
{
Befehl = B00000100;                     // 100 = F0 - F4
Funktion = Befehls_Byte & B00011111;    // x-xxxx = F0 F4 - F1
z_lok_F0++;
}

else if ((Befehls_Byte & B11110000) == B10110000)
{
Befehl = B00001011;                     // 1011 = F5 - F8
Funktion = Befehls_Byte & B00001111;    // xxxx = F8 - F5
z_lok_F5++;
}

else if ((Befehls_Byte & B11110000) == B10100000)
{
Befehl = B00001010;                     // 1010 = F9 - F12
Funktion = Befehls_Byte & B00001111;    // xxxx = F12 - F9
z_lok_F9++;
}

else if (Befehls_Byte == B11011110)
{
Befehl = Befehls_Byte;                  // 1101-1110 = F13 - F20
Funktion = Msg->Data[3];                // xxxx-xxxx = F20 - F13
z_lok_F13++;
}
else if (Befehls_Byte == B11011111)
{
Befehl = Befehls_Byte;                  // 1101-1111 = F21 - F28
Funktion = Msg->Data[3];                // xxxx-xxxx = F28 - F21
z_lok_F21++;
}
else if (Befehls_Byte == B11011000)
{
Befehl = Befehls_Byte;                  // 1101-1000 = F29 - F36
Funktion = Msg->Data[2];                // xxxx-xxxx = F36 - F29
z_lok_F29++;
}
else if (((Befehls_Byte & B11000000) == 0) && (pktByteCount == 4))
{
Befehl = 0;                             // 00RSSSSS
z_lok_speed++;
Funktion = Befehls_Byte;                // Speed 28 Stufen
}
else if (((Befehls_Byte & B11000000) == 64) && (pktByteCount == 4))  // Adr 10000 ???
{
Befehl = 0;                             // 00RSSSSS
Funktion = Befehls_Byte;                // Speed 28 Stufen
z_lok_speed++;
}

else if ((Befehls_Byte == B00111111) && (pktByteCount == 5))
{
Befehl = Befehls_Byte;                 // 00111111
Funktion = Msg->Data[3];               // RSSSSSSS Speed 127 Stufen
z_lok_speed++;
}
}
//-------------------------------------------------------------------------------------------------------------------------------
else   //bit7=1 AND bit6=0 -> Accessory Decoder
{
// 10xx-xxxx
//-------------------------------------------------------------------------------------------------------------------------------

decoderAddress = Msg->Data[0] & B00111111;
Befehls_Byte = Msg->Data[1];
decoderType = 1;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------
if (decoderType == 1)   // Accessory Basic
{
if (Anzeige_Acc && (Msg->Size != 6) )
{
z_acc++;

if ((Befehls_Byte & B10000000) && (Msg->Size == 3))   // Steuerbefehl für Zubehör Dekoder (Basic Accessory)
{
// die Zentrale sendet für Magnetartikel (accessories) immer ein Paket bestehend aus Adresse (= Signal), Richtung (rot/grün) und ein/aus (Spule).
// Zunächst wird eine Richtung eingeschaltet, dazu wird das DCC-Telegramm ggf. mehrfach wiederholt
// Bei der ECOS wird nach einer einstellbaren Zeit pro "Magnetartikel" ein Ausschaltbefehl (auch mehrfach) hinterhergeschickt

/*  Für Zubehör-/Weichendekoder sendet die DCC-Zentrale 3 Bytes:
Byte 1                      Byte 2                        Byte 3
                       __ __ __
1  0 A7 A6 A5 A4 A3 A2   :   1 AA A9 A8  P A1 A0  R   :   C7 C6 C5 C4 C3 C2 C1 C0

- AA..A0 sind die 11 Bit Adresse eines Zubehördekoders ("Addr")
- P = Power (0 = off, 1 = on) ("OutputPower"), bei Spulenantrieben von Weichen sind das Spule 1 und Spule 2
- R = Schaltrichtung (in welche Richtung "Direction" sich der Servo bewegt, 0 = rot, 1 = grün)
- C7..C0 = Checkbyte (Byte_3 = Byte_1 XOR Byte_2)

- Das 1. Byte beginnt immer mit "10" --> 10XX XXXX (Bit#7 = 1, Bit#6 = 0)
- Das 2. Byte beginnt immer mit "1"  --> 1XXX XXXX (Bit#7 = 1)
- Das 3. Byte dient der überprüfung der gesendeten Informationen: Byte_3 = Byte_1 XOR Byte_2

- Die 11 Bit Adresse des zu steuernden Spulenpaares entsteht aus den 11 Adress-Bits (AA ... A0). Dabei ist zu
beachten, dass die Bits AA, A9, A8 invertiert im ursprünglichen DCC-Paket abgebildet sind.
*/

decoderAddress = (((~Befehls_Byte)&B01110000) << 2) + decoderAddress;
Ausgang = (Befehls_Byte & B00000110) >> 1;
Spule   = (bitRead(Befehls_Byte, 3));
weichenadresse = (decoderAddress - 1) * 4 + Ausgang + 1;

if (puffern_Acc)
{
//-------------------------------------------------------------------------------------------------------------------------------
// alle Werte im Puffer ausgeben
// Schauen im Array, ob die gefundenen Bytes schon einmal ausgegeben wurden
if (Acc_counter > 0)
{
for (byte j = 0; j < Acc_counter; j++)
{
Paket_bekannt_A = 0;

if (Acc_received [j].ADR == weichenadresse)
{
Paket_bekannt_A++;
}
if (Acc_received [j].DIR == Ausgang)
{
Paket_bekannt_A++;
}
if (Acc_received [j].COIL == Spule)
{
Paket_bekannt_A++;
}

if (Paket_bekannt_A == 3)
{
return;  // nix machen, keine Ausgabe im seriellen Monitor: war lediglich eine Wiederholung !
}
}
}

if (Acc_counter > 0)
{
// Pufferzeilen mit der gleichen Adresse rauslöschen
for (byte j = 0; j < Acc_counter; j++)
{
if (Acc_received [j].ADR == weichenadresse)
{
// Befehl mit der gleichen Adresse aus der Puffertabelle löschen!
// dazu beginnend mit der Zeile j alle weiter hinten vorziehen, bis Pufferende oder mindestens bis Acc_counter

for (byte k = j; k < min (Acc_counter, bufferSizeAcc - 1); k++)
{
Acc_received [k].ADR = Acc_received [k + 1].ADR;
Acc_received [k].DIR = Acc_received [k + 1].DIR;
Acc_received [k].COIL = Acc_received [k + 1].COIL;
}

//                           }
Acc_counter--; // ein Eintrag wurde gelöscht
}
}
}
// eine Zeile im Acc_received mit neuem Paket befüllen
if (Acc_counter < bufferSizeAcc)
{
Acc_received [Acc_counter].ADR = weichenadresse;
Acc_received [Acc_counter].DIR = Ausgang;
Acc_received [Acc_counter].COIL = Spule;
Acc_counter++;
}
else
{
// ersten ältesten Wert löschen und alle anderen Wertepaare nach links rücken
for (byte j = 0; j < bufferSizeAcc - 1; j++)
{
Acc_received [j].ADR = Acc_received [j + 1].ADR;
Acc_received [j].DIR = Acc_received [j + 1].DIR;
Acc_received [j].COIL = Acc_received [j + 1].COIL;

}
// den letzten Eintrag nun dem neuen Paket befüllen

Acc_received [bufferSizeAcc - 1].ADR = weichenadresse;
Acc_received [bufferSizeAcc - 1].DIR = Ausgang;
Acc_received [bufferSizeAcc - 1].COIL = Spule;

Acc_counter = bufferSizeAcc;
}
}
//-------------------------------------------------------------------------------------------------------------------------------
// Zubehör-Daten ausgeben

Serial.print(F("Weichen-Adresse "));
lcd.setCursor(0, 3);
lcd.write("                    ");
lcd.setCursor(0, 3);
lcd.write("W ");
if ((decoderAddress - 1) * 4 + Ausgang + 1 < 10) Serial.print(" ");
Serial.print((decoderAddress - 1) * 4 + Ausgang + 1);
lcd.print((decoderAddress - 1) * 4 + Ausgang + 1, DEC);
Serial.print(" (");
lcd.write(" (");
if (decoderAddress < 10) Serial.print(" ");
Serial.print(decoderAddress);
lcd.print(decoderAddress, DEC);
Serial.print(" : ");
lcd.write(":");
Serial.print(Ausgang + 1);
lcd.print(Ausgang + 1, DEC);
Serial.print(")");
lcd.write(")");
if (bitRead(Befehls_Byte, 0)) {
Serial.print(" A");
lcd.write(" A");
}
else {
Serial.print(" B");
lcd.write(" B");
}
if (bitRead(Befehls_Byte, 3)) {
Serial.print(" On ");
lcd.write(" On ");
}
else {
Serial.print(" Off");
lcd.write(" Off");
}
print_spaces(36);
}
else   // Accessory Extended NMRA --> noch nicht getestet !!!
{
Serial.print("Acc Ext ");
decoderAddress = (decoderAddress << 5) + ((Befehls_Byte & B01110000) >> 2) + ((Befehls_Byte & B00000110) >> 1);
Serial.print(decoderAddress);
Serial.print(" Asp ");
Serial.print(Msg->Data[2], BIN);
}
printPacket(Msg);
}

//----------------------------------------------------------------------------------------------------------------------------------------
// CV-Befehle für Schaltdekoder POM

if (Anzeige_CV && (Msg->Size == 6))      // 6 Bytes --> d.h. CV-Befehle für Schaltdekoder !
{
z_acc_cv++;

/*  ECOS: POM-Schaltartikel POM-Adresse 12, CV 6, Wert 20 Schreiben:  (6 Bytes ohne Präambel und Trennbits!)
Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5
10001100 11110000 11101100 -----101 ---10100 10000001
___                                                  3 MSB der Adresse sind invertiert !
10AAAAAA 1AAACDDD 1110CCVV VVVVVVVV DDDDDDDD EEEEEEEE
11 = Adresse 12
            11 = Schreiben
            10 = Lesen
              V = CV + 1 --> 5 + 1 = 6
                             20
Lesen:
10001100 11110000 11100100 -----101 -------0 10011101

Bas.Op.Mode.Prog [preamble]0[10AAAAAA]0[1AAACDDD]0[CVACCESS]0[EEEEEEEE]1
AAAAAA AAA1DDD = Output Address
AAAAAA AAA0000 = Decoder Address
CVACCESS = DCC Programming CMD
EEEEEEEE = Checksum

CVACCESS [1110CCVV]0[VVVVVVVV]0[DDDDDDDD]
CC = Command
CC = 01 Verify Byte
CC = 11 Write Byte
CC = 10 Bit Manipulation
VV VVVVVVVV = CV Number
DDDDDDDD = New Value
EEEEEEEE = Checksum
*/

decoderAddress = (((~Msg->Data[1]) & B01110000) << 2) + (Msg->Data[0] & B00111111);         // Adresse ist in 2 Bytes kodiert, MSB invertiert in Byte1 (Bit4-6) und der Rest in Byte0 (Bit 0-5)
command = Msg->Data[2] & B00001100;                                                         // 2 Bits enthalten den Schreib-/ Verify-Befehl etc.
CV_address = ((Msg->Data[2] & B00000011) * 256) + Msg->Data[3] + 1;                         // Nummer der CV
CV_value = Msg->Data[4];                                                                    // CV-Wert für das Schreiben

if (!(((decoderAddress == decoderAddress_alt) && (CV_address == CV_address_alt) && (command == command_alt)) && puffern_CV))     // immer ausgeben
{
switch (command)
{
case 12:        //B1100 --> 12 ==> Schreiben

Serial.print(F("Acc    " ));
Serial.print(decoderAddress);
if (decoderAddress < 100) Serial.print("  ");
if (decoderAddress < 10)  Serial.print("  ");

Serial.print(" CV ");
Serial.print(CV_address); Serial.print(" ");
if (CV_address < 100) Serial.print(" ");
if (CV_address < 10)  Serial.print(" ");

Serial.print(F("Schreibe CV ="));
if (CV_value < 100) Serial.print(" ");
if (CV_value < 10) Serial.print(" ");
Serial.print(" ");
Serial.print(CV_value);
print_spaces(33);
break;

case 4:         //B0100 -->  4 ==> Lesen

Serial.print(F("Acc    " ));
Serial.print(decoderAddress);
if (decoderAddress < 100) Serial.print(" ");
if (decoderAddress < 10)  Serial.print(" ");

Serial.print("  CV ");
Serial.print(CV_address); Serial.print(" ");
if (CV_address < 100) Serial.print(" ");
if (CV_address < 10)  Serial.print(" ");
Serial.print(F("Lese CV "));
print_spaces(42);
break;

case 8:         //B1000 ==> Bit-Gefummel !

// ... 111K-DBBB EEEE-EEEE --> Zugriffe auf einzelne Bits
// K = 1 – Bit Schreiben
// K = 0 – Bit Überprüfen

if (Msg->Data[pktByteCount - 2] & B00010000)
{
Serial.print("Schreibe Bit #");
Serial.print(Msg->Data[pktByteCount - 2] & B00000111);
Serial.print(" = ");
Serial.print((Msg->Data[pktByteCount - 2] & B00001000) >> 3);
print_spaces(36);
}
else
{
Serial.print("Lese    Bit #");
Serial.print(Msg->Data[2] & B00000111);
print_spaces(41);
}
break;

}
printPacket(Msg);

decoderAddress_alt = decoderAddress;
CV_address_alt =  CV_address;
command_alt = command;
}
return;
}
}

//-------------------------------------------------------------------------------------------------------------------------------
else if (decoderType == 0)       // --> Lok / Funktionsdekoder
{
/*  Aufbau der Fahrbefehle:
Fahrbefehl, kurze Adressen
Byte 7 6 5 4 3 2 1 0
---------------------------------------------------------------------------
0    0 A A A A A A A    Adresse 7 Bit
1    0 0 R S S S S S    R = Fahrtrichtung, Sn = Geschwindigkeit 28 Stufen
2          XOR          Prüfbyte

0    0 A A A A A A A    Adresse 7 Bit
1    0 0 1 1 1 1 1 1    Befehlsbyte 0x3F
2    R S S S S S S S    R = Fahrtrichtung, Sn = Geschwindigkeit 127 Stufen
3          XOR          Prüfbyte

- Fahrbefehl 28 Stufen: unsigned char speed = ((Byte[1] & 0x0F) << 1) + ((Byte[1] & 0x10) >> 4);
- Fahrbefehl 127 Stufen: unsigned char speed = Byte[2] & 0x7F;

Fahrbefehl, lange Adressen
Byte 7 6 5 4 3 2 1 0
---------------------------------------------------------------------------
0    1 1 A A A A A A    Adresse 6 Bit
1    A A A A A A A A    Adresse 8 Bit
2    0 0 R S S S S S    R = Fahrtrichtung, Sn = Geschwindigkeit 28 Stufen
3          XOR          Prüfbyte

Byte 7 6 5 4 3 2 1 0
---------------------------------------------------------------------------
0    1 1 A A A A A A    Adresse 6 Bit
1    A A A A A A A A    Adresse 8 Bit
2    0 0 1 1 1 1 1 1    Befehlsbyte 0x3F
3    R S S S S S S S    R = Fahrtrichtung, Sn = Geschwindigkeit 127 Stufen
4          XOR          Prüfbyte

- Fahrbefehl 28 Stufen: unsigned char speed = ((Byte[2] & 0x0F) << 1) + ((Byte[2] & 0x10) >> 4);
- Fahrbefehl 127 Stufen: unsigned char speed = Byte[3] & 0x7F;

*/
if (Anzeige_Loks )
// zu Testzwecken filtern auf bestimmte Lok-Adresse
// if (Anzeige_Loks && (decoderAddress == 42 || decoderAddress == 888))
// if (Anzeige_Loks && (decoderAddress < 25))
{
byte instructionType = Befehls_Byte >> 5;

/*  Bits 7-6-5 sind relevant, ergibt 0 - 7 =  8 unterschiedliche Befehlstypen
0 = Control ??
1 = 0011-1111 128 Geschwindigkeitsstufen-Befehl, 0011-1110 Sonderbetriebsarten-Befehl
2 = 01xx-xxxx Basis Geschwindigkeits- und Richtungsbefehl rückwärts 28 Stufen
3 = 01xx-xxxx Basis Geschwindigkeits- und Richtungsbefehl vorwärts  28 Stufen
4 = Lok Funktionen F0, F1 - F4
5 = Lok-Funktionen F5 - F12
6 = Lok-Funktionen F13 - F36
7 = CVs                                 */

if (puffern_Lok)
{
// Schauen im Array, ob die gefundenen Bytes schon einmal ausgegeben wurden
if (Lok_counter > 0)
{
for (byte j = 0; j < Lok_counter; j++)
{
Paket_bekannt_L = 0;
if (Lok_received [j].ADR == decoderAddress)
{
Paket_bekannt_L++;
}
if (Lok_received [j].ORDER == Befehl)
{
Paket_bekannt_L++;
}
if (Lok_received [j].FUNC == Funktion)
{
Paket_bekannt_L++;
}

if (Paket_bekannt_L == 3)
{
return;  // nix machen, keine Ausgabe im seriellen Monitor: war lediglich eine Wiederholung !
}
}
}
if (Lok_counter > 0)
{
// Pufferzeilen mit der gleichen Adresse und dem gleichen Befehl rauslöschen
for (byte j = 0; j < Lok_counter; j++)
{
if (Lok_received [j].ADR == decoderAddress && Lok_received [j].ORDER == Befehl)                   // && Lok_received [j].FUNC == Funktion )
{
for (byte k = j; k < min (Lok_counter, bufferSizeLok - 1); k++)
{
Lok_received [k].ADR   = Lok_received [k + 1].ADR;
Lok_received [k].ORDER = Lok_received [k + 1].ORDER;
Lok_received [k].FUNC  = Lok_received [k + 1].FUNC;
}

Lok_counter--; // ein Eintrag wurde gelöscht
}
}
}

// eine Zeile im Acc_received mit neuem Paket befüllen
if (Lok_counter < bufferSizeLok)
{
Lok_received [Lok_counter].ADR   = decoderAddress;
Lok_received [Lok_counter].ORDER = Befehl;
Lok_received [Lok_counter].FUNC  = Funktion;
Lok_counter++;
}
else
{
// ersten ältesten Wert löschen und alle anderen Wertepaare nach links rücken
for (byte j = 0; j < bufferSizeLok - 1; j++)
{
Lok_received [j].ADR   = Lok_received [j + 1].ADR;
Lok_received [j].ORDER = Lok_received [j + 1].ORDER;
Lok_received [j].FUNC  = Lok_received [j + 1].FUNC;

}
// den letzten Eintrag nun mit dem neuen Paket befüllen

Lok_received [bufferSizeLok - 1].ADR   = decoderAddress;
Lok_received [bufferSizeLok - 1].ORDER = Befehl;
Lok_received [bufferSizeLok - 1].FUNC  = Funktion;

Lok_counter = bufferSizeLok;
}
}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Serial.print("Lok ");
lcd.setCursor(0, 1);
lcd.write("                    ");
lcd.setCursor(0, 2);
lcd.write("                    ");
lcd.setCursor(0, 1);
lcd.write("L");
if (decoderAddress < 10) {
Serial.print("    ");
lcd.print("   ");
}
else if (decoderAddress < 100) {
Serial.print("   ");
lcd.print("  ");
}
else if (decoderAddress < 1000) {
Serial.print("  ");
lcd.print(" ");
}
else if (decoderAddress < 10000) {
Serial.print(" ");
lcd.print("");
}
Serial.print(decoderAddress); Serial.print(" "); Lokname(decoderAddress); Serial.print(" ");
lcd.print(decoderAddress, DEC);
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
switch (instructionType)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 0:
// 000x-xxxx
Serial.print(" Control ");
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 1:
// Advanced Operations
// 001x-xxxx

if (Befehls_Byte == B00111111)   //128 speed steps
{
//0011-1111 128 Geschwindigkeitsstufen-Befehl

// Richtung auswerten Bit 7 "R" im vorletzten Byte
if (bitRead(Msg->Data[pktByteCount - 2], 7))
{
Serial.print("  -->> ");
lcd.print(" -->> ");
}
else
{
Serial.print("  <<-- ");
lcd.print(" <<-- ");
}

// Geschwindigkeit Bit 6 - 0 vom vorletzten Byte
byte speed = Msg->Data[pktByteCount - 2] & B01111111;
if (speed == 0)
{
Serial.print(" Stopp  ");                  // wenn = 0, dann Stoppbefehl
lcd.print("  S");                  // wenn = 0, dann Stoppbefehl
}
else if (speed == 1)
{
Serial.print(" Nothalt ");                  // wenn = 1, dann Notbremse
lcd.print(" NH");                  // wenn = 1, dann Notbremse
}
else
{
Serial.print(speed - 1);                                   // 1 abziehen; Stufen gehen von 2 - 127 = 126 Stufen
lcd.print(speed - 1);                                   // 1 abziehen; Stufen gehen von 2 - 127 = 126 Stufen
if (speed - 1 < 10) Serial.print("       ");
else if (speed - 1 < 100) Serial.print("      ");
else Serial.print("     ");
}
print_spaces(25);
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
else if (Befehls_Byte == B00111110)   //Speed Restriction
{
//0011-1110 Sonderbetriebsarten-Befehl
if (bitRead(Msg->Data[pktByteCount - 2], 7)) Serial.print(" On ");
else Serial.print(" Off ");
Serial.print(Msg->Data[pktByteCount - 1])&B01111111;
print_spaces(22);
}
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 2:
// Reverse speed step 28 Stufen
// 01xx-xxxx Basis Geschwindigkeits- und Richtungsbefehl
//                    speed = ((Befehls_Byte & B00001111) << 1) - 3 + bitRead(Befehls_Byte, 4);
speed = ((Befehls_Byte & B00001111) << 1) + ((Befehls_Byte & 0x10) >> 4) - 3;
if (speed == 253 || speed == 254)
{
Serial.print("  Stopp  ");                  // wenn = 0, dann Stoppbefehl
lcd.print("  S");                  // wenn = 0, dann Stoppbefehl
}
else if (speed == 255 || speed == 0)
{
Serial.print("  Nothalt");                  // wenn = 1, dann Notbremse
lcd.print(" NH");                  // wenn = 1, dann Notbremse
}
else
{
Serial.print("   <<-- ");
lcd.print(" <<-- ");
Serial.print(speed);
lcd.print(speed);
}
print_spaces(31);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 3: // Forward speed step 28 Stufen
speed = ((Befehls_Byte & B00001111) << 1) + ((Befehls_Byte & 0x10) >> 4 - 3);
if (speed == 253 || speed == 254)
{
Serial.print("  Stopp  ");                  // wenn = 0, dann Stoppbefehl
lcd.print("  S");                  // wenn = 0, dann Stoppbefehl
}
else if (speed == 255 || speed == 0)
{
Serial.print("  Nothalt");                  // wenn = 1, dann Notbremse
lcd.print(" NH");                  // wenn = 1, dann Notbremse
}
else
{
Serial.print("   -->> ");
lcd.print(" -->> ");
Serial.print(speed);
lcd.print(speed);
}
print_spaces(31);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 4: // Loc Function L-4-3-2-1
// 100x-xxxx Funktionssteuerung F0-F4, die F-Nummern sind allerdings seltsam verteilt ;-)

if (Funktion & 16) {
lcd.setCursor(5, 1);
Serial.print("   F0");
lcd.print(" F0");
}
else {
lcd.setCursor(5, 1);
Serial.print("   f0");
lcd.print("  0");
}

for (byte k = 0; k < 4; k++)
{
if (bitRead (Funktion, k)) {
Serial.print("   F");
lcd.print(" F");
}
else {
Serial.print("   f");
lcd.print("  ");
}
Serial.print(k + 1);
lcd.print(k + 1);

}
print_spaces(15);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 5: // Loc Function 8-7-6-5
// 1011-xxxx Funktionssteuerung F5-F8
if (bitRead(Befehls_Byte, 4))
{
lcd.setCursor(5, 1);
for (byte k = 0; k < 4; k++)
{
if (bitRead (Funktion, k)) {
Serial.print("    F");
lcd.print(" F");
}
else {
Serial.print("   f");
lcd.print("  ");
}
Serial.print(k + 5);
lcd.print(k + 5);
}
print_spaces(20);
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
else   // Loc Function 12-11-10-9
{
//1010-xxxx Funktionssteuerung F9-F12
lcd.setCursor(5, 1);
for (byte k = 0; k < 4; k++)
{
if (k == 0) Serial.print(" ");
if (bitRead (Funktion, k)) {
Serial.print("  F");
lcd.print(" F");
}
else {
Serial.print("  f");
lcd.print("  ");
}
Serial.print(k + 9);
lcd.print(k + 9);
}
print_spaces(20);
}
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 6: // 110x-xxxx Eigenschaften-Erweiterungs-Befehle

switch (Befehls_Byte & B00011111)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 0: // Binary State Control Instruction long form
// 1100-0000 Binärzustandssteuerungsbefehl lange Form
Serial.print(" BinStateLong ");
Serial.print(256 * Msg->Data[pktByteCount - 1] + (Msg->Data[pktByteCount - 2] & B01111111));
if bitRead(Msg->Data[pktByteCount - 2], 7) Serial.print(" On ");
else Serial.print(" Off ");
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00011101: // Binary State Control
// 1101-1101 Binärzustandssteuerungsbefehl kurze Form
Serial.print(" BinStateShort ");
Serial.print(Msg->Data[pktByteCount - 1] & B01111111);
if bitRead(Msg->Data[pktByteCount - 1], 7) Serial.print(" On ");
else Serial.print(" Off ");
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00011110: // F13-F20 Function Control
// 1101-1110 Funktionssteuerung F13-F20

lcd.setCursor(8, 1);
for (byte k = 0; k < 8; k++)
{
if (k == 3) lcd.setCursor(0, 2);
if (bitRead (Funktion, k)) {
Serial.print("  F");
lcd.print(" F");
}
else {
Serial.print("  f");
lcd.print("  ");
}
Serial.print(k + 13);
lcd.print(k + 13);
}
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00011111: // F21-F28 Function Control
//1101-1111 Funktionssteuerung F21-F28

lcd.setCursor(8, 1);
for (byte k = 0; k < 8; k++)
{
if (k == 3) lcd.setCursor(0, 2);
if (bitRead (Funktion, k)) {
Serial.print("  F");
lcd.print(" F");
}
else {
Serial.print("  f");
lcd.print("  ");
}
Serial.print(k + 21);
lcd.print(k + 21);
}
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00011000: // F29-F36 Function Control
//1101-1000 Funktionssteuerung F29 - F36
lcd.setCursor(8, 1);
for (byte k = 0; k < 8; k++)
{
if (k == 3) lcd.setCursor(0, 2);
if (bitRead (Funktion, k)) {
Serial.print("  F");
lcd.print(" F");
}
else {
Serial.print("  f");
lcd.print("  ");
}
Serial.print(k + 29);
lcd.print(k + 29);
}
break;
}
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case 7:
Serial.print("  CV ");
if (Befehls_Byte & B00010000)   // CV Short Form
{
byte cvType = Befehls_Byte & B00001111;
switch (cvType)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00000010:
// KKKK = 0010 – Beschleunigungswert in einer Mehrfachtraktion (CV #23)
Serial.print("23 ");
Serial.print(Msg->Data[pktByteCount - 1]);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00000011:
// KKKK = 0011 – Verzögerungswert in einer Mehrfachtraktion (CV #24)
Serial.print("24 ");
Serial.print(Msg->Data[pktByteCount - 1]);
break;
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00001001:
/*
D.2 "Service Mode Decoder Lock Instruction"
    Dieser Befehl wird in der Technical Note TN-1-05 der NMRA näher beschrieben.
    Die "Service Mode Decoder Lock Instruction" (SMDLI) verhindert die Programmierung einiger Decoder, während andere auf dem
    gleichen Gleis programmiert werden können. Es werden dazu Befehle für den Programmiermodus auf dem normalen Fahrgleis verwendet,
    womit man nicht den Vorteil der strombegrenzten Testumgebung hat und Decoder, die diesen Befehl nicht unterstützen, ungewollt umprogrammiert werden können.

Das Befehlsformat lautet: {20 Synchronbits} 0 0000-0000 0 1111-1001 0 0AAA-AAAA 0 PPPP-PPPP 1

Dabei steht das AAA-AAAA für die kurze Adresse des Decoders, der weiterhin Befehle des Programmiermodus ausführen wird.
Ein Decoder, der diesen Befehl unterstützt, vergleicht seine Adresse in CV #1 gegen die Adresse in dem Befehl.
Stimmen die Adressen nicht überein, geht er in einen gesperrten Zustand über, in dem er auch nach Aus- und wieder Einschalten der
Spannung verbleibt. In diesem Zustand ignoriert er alle Befehle des Programmiermodus.
*/
Serial.print(F("Decoder Lock "));
Serial.print(Msg->Data[pktByteCount - 1]);
break;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
else   // CV Long Form für Betriebsmodus  POM !
{
CV_address = ((Msg->Data[pktByteCount - 4] & B00000011) * 256) + Msg->Data[pktByteCount - 3] + 1;
Serial.print(CV_address);

if (CV_address < 1000) Serial.print(" ");
if (CV_address < 100) Serial.print(" ");
if (CV_address < 10) Serial.print(" ");

switch (Befehls_Byte & B00001100)
{
/*  Die für den Befehlstyp (xxxx-KKxx) im ersten Befehlsbyte festgelegten Werte sind:
KK = 00 – reserviert
KK = 01 – Byte Überprüfen
KK = 11 – Byte Schreiben
KK = 10 – Bit Manipulation */

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00000100: // Lesen Byte

Serial.print(F("Lese CV"));  print_spaces(24);
break;

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00001100: // Schreiben Byte

Serial.print(F("Schreibe CV ="));
if (Msg->Data[pktByteCount - 2] < 100) Serial.print(" ");
if (Msg->Data[pktByteCount - 2] < 10) Serial.print(" ");
Serial.print(" ");
Serial.print(Msg->Data[pktByteCount - 2]);
print_spaces(14);
break;

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------
case B00001000:         //B1000 ==> Bit-Gefummel !

// ... 111K-DBBB EEEE-EEEE --> Zugriffe auf einzelne Bits
// K = 1 – Bit Schreiben
// K = 0 – Bit Überprüfen

if (Msg->Data[pktByteCount - 2] & B00010000)
{
Serial.print("Schreibe Bit #");
Serial.print(Msg->Data[pktByteCount - 2] & B00000111);
Serial.print(" = ");
Serial.print((Msg->Data[pktByteCount - 2] & B00001000) >> 3);
print_spaces(20);
}
else
{
Serial.print("Lese    Bit #");
Serial.print(Msg->Data[2] & B00000111);
print_spaces(25);
}
break;
}
}
break;
}
Serial.print("          ");
printPacket(Msg);
}
}
}


//-------------------------------------------------------------------------------------------------------
void notifyCVChange( unsigned int CvAddr, byte Value )
//-------------------------------------------------------------------------------------------------------
// Wird aufgerufen, nachdem ein CV-Wert verändert wurde
{
Serial.print("notifyCVChange: ");
Serial.print("CV"); Serial.print(CvAddr); Serial.print(" = "); Serial.println(Value);
}

//-------------------------------------------------------------------------------------------------------
void Byte_to_Bits (byte b)
//-------------------------------------------------------------------------------------------------------
// Gibt einen Byte-Wert binär mit führenden Nullen und "-" nach der 4. Stelle aus
// z.B. 12 --> 0001 1000
{
for (int i = 7; i >= 0; i--)
{
Serial.print(bitRead(b, i));
if (i == 4) Serial.print("-");
}
}

//-------------------------------------------------------------------------------------------------------
void print_spaces (byte b)
//-------------------------------------------------------------------------------------------------------
// Gibt b mal ein Leerzeichen aus zur Formatierung
{
for (byte i = 0; i < b; i++)
{
Serial.print(" ");
}
}


//-------------------------------------------------------------------------------------------------------
void Lokname (unsigned int DCC_Adresse)
//-------------------------------------------------------------------------------------------------------
// Ausgabe der Loknamen zu den gefundenen Adressen
{
switch (DCC_Adresse)
{
// Adresse + Text manuell eintragen
case    4:   Serial.print(F("P4 KPEV FLM     ")); break;
case    5:   Serial.print(F("EP5 bayr. FLM   ")); break;
case    6:   Serial.print(F("P6 KPEV FLM     ")); break;
case    9:   Serial.print(F("S9 KPEV Brawa   ")); break;
case   10:   Serial.print(F("P10 Trix        ")); break;
// ...
case 8507:   Serial.print(F("BR 85 007 Roco  ")); break;
case 10000:  Serial.print(F("ECoS Dummybefehl")); break;
default:     Serial.print(F("???             ")); // 16 Leerzeichen, falls Lokname nicht gefunden !
}
}

//-------------------------------------------------------------------------------------------------------
void print_Zahl_rechts_ln (unsigned long zahl)
//-------------------------------------------------------------------------------------------------------
// Gibt eine ganze Zahl rechtsbündig aus
{
Serial.print(" ");
if (zahl < 10000000) Serial.print(" ");
if (zahl < 1000000) Serial.print(" ");
if (zahl < 100000) Serial.print(" ");
if (zahl < 10000) Serial.print(" ");
if (zahl < 1000) Serial.print(" ");
if (zahl < 100) Serial.print(" ");
if (zahl < 10) Serial.print(" ");
Serial.println(zahl);
}


//-------------------------------------------------------------------------------------------------------
void printPacket(DCC_MSG *Msg)
//-------------------------------------------------------------------------------------------------------
// Gibt alle gefundenen Bytes eines DCC-Befehls aus, ohne Präambel, aber incl. Prüfbyte
{
Serial.print(" ");
for (byte n = 0; n < pktByteCount; n++)
{
Serial.print("  ");
Byte_to_Bits(Msg->Data[n]);
}
Serial.println(" ");
}

Klaus
"Meine" Modellbahn: http://www.modelbaneeuropa.dk
Dänisches Bahnforum: http://www.baneforum.dk
PIKO C4 "Horror Gallery": http://moppe.dk/PIKOC4.html
Benutzeravatar

fbstr
EuroCity (EC)
Beiträge: 1162
Registriert: So 28. Aug 2016, 21:04
Nenngröße: H0
Stromart: digital
Steuerung: DR5000, Lenz LZV100
Gleise: Peco Code 75, Trix C
Wohnort: Stuttgart
Kontaktdaten:
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#10

Beitrag von fbstr »

Hallo Martin,

ich möchte gerne Deinen DCC-Monitor auf einem UNO laufen lassen und zwar mit Pin 8 statt 2 und A3 statt A5.
In Zeile 86 wird A3 definiert:

Code: Alles auswählen

const byte DccAckPin        = A3;    // Arduino-Pin zur Erzeugung eines ACK-Signals
Und nur in Zeile 172 finde ich was zum anderen Pin:

Code: Alles auswählen

Dcc.pin(0, 8, 1);                                 // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Tut aber nur wenn ich doch Pin 2 nehme. Benötigt die NmraDcc fest den Pin2?
Gruss
Frank
---------------------------------------------------------------------------------------------------------------------
MobaLedLib Wiki
Projekt "Bahnpark Augsburg"
Stummitreff BB: normalerweise jeden 3. Freitag im Monat im Haus Sommerhof in Sindelfingen
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#11

Beitrag von Domapi »

Das DCC-Signal wird über eine Interrupt-Routine ausgewertet.
Das ist beim Nano/Uno nur über PIN 2 oder 3 möglich.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

ringstrecke
RegionalExpress (RE)
Beiträge: 94
Registriert: Do 3. Apr 2008, 10:12
Nenngröße: H0
Stromart: digital
Steuerung: Railware
Gleise: 550 m Roco Flex
Wohnort: NRW

Re: DCC-Monitor auf Arduino-Basis

#12

Beitrag von ringstrecke »

Hallo Martin,

tolles Projekt!!

Habe dazu natürlich ein Fragen.
Ich „spiele“ öfters mit einem STM32F1 Arduino.
Wo gibt es die Adapterplatine mit Schraubanschlüssen für den Arduino?
Ich habe auch bei arltt.de geschaut, habe das ACK-Schaltungsteil nicht gefunden.

Bezüglich des Display arbeite ich mit dem I2C-Bus, denke (hoffe) mal, dass ich das hinbekomme.

Viele Grüße

Martin
HO-Anlage im Aufbau, Lenz-DCC, 8 Booster Fahren, 1 Booster Schalten, PowerManagement für alle, WatchDog, Besetztmelder LDT, Weichendecoder LDT+Lenz, LDT Drehscheibendecoder, RS-Bus, Steuerung mit Railware
Als zweites "Standbein" Aufbau einer LGB Aussenanlage, Z21+WLAN
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#13

Beitrag von Domapi »

Ich selbst nutze eine Lochrasterplatine; wo es Adapterplatinen gibt, weiß ich leider nicht.

Es ist aber keine rocket science, sich die paar Komponenten selbst zusammenzulöten.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

fbstr
EuroCity (EC)
Beiträge: 1162
Registriert: So 28. Aug 2016, 21:04
Nenngröße: H0
Stromart: digital
Steuerung: DR5000, Lenz LZV100
Gleise: Peco Code 75, Trix C
Wohnort: Stuttgart
Kontaktdaten:
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#14

Beitrag von fbstr »

ringstrecke hat geschrieben: Do 23. Apr 2020, 06:54 Wo gibt es die Adapterplatine mit Schraubanschlüssen für den Arduino?
Ich habe auch bei arltt.de geschaut, habe das ACK-Schaltungsteil nicht gefunden.
Hallo Martin,
meinst Du die Testplatine mit meinem Nano drauf?
Die gibt's bei ebay, Amazon oder Ali. Auf die Schnelle habe ich dieses sündhaft teure Teil gefunden: Link
Also ich bin der Meinung die gibt es in China für weniger als 1€. Ich hatte die mir damals wegen den Printschraubanschlüssen bestellt, die ich für Platinen von Bodo gebraucht hatte.

Die DCC-Platine ist von Thomas Arlitt (digi_thomas2003). Er hatte mir 2017 die Dateien gegeben und ich hatte damit meine ersten Platinen in China machen lassen. Frag ihn mal an ob er noch welche hat. Aber wie Martin (Domapi) schreibt, die Schaltung ist kein Hexenwerk.
Gruss
Frank
---------------------------------------------------------------------------------------------------------------------
MobaLedLib Wiki
Projekt "Bahnpark Augsburg"
Stummitreff BB: normalerweise jeden 3. Freitag im Monat im Haus Sommerhof in Sindelfingen
Benutzeravatar

ringstrecke
RegionalExpress (RE)
Beiträge: 94
Registriert: Do 3. Apr 2008, 10:12
Nenngröße: H0
Stromart: digital
Steuerung: Railware
Gleise: 550 m Roco Flex
Wohnort: NRW

Re: DCC-Monitor auf Arduino-Basis

#15

Beitrag von ringstrecke »

Hallo Frank,

danke für die Hinweise.
Hab leider keine passende gefunden, werde aber weiter suchen.
Ich benutze den STM32F103 - dieser hat 2x 20 Anschlüsse.

Wegen der Platine wende ich mich Thomas.

Gruß Martin
P.S. Hab heute ein Netzteil von Ali mit Kabel bekommen.
Nennt man so etwas klassich genullt ?
Bild
HO-Anlage im Aufbau, Lenz-DCC, 8 Booster Fahren, 1 Booster Schalten, PowerManagement für alle, WatchDog, Besetztmelder LDT, Weichendecoder LDT+Lenz, LDT Drehscheibendecoder, RS-Bus, Steuerung mit Railware
Als zweites "Standbein" Aufbau einer LGB Aussenanlage, Z21+WLAN

vikr
InterCityExpress (ICE)
Beiträge: 2154
Registriert: So 23. Okt 2011, 19:05
Nenngröße: H0
Stromart: AC
Steuerung: PC
Gleise: MMärklin C
Alter: 102

Re: DCC-Monitor auf Arduino-Basis

#16

Beitrag von vikr »

Hallo Martin,
ringstrecke hat geschrieben: Do 23. Apr 2020, 12:44
Hab leider keine passende gefunden, werde aber weiter suchen.
Ich benutze den STM32F103 - dieser hat 2x 20 Anschlüsse.
Du wählst hier aber nicht den einfachsten Weg.
Programmieren des STM23F103 mit der Arduino IDE geht, bemötigt etwas Vorbereitung:
Um Frust zu minimieren würde ich vielleicht doch mit einen Atmega 328p-Board anfangen, z.B. dem Arduino Nano ...

MfG

vk
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#17

Beitrag von Domapi »

Kommen wir ˋmal wieder zum eigentlichen Thema zurück.

Hier meine Schaltskizze:

Bild

Und ein Bild der aufgebauten Schaltung:

Bild

Zwei Kabel mit Klemmen zum bequemen Gleisanschluß und eine zusätzliche LED (mit eingebautem Vorwiderstand) parallel zum R9 als Anzeige des ACK-Signals.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

ringstrecke
RegionalExpress (RE)
Beiträge: 94
Registriert: Do 3. Apr 2008, 10:12
Nenngröße: H0
Stromart: digital
Steuerung: Railware
Gleise: 550 m Roco Flex
Wohnort: NRW

Re: DCC-Monitor auf Arduino-Basis

#18

Beitrag von ringstrecke »

Hallo vikr
mit dem STM32 komme ich gut zurecht (ist preisgünstig und für meine Zwecke ausreichend),
habe schon einige für die Kirmesbeleuchtung (WS2812) verbaut.

@Martin, vielen Dank für den Schaltplan, werde mich mal um die Teile kümmern.

Gruß Martin
HO-Anlage im Aufbau, Lenz-DCC, 8 Booster Fahren, 1 Booster Schalten, PowerManagement für alle, WatchDog, Besetztmelder LDT, Weichendecoder LDT+Lenz, LDT Drehscheibendecoder, RS-Bus, Steuerung mit Railware
Als zweites "Standbein" Aufbau einer LGB Aussenanlage, Z21+WLAN
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis

#19

Beitrag von Domapi »

Heute gibt´s ein Update zu meinem DCC-Monitor, das einen voll krassen Fehler und ein paar andere Lappalien bereinigt. :oops:

Offenbar nutzt keiner die Lokdressen 112 bis 127, sonst wäre der Fehler bestimmt schon jemandem aufgefallen. Entweder habt ihr armen Habenichtse <100 Loks im Bestand oder fahrt keine E-Loks, die in diesem Nummernband liegen :mrgreen:

Folgende Probleme sind in der neuen Version gelöst:
  • Bei den Zubehördekodern wurde die Schaltrichtung/Spule umgedreht und die Textausgabe passt jetzt z.B. zur Anzeige im ESU Lokprogrammer Führerstand Weichenstellpult
    - rote Taste = A
    - grüne Taste = B
  • Bei Lokdekoder-Adressen von 112 - 127 wurden falsche DCC-Befehle ausgegeben, da diese vom Sketch fälschlicherweise als Programmierbefehle für das Programmiergleis interpretiert wurden. Nun wird eine zusätzliche Routine der NRMA-Library aufgerufen, die prüft, ob der DCC-Monitor vom Programmiergleis angesprochen wurde. In diesem Fall sendet die Zentrale diverse Befehlsketten, um den Dekoder bzw. Monitor in den Programmiermodus zu versetzen. Die Programmierbefehle fürs Programmiergleis und die Befehle für kurze Lokadressen ähneln sich dummerweise stark …

    Jetzt werden die Lokadressen von 112 - 127 und ihre Steuerbefehle sauber angezeigt. Auf dem Programmiergleis wird der Programmiermodus ein-/ausgeschaltet und im seriellen Monitor ausgegeben.

Wichtig war die Verwendung dieser Routine:

Code: Alles auswählen

//-------------------------------------------------------------------------------------------------------
// Wird aufgerufen, wenn ein Programmierbefehl von der Zentrale gesendet wurde
// Brauchen wir, um nicht mit den Lok-Adressen 112 - 127 zu kollidieren ;-)
void notifyServiceMode(bool Prg_gleis_Mode)
//-------------------------------------------------------------------------------------------------------
{
    Serial.print("Service-Mode/Programmiergleismodus: ");
    if (Service_Mode == 0)
    {
        Serial.println("Ein");
    }
    else
    {
        Serial.println("Aus");

    }
    Service_Mode = Prg_gleis_Mode;
}
Die neueste Sketch-Version findet sich weiter unten im Thread.
Zuletzt geändert von Domapi am So 13. Dez 2020, 10:57, insgesamt 1-mal geändert.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.2

#20

Beitrag von Domapi »

Am Wochenende habe ich mich mal über Layout-Software zur Erstellung von Schaltplänen und Platinen schlau gemacht und habe gleich ´mal mit KICAD einen g´scheiten Plan für den DCC-Monitor erstellt.

Ging nach ein wenig Einarbeitung wider Erwarten recht schnell. Da es mein Erstlingswert ist, fragt lieber vor der Verwendung des Schaltplans eure Eltern …

:mrgreen:

Bild

Insbesondere ist mir der Transistor unten aufgefallen, der wird fast komplett auf GND gezogen, wenn ein ACK-Signal ausgegeben wird.
Obwohl er an der Basis nur für 6ms angesteuert wird, erscheint mir das elegdrisch bedenklich. Bislang funktioniert es.
Evtl. könnte man sicherhalthalber einen 4,7 kOhm Widerstand zwischen Optokoppler Pin 5 und BC557 Basis einbauen.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.2

#21

Beitrag von Domapi »

Ich habe mir spaßeshalber ein paar Platinen für den DCC-Monitor anfertigen lassen. Mein Erstlingswerk und funktioniert sogar :fool:

So sieht die Minimalbestückung aus:

Bild

Brückengleichrichter
Optokoppler 6N137
Widerstand 1,2 kOhm
Kondensator 100nF
Und natürlich ein Nano

Damit kann man die DCC-Signale schon auswerten.

Bestückt man die Platine komplett, dann lassen sich auch Acknowledgement-Befehle an die Zentrale senden. Dazu braucht man ein paar Bauteile mehr. Den R5 habe ich mit 470 Ohm verwendet, den R6 muss man in Abhängigkeit der verwendeten LED bestimmen. Ich habe eine LED mit eingebauten Vorwiderstand eingelötet und daher den Widerstand mit einem Draht gebrückt. Für normale LEDs sollte ein 470 Ohm eingebaut werden.

Bild

Hier der aktualisierte Schaltplan mit den neuen Widerständen R5 und R6:

Bild

Ich habe noch ein paar Platinen übrig, die ich günstig abgeben kann; bei Bedarf einfach per PN melden.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Benutzeravatar

MicroBahner
Metropolitan (MET)
Beiträge: 2636
Registriert: Mi 28. Nov 2012, 14:24
Nenngröße: H0
Stromart: analog DC
Steuerung: Microprozessor-Eigenbau
Gleise: Tillig
Wohnort: Mittelfranken
Alter: 70

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.2

#22

Beitrag von MicroBahner »

Hallo Martin,
ein sehr interessantes Projekt, dass sicher jeder DCC-ler gut gebrauchen kann.

Eine Anmerkung zu deiner Schaltung: Den R5 braucht es nicht, das war schon ok ohne Widerstand. Der Transistor soll ja als Schalter arbeiten und gut durchschalten ( obwohl man ihn in dieser Schaltung eh nicht in die Sättigung bekommt). Den Strom bestimmt R2.
Im Gegensatz dazu ist der 'optionale' Widerstand R6 essentiell, sonst betreibst Du die LED praktisch ohne Vorwiderstand. Sie wird zwar immer nur für 6ms eingeschaltet, aber auf Dauer dürfte ihr ( und auch dem Transistor ) das ohne Vorwiderstand nicht gut bekommen. Du schließt da praktisch über Transistor und LED die DCC-Spannung kurz.
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.3

#23

Beitrag von Domapi »

Heute gibt es wieder ein kleines Update meines DCC-Monitors.

Hintergrund der Änderungen waren Tests mit dem ESU Lokprogrammer als "Zentrale". Der Lokprogrammer sendet nämlich ein paar seltsame Befehle aufs Gleis, die die Ausgabe durcheinander gebracht haben.

Es sind sogenannte Analogfunktionsgruppenbefehle. Diese sind von der DCC-Norm durchaus vorgesehen. Beim Lokprogrammer scheinen sie jedoch verwendet zu werden, um den Dekodern mitzuteilen, dass sie gerade vom ESU Lokprogrammer angesprochen werden. Folgende Befehle werden gesendet:

Code: Alles auswählen

Lok     5   EP5 bayr. FLM      Analogfkt.gruppe Steuerkanal 151 = 128   0000-0101  0011-1101  1001-0111  1000-0000 
Lok     5   EP5 bayr. FLM      Analogfkt.gruppe Steuerkanal 152 =   0   0000-0101  0011-1101  1001-1000  0000-0000 
Lok     5   EP5 bayr. FLM      Analogfkt.gruppe Steuerkanal 153 =   0   0000-0101  0011-1101  1001-1001  0000-0000 
Lok     5   EP5 bayr. FLM      Analogfkt.gruppe Steuerkanal 154 =   0   0000-0101  0011-1101  1001-1010  0000-0000 
Die "151" erinnert schon stark an die ESU-Hersteller-ID, die normalerweise in der CV8 steht …

Irgendwann muss ich den Monitor mal an das Zimo MXULFA hängen; mal sehen, was da so alles gesendet wird.

Die Platinen sind mittlerweile alle weg; ich habe aber Nachschub in China bestellt, dieses Mal in schickem Rot :redzwinker:
Zuletzt geändert von Domapi am Do 17. Dez 2020, 16:55, insgesamt 1-mal geändert.
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275

sambaer1
Beiträge: 8
Registriert: Mo 14. Feb 2011, 20:44
Nenngröße: H0
Stromart: digital
Steuerung: rocrail
Gleise: rocoline
Wohnort: München
Alter: 60

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.3

#24

Beitrag von sambaer1 »

Hallo Martin,

erst mal herzlichen Dank für die Entwicklung des DCC Monitor. Der ist sicher für Viele sehr hilfreich.

Ich hab ihn nachgebaut und er funktioniert.

Ich hätte nur einen kleinen Wunsch bei der Ausgabe der Accessory Befehle:

Wenn ich eine Weiche das erste mal zum Beispiel auf Abzweig schalte, wird sie angezeigt. Wenn ich die gleiche Weiche wieder auf Gerade schalte wird sie nicht mehr angezeigt, obwohl der Zustand sich ja geändert hat.

Wenn ich mit "5 Nur neue Zubehör-Pakete anzeigen ein/aus = aus" schalte werden beide Richtungen angezeigt, aber auch alle Wiederholungen, was bei vielen Befehlen sehr unübersichtlich ist..

Es wäre schön, wenn (mit der Einstellung: "5 Nur neue Zubehör-Pakete anzeigen ein/aus = ein") beim Schalten einer Weiche genauso wie beim Schalten einer Lok Funktion jede Zustandsänderung angezeigt würde.

Zu meinem Testfeld: ich habe mit einer DCC++ Zentrale getestet.

Viele Grüße

Bernd
Benutzeravatar

Threadersteller
Domapi
EuroCity (EC)
Beiträge: 1059
Registriert: Di 22. Sep 2015, 07:12
Nenngröße: H0
Stromart: digital
Steuerung: DCC & ECOS & TC9 Gold
Gleise: Roco/Tillig/Weinert
Wohnort: Nämberch
Deutschland

Re: DCC-Monitor auf Arduino-Basis: --> N E U Version 1.3

#25

Beitrag von Domapi »

Hallo Bernd,

bei mir unter reinem DCC funktioniert das wunderbar. Standardmäßig ist im Sketch die Speicherung der Accessory-Befehle eingeschaltet, damit nur neue Befehle gezeigt werden. Bei mir sieht die Ausgabe beim Schalten der Weichen wie folgt aus:

Code: Alles auswählen

NMRA DCC Monitor V 1.3
Sketch-Upload am: Dec 11 2020, 06:47:58
? = Zeige Tastaturbefehle für den seriellen Arduino-Monitor
Prg   Dekoder-Reset-Befehl                                              0000-0000  1111-1111 
DCC-Adresse   21 (  6 : 1) A On                                         1000-0110  1111-1000 
DCC-Adresse   21 (  6 : 1) A Off                                        1000-0110  1111-0000 
DCC-Adresse   21 (  6 : 1) B On                                         1000-0110  1111-1001 
DCC-Adresse   21 (  6 : 1) B Off                                        1000-0110  1111-0001 
DCC-Adresse   22 (  6 : 2) A On                                         1000-0110  1111-1010 
DCC-Adresse   22 (  6 : 2) A Off                                        1000-0110  1111-0010 
DCC-Adresse   22 (  6 : 2) B On                                         1000-0110  1111-1011 
DCC-Adresse   22 (  6 : 2) B Off                                        1000-0110  1111-0011 
DCC-Adresse   23 (  6 : 3) A On                                         1000-0110  1111-1100 
DCC-Adresse   23 (  6 : 3) A Off                                        1000-0110  1111-0100 
DCC-Adresse   23 (  6 : 3) B On                                         1000-0110  1111-1101 
DCC-Adresse   23 (  6 : 3) B Off                                        1000-0110  1111-0101 
DCC-Adresse   24 (  6 : 4) A On                                         1000-0110  1111-1110 
DCC-Adresse   24 (  6 : 4) A Off                                        1000-0110  1111-0110 
DCC-Adresse   24 (  6 : 4) B On                                         1000-0110  1111-1111 
DCC-Adresse   24 (  6 : 4) B Off                                        1000-0110  1111-0111 
Zuerst kommt der "On"-Befehl für eine Adresse, der wird solange gesendet, wie man die Taste in der Zentrale drückt. Dann kommt der "Off"-Befehl.
Jeweils nur eine Ausgabe im seriellen Monitor, da ja "nur neue" eingestellt ist.

Evtl. liegt es an der Art und Menge der DCC++ Signale. Ich selbst kenne DCC++ nicht, aber ich vermute, dass die DCC++-Befehle stark von der DCC-Nomenklatur abweichen und daher mit meinem Monitor nicht ausgewertet werden können.

Eine Idee noch: Ganz am Anfang meines Sketches wird die Anzahl der gespeicherten Befehle festgelegt:

Code: Alles auswählen

const byte bufferSizeAcc    = 5;     // Schaltartikelbefehle werden nicht andauernd wiederholt; hier reichen ein paar Pufferplätze aus
Evtl. hilft bei DCC++ ein größerer Wert, z.B. 20 oder höher.

Alternativ bitte hier mal einen Teil der Ausgaben einstellen (mit Speicherung "aus"), dann kann man vll. erkennen, was DCC++ hier so alles treibt.

Ansonsten darfst Du den Sketch gerne erweitern! :fool:
Viele Grüße
Martin

Der Weg ist das Ziel !

Mein noch namenloser Trennungsbahnhof: https://www.stummiforum.de/viewtopic.php?f=64&t=152275
Antworten

Zurück zu „Digital“