Hallo Leute,
es gibt für fast alles zig Codeexemplare, außer für DCC.
Da ich viel "ernten" konnte aus dem Forum, möchte ich nun mal was
zurückgeben. Oft habe ich gelesen, dass nach sowas die Suche ist, viel
habe ich nur in Assembler gefunden.
Ich habe (für mich) für das DCC-Protokoll eine kleine Codesammlung
geschrieben. Die 2 Dateien können das DCC-Signal encodieren und auch
codieren, also man kann bspw. eine Zentrale oder einen intelligenten
Bremsgenerator bauen (das habe ich auch gemacht). Dort wird in Echtzeit
das DCC-Signal vom Hauptgleis auf das Bremsgleis weitergeleitet, und die
Fahrinformation gegen STOP ausgetauscht (optional wäre auch
Langsamfahrt, etc...)
Mir ging es beim Programmieren darum, einen möglichst komplexen
"alleskönner" zu programmieren. Die Implementierung ist super einfach,
gibt viele Macro's und Funktionen die einem die gesamte Arbeit abnehmen.
Zwar alles sehr konfortabel aber dafür auch nicht gerade klein (4kb ist
der Encoder mit allen Möglcihkeiten), aber die µC kosten ja nix :).
Man braucht aber auch nicht unbedingt alles, kann man kürzen dann wird
es viel kleiner. Ich extrahiere direkt alle Daten und man kann
Fahrinformation, Richtung, etc.. abrufen.
Der Decoder & Soft-PWM läuft ohne Interrupt nur in der loop.
Wenn man andere Taktraten nehmen will, dann muss man in der dcc_init den
Wert nach der Timerinitialisierung anpassen.
Formel lautet: 77 / ((FCPU/TIMER_PRESCALER)^-1 * (10^6))
Den Wert dann einfach da eintragen und dann klappt es
(decoder.dcc.dcc_time_logic_one dort eintragen in der dcc_init_and_sei)
Damit kann man sich jeden denkbaren Decoder/Zentrale/Modul selber bauen
für wenig Geld. Ich hoffe es hilft jmd!
Das DCC-Signal einfach 1 Leitung vom Gleis vor dem Gleichrichter über
10K und 5,1V Z-Diode an einen beliebigen Pin. Das reicht.
Kurze Zusammenfassung:
- DCC encodieren/decodieren
- CV Programmierung POM, Register, CV read/write
- Breites Spektrum an Sonderfunktioen (Neon, Gaslampe, TV, Flops, etc..)
- NMRA-Test bestanden (ich habe mal ein Gerät von mir eingeschickt und
es prüfen lassen).
Man kann Softwareversion einfach angeben (ist dann in CV7 gespeichert).
Meine ID (Manufacture ID) darf NICHT genutzt werden. Hier die freie ID
eintragen (glaube ist 13, kann man nachlesen auf NMRA.org).
Meine ID ist nur für mich von NMRA zugeteilt!
EEPROM gibt es ein struct, dort einfach einfügen welche CV's man haben
will und fertig. Sieht man aber alles in der .h.
Bei Fragen oder Problemen einfach melden.
Hier noch andere Codesammlungen von mir:
https://www.dropbox.com/sh/l121q3iv151kgrq/AABhNLPHT_ch2xuF_rqRPOL0a?dl=0
Das ist eine sehr interessante Bibliothek. Ich habe den Code durchsucht,
aber es ist nicht klar, wie die Funktionen verwendet werden. Gibt es
auch Dokumentation?
Frysk schrieb:> Das ist eine sehr interessante Bibliothek. Ich habe den Code durchsucht,> aber es ist nicht klar, wie die Funktionen verwendet werden. Gibt es> auch Dokumentation?
KURZER EDIT: Ich habe noch vergessen zu sagen, dass für den ACK ein idR.
100 Ohm Widerstand zwischen + und - geschaltet werden sollte (über einen
BSS123 bspw.). So ca. 200mAmps sollten fließen, sonst erkennen manche
Zentralen den ACK nicht. Ich habe den als seperates Bauteil
hinzugefügt, da einem so das lästige Anschließen einer Last erspart
bleibt.
So jetzt zur Frage:
Wahrscheinlich wäre das wohl bei der Komplexität angebracht, für mich
aber glasklar, daher gibt es keine.
Ich helfe dir aber gerne, und dann kann man das als Doku ansehen
(hoffentlich) (kleine "Anleitung" zur Bedienung befindet sich oben in
der dcc.h):
1. Am besten in einem Editor á la AtmelStudio öffnen, dass man etwas
Highlighting bekommt, sonst blickt keiner durch.
2. Die Soft-PWM ist ganz einfach gestrickt, Timer-Counter Register
angeben und fertig, dann kann an jedem Pin PWM erzeugt werden, und das
invers oder normal. Das sollte klar sein. Darf natürlich dann keine
Delays im Programm geben (bei guter Programmierung eigentlich auch nicht
vorhanden). Der Timer von der PWM kann als System-Timer genutzt werden
(bspw. Systemtakt, wird auch in der ddc.c initialisiert für den
Analogwechsel etc... (Takt 1ms/ovf ==> Pwm läuft dementsprechend mit
1khz)
3. dcc_init_and_sei aufrufen BEVOR die mainloop kommt. Dort wird der ack
und dcc pin/port angegeben und der timer initialisert
4. dcc_detect_dcc convertiert und wandelt das dcc signal an angegebenen
pin (muss in die loop).
5. Dann haben wir rund 4kb belegt (encoder + alle
Programmiermöglichkeiten + Resetfunktionen etc... (siehe dazu unbedingt
auch die dcc_servce Funktionen) und ab dann kann die eigene Logik kommen
Hier ist es jetzt wichtig was du haben willst (accesory,
Lok-/Zubehördecoder oder was auch immer).
Das definierst du im groben in der h, damit stellst du dein Layout im
groben ein.
Dann kannst du in der EEPROM-Struct alle deine benötigten Einstellungen
hinzufügen (achte hierzu mal auf die darüberliegenden structs wie bspw.
cv_recommenend, cv_f_functs etc...).
In der EEProm Struct sind auch nochmals Beispiele aufgeführt (dort ist
ein Weichendecoder mit 2 Weichenausgängen und 2 F-Ausgängen
initialisiert, da sind dann die benötigten CV-Werte + Startwerte alle
angegeben). Da kannst du dann hinzufügen was du willst (einfach neue
Instanzen der bspw- Funktionsausgänge Strukturen erstellen (bspw. ist
ein drüber mit F1-F7). Das was dahinter steht in {} musst du dann nach
dem cv_xxxxx EEMEM = .... einfügen, da das ja ins EEPROM als Startwert
soll. Resetbereiche passt du in der dcc.c in den ServiceMode Funktionen
an.
Klingt schwer, klingt kompliziert, ist es aber nicht. Einfach mal in
Ruhe durchlesen, vorallem auch was in der .h steht.
Und dann kommt die Logik.
bspw. (in der loop, also bspw. direkt nach der dcc_detect_dcc)
1
//Das wäre die normale digitale funktion (if (decoder.dcc.state.systemBits.operation_dcc) ==> digitalbetrieb, sonst analogbetrieb (kann sich natürlich ändern bei fahrzeugen (blockstellen, was weiß ich)
2
3
if(dcc_is_detection_complete())//got one correct data packet
4
{
5
if(dcc_ReceivedMyNonAccesoirAddr())//lokadresse angekommen? UND ZWAR MEINE??? (Automatische Erkennung zwischen CV1 oder CV 17/18 (lange Adresse). Also hier testet er immer, ob eine Lokadresse gesendet wurde, die zu meiner in der CV1 bzw. CV17/18 passt (das hängt ja von CV29 bit5 ab (lange ode kurze Adresse, in meiner Dropbox liegen unter dem Ordner NMRA DCC die Dokumente mit der Beschreibung)
6
{
7
//Hier wird gefragt, ob es eine änderung zum schalten für F1 gibt und ob F1 überhaupt gesendet wurde, der rest stammt aus meiner internen Logic die ich hinzugebastelt habe (man kann bei mir in cv49 umschalten, ob die F-Ausgänge mit F-Taste und Lokadresse oder per Weichenadresse schaltbar sind).
dcc_setFOutput(&decoder.system.f1,&decoder.f1,f1_spec_timer,FALSE,DCC_GET_ACT_F_STATE(decoder.system.f1.function),FALSE,&F1_PORT,F1_PIN);//schalte den Ausgangspin entsprechend dem gesendetem Befehl, timer sind ggf. für programmierbare sonderfunktionen (siehe ebenfalls .h der strukturen)
10
}
11
12
13
14
if(dcc_isMY_accessoirAddr_received(TRUE,DCC_16BIT_ADDRESS(decoder.system.switch1.switch_addr_hi,decoder.system.switch1.switch_addr_lo),TRUE))//accesor (weichenadresse gesendet?) und enspricht meiner? (berechnung passiert im hintergrund über macros etc... einfach mal die Funktionen rückwärtsverfolgen)
15
{
16
//weiche schalten (h-brücke für EPL-Antriebe mit Spulenantrieb). Hier müssen div. Timer übergeben werden. Das Timerhandling passiert in der ISR in der dcc.c jede ms einen OVF INT generiert (Systemzeit). Kann kann hier jetzt
17
//bspw. in CV118 angeben ob invers oder normal geschaltet werden soll, DCC_IS_ACESSOR_SignalGO_SwitchSTRAIGHT das gibt einen den Schaltstatus an, automatisches zurückschalten etc.. ist halt auch möglich (via timer)
Das war jetzt mehr für Weichen, für Lok/Funktionsausgänge gibt es noch
andere Funktionen (siehe dcc.c) die auch die ganzen Sonderfunktionen
(Neon, Gaslampen, TV, Feuer, etc...) beinhalten.
Eigentlich beschränkt sich das Programm auf vll. 5 Funktionen, der Rest
ist alles ineinander verschachtelt, um die Bedienung so einfach wie
möglich zu machen und wird intern genutzt.
Da das DCC Protokoll mit den Jahren gewachsen ist, ist es halt sehr
"komplex", man muss zig Fälle unterscheiden jenachdem was wie aktiv ist
etc...
Um da keinen Kollaps zu bekommen habe ich diese vielen Funktionen
gemacht die Schrittweise die Sachen im Hintergrund erledigen, man selber
fragt ganz "dumm" nur ab (ist Lokadresse angekommen? Dann weiß man
gleich das eine angekommen ist und es meiner entspricht und dabei ist es
egal ob die lange oder die kurze, das wird alles im Hintergrund
gemanaged).
Frysk schrieb:> Hallo Marius,>> Danke für die Erklärung. Ich werde sehen, ob ich den Code verstehen> könnte. Ihr Beispiel wird sicherlich dazu beitragen.
Wenn noch fragen da sind, einfach mal melden.
Im code ist auch ein Beispiel (vor der ISR).
Du solltest sie aber aus meiner Dropbox runterladen, manchmal gibt's ne
Aktualisierung. Ich habe jetzt bspw. noch eingebaut, dass man Ausgänge
(gerade bei Weichen) auch invers schalten kann (siehe DCC_HANDLE_INVERS)
aus der Dropbox.
Ansonsten gutes gelingen!
Es ist die Tage ein neues Update der Lib raus gekommen.
Darin wurde u.a. Funktionen für normale Decoder hinzugefügt
(Wechselblinker) und eine Funktion kombinierte Ausgänge logisch zu
verknüpfen.
Außerdem wurde ein kleiner Bug beim Fotographblitz beseitigt und ein Bug
in der Bereitstellung der Richtung bei 128 Fahrstufen.
Hinzugefügt wurde noch eine Funktion, welche das Handling für
Conditionen übernimmt. Conditionen sind (siehe .h) nur bei
Vorwärtsfahrt, nur im Stand, bei Fahrt, etc.....
Dieses Handling fügt man so ein:
1
if(dcc_is_detection_complete())//got one correct data packet
2
{
3
if(dcc_ReceivedMyNonAccesoirAddr())//lokadresse angekommen? UND ZWAR MEINE??? (Automatische Erkennung zwischen CV1 oder CV 17/18 (lange Adresse). Also hier testet er immer, ob eine Lokadresse gesendet wurde, die zu meiner in der CV1 bzw. CV17/18 passt (das hängt ja von CV29 bit5 ab (lange ode kurze Adresse, in meiner Dropbox liegen unter dem Ordner NMRA DCC die Dokumente mit der Beschreibung)
4
{
5
//Hier wird gefragt, ob es eine änderung zum schalten für F1 gibt und ob F1 überhaupt gesendet wurde, der rest stammt aus meiner internen Logic die ich hinzugebastelt habe (man kann bei mir in cv49 umschalten, ob die F-Ausgänge mit F-Taste und Lokadresse oder per Weichenadresse schaltbar sind).
dcc_setFOutput(&decoder.system.f1,&decoder.f1,f1_spec_timer,FALSE,DCC_GET_ACT_F_STATE(decoder.system.f1.function),FALSE,&F1_PORT,F1_PIN);//schalte den Ausgangspin entsprechend dem gesendetem Befehl, timer sind ggf. für programmierbare sonderfunktionen (siehe ebenfalls .h der strukturen)
8
}
9
10
11
12
if(dcc_isMY_accessoirAddr_received(TRUE,DCC_16BIT_ADDRESS(decoder.system.switch1.switch_addr_hi,decoder.system.switch1.switch_addr_lo),TRUE))//accesor (weichenadresse gesendet?) und enspricht meiner? (berechnung passiert im hintergrund über macros etc... einfach mal die Funktionen rückwärtsverfolgen)
13
{
14
//weiche schalten (h-brücke für EPL-Antriebe mit Spulenantrieb). Hier müssen div. Timer übergeben werden. Das Timerhandling passiert in der ISR in der dcc.c jede ms einen OVF INT generiert (Systemzeit). Kann kann hier jetzt
15
//bspw. in CV118 angeben ob invers oder normal geschaltet werden soll, DCC_IS_ACESSOR_SignalGO_SwitchSTRAIGHT das gibt einen den Schaltstatus an, automatisches zurückschalten etc.. ist halt auch möglich (via timer)
Hallo Marius,
das klingt alles recht vielversprechend. Ich werde mich wohl mal wieder
mit dem Thema befassen, wenn andere Projekte fertig sind.
Vielen Dank.