OpenDCC - Zentrale für DCC - Details zur Software

    OpenDCC kann mit unterschiedlicher Software geladen werden. Diese nachfolgend beschriebene Software kann per Jumper auf folgende Betriebsarten programmiert werden:
      Jumper / Betriebsarten
      JP2 JP1 Mode
       offen   offen  Betrieb als Zentrale, Befehlssatz für eine Emulation der Intellibox ® von Uhlenbrock. Der Befehlssatz kann auch auf Lenz-Emulation umgestellt werden (per #define in config.h, danach neu übersetzen).
       offen   zu  Betrieb als DMX Steuerzentrale, Bedienung durch Tasten (Remote Control noch nicht enabled)
      (Hinweis: Das wird entfallen, bitte die DMX-Ansteuerung mit dem Decoder realisieren)
       zu   offen  Betrieb als HSI88 Interface, Befehlssatz kompatibel zu Littfinski
      zu zu Testbetrieb: Die LEDs blinken, alle Daten auf der Schnittstelle werden mit 19200 Baud einfach wieder zurückgesendet.

    Wenn kein Jumper gesteckt ist, dann wird mit dieser Software aus OpenDCC eine Zentrale. Es werden Befehle vom PC nach DCC umgesetzt, wobei OpenDCC wahlweise eine Lenz-Zentrale oder eine Intellibox ® (default) emuliert. verhält. Es sind jedoch nicht alle Befehle nach Lenz V3.0 oder IB implementiert. Es fehlt z.B. der Support für 27 Fahrstufen und die Unterstützung für Mehrfachtraktionen.

    Die Software wurde in C mit WinAVR (basiert auf dem avrgcc) geschrieben und mit AVR-Studio (gibts auf www.atmel.com) simuliert.
    Das Ganze ist als Open Source unter der GNU License freigegeben.
    Bei der Entwicklung wurde besonders auf maximalen Durchsatz an DCC-Befehlen geachtet; hierzu ist auch ein intelligenter Refreshalgorithmus implementiert, der neue Fahrbefehle priorisiert und dann zyklisch wiederholt, wobei die Wiederholrate bei schon lange nicht mehr benutzten Loks zurückgenommen wird. Bei der Priorisierung wird zusätzlich noch zwischen Funktionen, Beschleunigung und Abbremsen unterschieden: Bremsbefehle haben höchste Priorität.
    Neueste technische Entwicklungen (wie z.B. Unterstützung für BiDi (oder gemäß dem Handelsname von Lenz: railcom™)) oder auch die Übertragungung einer beschleunigten Layoutzeit mittels DCC (FAST CLOCK)) werden durch permanente Weiterentwicklung unterstützt.

    Die Software besteht aus aus mehreren Modulen:
      Modulübersicht
    • HARDWARE.H: Einstellen des Prozessors und Portdefinitionen
    • CONFIG.H: Einstellen der Betriebsarten, Speichergrößen, usw.
    • DCCOUT.C: Erzeugung des DCC-Protokolls (DCC Encoder)
    • DMXOUT.C: Erzeugung des DMX-Protokolls (DMX Encoder)
    • ORGANIZER.C: DCC-Kommandoverwaltung (Repeat, Refresh)
    • LENZ_PARSER.C, IBOX_PARSER.C: Übersetzen der PC-Befehle in die entsprechenden internen Aufrufe
    • LENZ_PROGRAMMER.C, IBOX_PROGRAMMER.C: Abarbeiten von Programmierbefehlen
    • RS232.C: Schnittstelle zum PC (mit Interrupt + Fifos)
    • STATUS.C: Zustandsverwaltung, Timertick, Keys und LEDs
    • S88.C: Auswerten der Rückmelder
    • XPNET.C: Busmaster für Xpressnet
    • MAIN.C: Init, Loop

DCC-Erzeugung

    Das Modul DCCOUT kümmert sich um die Erzeugung des Gleissignals.

  • Wie sieht DCC überhaupt aus?
    Bei DCC wird das Gleissignal immer mit konstanter Spannung, aber wechselnder Polarität übertragen. Durch die Zeitpunkte der Polaritätswechsel wird die Information kodiert, welche an die Lok / Weiche übertragen wird.

    Die Codierungsregel ist relativ einfach: zwei Polaritätswechsel nach je 58µs bedeuten 1, zwei Wechsel nach je 116µs bedeuten 0. Da es immer 2 Polaritätswechsel sind, ist das Ausgangssignal (normalerweise) gleichspannungsfrei und die Polarität am Empfänger ist egal. Eine 1 dauert also zweimal 58µs=116µs, eine 0 ist doppelt so lang.

    Bild mit Bits

    Auf diese Art und Weise wird ein serieller Bitstrom an die Lok gesendet. Um nun dem Empfänger eine Wertung dieser Bits zu ermöglichen, muß der Datenstrom gegliedert werden. Bei DCC geschieht das durch Aufteilung in Preamble, Nutzbytes und Prüfsumme. Die Preamble kennzeichnet jeweils den Beginn einer neuen Nachricht. Preamble, Nutzbytes und Prüfsumme (je 8 Bits) sind jeweils durch eine 0 voneinander getrennt.

    Damit die Preamble leicht vom Empfänger leicht erkannt werden kann, muß sie nach einer Regel aufgebaut sein, die im normalen Datenstrom nicht vorkommt. Bei DCC ist die Preamble eine Folge von mind. zwölf 1 Bits. Da ja die Nutzbytes nach 8 Bits durch eine 0 getrennt sind, kommt diese lange 1-Sequenz im normalen Datenstrom nicht vor.

    Nach der Preamble kommen zwei bis fünf Nutzbytes (jeweils durch 0 getrennt), welche i.d.R. die Adresse und die Fahrstufe enthalten. Das ursprüngliche DCC-Format sah nur 2 Nutzbytes vor, diese wurde später bis zu 5 Nutzbytes erweitert. An diese Nutzbytes wird die 8-Bit XOR-Summe dieser Nutzbytes als Prüfsumme (checksum) angehängt. Wenn der Empfänger nun die XOR-Summe über die alle empfangenen Bytes bildet, dann muß sich 00000000 ergeben, nur dann ist die Nachricht gültig.


  • Welche Bedeutung haben die einzelnen Bits?
    Mit dem ersten Byte wird eine generelle Aufteilung in Lokbefehle, Zubehördecoder (Accessory Decoder) und Programmierbefehle (Service Mode) vorgenommen. Alle folgenden Bytes sind dann je nach Befehlsgruppe unterschiedlich codiert.
    Erstes Byte
    0: 00000000: Die Adresse 0 ist als Broadcast für alle Lokomotiven reserviert.
    1-127: 0AAAAAAA: Beginnt das erste Byte mit einer 0, so handelt es sich um einen Lokfahrbefehl mit kurzer Adresse.
    128-191: 10AAAAAA: Der Bereich (128-191)(einschließlich) ist für Zubehördecoder.
    192-231: 11000000-11100111: Es handelt sich um einen Lokbefehl mit langer Adresse, die weiteren Adressbits folgen dann im nächsten Byte.
    232-254: 11101000-11111110: Dieser Bereich ist reserviert für Erweiterungen.
    255: 11111111: Damit wird keiner adressiert (IDLE).
    Im Prinzip beginnt eine DCC-Message immer mit einem (oder zwei Adressbytes), gefolgt von einem (oder mehreren) Befehlsbytes, in denen die jeweilige Aktion bzw. Lokgeschwindigkeit kodiert ist.
    Das DCC-Protokoll ist im Laufe der Jahre immer wieder erweitert worden; Dabei haben sich leider verschiedene Darstellungen für die Geschwindigkeit (14,27, 28 und 126 Fahrstufen) etabliert.
    Die Bedeutung der weiteren Bytes kann man bei der NMRA nachlesen.


  • Beispiel 1: Fahrbefehl an Lok 5, Fahrstufe 4 (von 14 Stufen), vorwärts
    Es wird ein Befehl mit 3 Byte geschickt:
    Preamble Startbit  Adressbyte (=0AAAAAAA)
             Startbit  Datenbyte  (=01DCSSSS)
             Startbit  Prüfsumme
             Stopbit
    
    Dabei bedeutet im Adressbyte AAAAAAA [A6 .. A0] die Lokadresse und und im Datenbyte D [Direction=Richtung], C [Lichtfunktion], SSSS [Speed]. Das DCC-Telegramm wird wie folgt zusammengebaut:
        Adressbyte = (Lokadresse & 0x7F);
        Datenbyte = 0b01000000 | (speed & 0x0F) | (Richtungsbit << 5);
        Prüfsumme  = Adressbyte ^ Datenbyte;
    
    Das Richtungsbit ist 1 für vorwärts, Null für rückwärts.
    Preamble 0 Adressbyte 0 Datenbyte 0 Prüfsumme
    11111111111111 0 00000101 0 01100100 0 01100001


  • Beispiel 2: Weichenansteuerung per DCC
    Es wird ein Befehl mit 3 Byte geschickt:
    Preamble Startbit  Adressbyte 10AAAAAA
             Startbit  Datenbyte  1AAA1BBR
             Startbit  Prüfsumme
             Stopbit
    
    Dabei bedeutet im Adressbyte AAAAAA [A5 .. A0] und im Datenbyte AAA [A8 .. A6], wobei die Adressen A8 bis A6 invertiert übertragen werden. BB ist die lokale Adresse am Decoder (0,1,2,3), R ist das Outputbit, d.h. welche Spule aktiviert werden soll. In der Zentrale wird nun z.B. aus der von PC übermittelten Adressen wie folgt das DCC-Telegramm zusammengebaut:
       Adressbyte = 0x80 + (adresse & 0x3F);
       Datenbyte  = 0x80 + (adresse / 0x40) ^ 0x07) * 0x10;
       Prüfsumme  = Adressbyte ^ Datenbyte;
    
    Die Adresse 0 ist als Broadcast reserviert, so dass die erste Weichengruppe bei Adresse 1 liegt. Leider gibt es bei den PC-Protokollen der einzelen Zentralen kleine, aber störende Unterschiede im Adressbereich und in der Interpretation des Outputbits sowie des Activatebits (im obigen Beispiel die 1).

    Uhlenbrock (Intellibox) beschreibt wie folgt (und überträgt auch so):
    'r' (red = thrown) and ('r' may also be spec'd as '0')
    'g' (green = closed) and ('r' may also be spec'd as '1')
    Der Adressbereich in der PC Schnittstelle beginnt dagegen entgegen der Dokumentation bei 1. Das heißt, der erste Decoder liegt auf Adressen 1 ... 4; Die Intellibox sendet auch nie den Abschaltbefehl auf das Gleis, auch wenn dieser vom PC aus angefordert wird.

    Lenz beschreibt das Richtungsbit als D2 mit folgendem Text:
    D2: D2 = 0 bedeutet Ausgang 1 der Weiche gewählt.
         D2 = 1 bedeutet Ausgang 2 der Weiche gewählt.

    Allerdings läßt es sich nirgends rausfinden, was Ausgang 1 oder 2 bedeutet. An Hand eines Logfiles scheint rot und grün vertauscht zu sein. OpenDCC bildet diese Invertierung (abschaltbar) durch eine CV nach.
    Dafür beginnen die Weichenadressen bei Lenz bei der Adresse 0 und den Abschaltbefehl gibt es.


  • Allgemeine Regeln für die Pakete
    • Präambel: Ein Empfänger muß eine Präambel aus mind. 12 Einsern erkennen, eine Preamble mit weniger als 10 Einsern muß er verwerfen; eine Zentrale muß mind. 14 Einser senden. Das Stopbit darf gleichzeitig zur Präambel des nächsten Befehls gehören. Wenn die Zentrale im Programmiermode betrieben wird, dann muß die Präambel 20 Bits lang sein.
    • Länge: Solche Pakete können von 3 bis 6 Bytes lang sein, jedoch ist bei allen Paketen das letzte Byte eine XOR-Prüfsumme über die vorherigen Bytes.
    • Zeitlicher Abstand: Pakete an den *gleichen* Decoder müssen 5ms Abstand haben. Nach spätestens 30ms muß wieder irgendein DCC Packet gesendet werden, damit die Decoder nicht die Lust verlieren und auf analog umschalten. Mit der Einführung von Railcom besteht für Dekoder die Anforderung, Pakete 'nahtlos' erkennen zu können, d.h. es können zwei Pakete direkt hintereinander an den gleichen Dekoder geschickt werden.


  • Wie werden nun diese Bits in OpenDCC erzeugt?
    Es wird der Timer 1 benutzt, dieser wird im CTC-Mode (Clear Timer on Compare-Match) betrieben, d.h. nach Erreichen des Compare-Wertes beginnt der Timer wieder bei Null. Zugleich wird beim Erreichen des Comparevalues das DCC-Bit per Hardware umgeschaltet. Die Ausgänge der Komparatoren sind mit dem Leistungstreiber verbunden und erzeugen das Gleissignal.

    Gleichzeitig mit dem Neustart des Timers wird ein Interrupt ausgelöst, die Interruptroutine trägt die Compare-Werte für das nächste Bit ein, je nach dem ob 0 oder 1 ausgegeben werden soll. Jeder Polaritätswechsel des DCC-Signals erzeugt also einen Interrupt, jeder zweite Interrupt schaltet um ein Bit innerhalb der DCC-Message weiter.

    Beginnend mit der Preamble hangelt sich die Interruptroutine nun Bit um Bit durch die DCC-Message, wobei sie auch noch gleich den Overhead des DCC Protokolls (sozusagen Layer 1) mit erledigt, d.h. es wird die Preamble und die Prüfsumme (XOR-Byte) in der ISR errechnet und mit ausgegeben.

    Das "nächsthöhere" Programm muß also nur die Nutzbytes zusammenstellen und an DCCOUT übergeben (im Datenarray "next_message"). Die Übergabe ist durch ein Semaphor ("next_message_count") verriegelt - DCCOUT übernimmt nur, wenn dieses Semaphor größer Null ist und decrementiert bei jeder Übernahme dieses Semaphor um 1.

S88.C, Einlesen der Rückmelder

    In S88.C werden die Rückmelder eingelesen und auf Änderungen überwacht. Es gibt drei S88-Stränge, diese werden parallel eingelesen. Wenn ein Strang kürzer ist (d.h. weniger Bits hat), dann wird dieser Strang zwar mitgetaktet, die Bits werden jedoch nicht mehr ausgewertet.

    Es werden 1024 Rückmelder unterstützt, diese sind allerdings nicht in allen Interface-Formaten verfügbar. Wenn der HSI88-Mode aktiviert ist, dann können nur 31*16 = 496 Rückmeldekontakte abgefragt werden. Mehr ist in der HSI88 Beschreibung nicht vorgesehen und auch PC-Steuerprogramme limitieren bei Wahl eines HSI88 auf 496 Rückmelder.

    Es gibt zwei Datenarrays, s88_data und s88_change. Wenn beim Einlesen des S88-Bus nach S88-Data ein Wechsel zum bisherigen Zustand festgestellt wird, dann wird an der entsprechenden Stelle in s88_change das Bit gesetzt; Wenn dieser Wechsel an den PC gemeldet worden ist, dann wird das Change-Flag wieder gelöscht;
    Die Meldung an den PC erfolgt je nach Protokoll entweder je Nibble (Lenz), je Byte (Intellibox) oder als 16-Bit Wert (Littfinski HSI88).

STATUS.C, Timertick und Zustandsverwaltung

    In Status.c werden die LEDs angesteuert, Tasten und externe Eingänge abgefragt und der Zustand von OpenDCC verwaltet.

    Die LED Ansteuerung erfolgt timergesteuert mit Hilfe einer Kontrollstruktur led_pwm. Diese enthält für jede LED die Restleuchtdauer in aktuellen Zustand, die Einschaltzeit und die Ausschaltzeit. Wenn die Restleuchtdauer zu Null gesetzt wird, bleibt der Zustand für immer erhalten. Damit lassen sich ganz einfach unterschiedlich Blinkmodi generieren:
      LED_RS232_OFF;
         led_pwm.rs232_rest = 20000L / TICK_PERIOD;
         led_pwm.rs232_ontime = 50000L / TICK_PERIOD;
         led_pwm.rs232_offtime = 150000L / TICK_PERIOD;
         break;
    Beispielsweise wird mit diesen Einstellungen die RS232-LED für 20ms ausgeschaltet, fortan blinkt sie mit einem Puls-Pausenverhältnis von 1:3 und 5Hz. TICK_PERIOD ist das Interval der Timerinterrupts und wird in config.h auf 5ms gesetzt. Alle Zeitangaben erfolgen in µs, d.h. 50000L bedeutet 50ms; Zu beachten ist, dass die Zeiten als unsigned char gespeichert werden, d.h. die Zeiten müssen kleiner 1,25s sein.

    Weitere Verwendung findet der Timer als Entprellmaschine der Tasten und als Timeoutzähler.

ORGANIZER.C, Lokverwaltung und Befehlsverwaltung

    Diesem Modul obliegt es, sowohl für geringe Latenzzeit und hohen Datendurchsatz bei den Fahrbefehlen zu sorgen, als auch den Refresh bereits fahrender Loks zu organisieren. Hier liegt einer der Hauptvorteile von OpenDCC gegenüber käuflichen Zentralen!

    Die eigentlich limitierende Grenze ist der Durchsatz am Gleis - DCC hat im Schnitt etwa 4000 - 5000 Bit/s bzw. 100 Nachrichten / s. Deshalb ist in OpenDCC ein Regelwerk definiert, das dafür sorgt, dass neue Befehle schnell aufs Gleis kommen und dann mit sinkender Priorität in den allgemeinen Refresh einsortiert werden.

    Bremsbefehle (d.h. Befehlen, bei denen die Geschwindigkeit gegenüber der aktuellen Geschwindigkeit verringert ist) werden mit höchster Priorität aufs Gleis gelegt, parallel anliegende Beschleunigungsbefehle an eine andere Lok müssen ein klein bischen warten.

    Das Regelwerk des Organizers
    für Lokfahrbefehle: Lokgeschwindigkeit in den Lokspeicher eintragen.
    
    Alle Queues und Buffer nach dieser Lok durchsuchen, ob ev. da noch ein
    älteres Kommando an diese Lok wartet - wenn ja, dieses ersetzen.
    
    Geschwindigkeit größer oder kleiner als die aktuell gefahrene Geschwindigkeit?
       - falls kleiner: -> Befehl in die High Priority Queue.
       - falls größer (oder Funktion bzw. Accessory):
                        -> Befehl in die Low Priority Queue.
    
    Wenn ein Befehl aus einer Queue verarbeitet worden ist, dann kommt er
    anschließend in den Repeat Buffer:
        Speedbefehle mit 3 Repeats, Accessory-Befehle mit 2 Repeats.
    
    Bei der Gleisausgabe gilt dann folgende Reihenfolge:
       1. High Priority Queue.   wenn diese leer ist:
       2. Low Priority Queue.    wenn diese leer ist:
       3. Repeatbuffer.          wenn dieser auch leer ist:
       4. Lokspeicher refreshen. (jeweils in der Sequenz:
                 Speed, Funkt1, Speed, Funkt2, Speed, Funkt3, Speed)
    

    Darüber hinaus beachtet der ORGANIZER noch ein paar Zusatzregeln wie z.B. kein Befehl an die gleiche Loks in Folge, Vorrang für Broadcast-Befehle.

    Anzahl von Lokomotiven und Lokformat
    OpenDCC kann 9999 (Lenz-Parser) bzw. 16383 (Intellibox-Parser) verschiedene Loks adressieren, diese können aber nicht gleichzeitig fahren. Die Zahl der gleichzeitig zu fahrenden Loks ist (bei der aktuellen SW-Version) auf 64 begrenzt (Speicherplatz im Lokspeicher), mehr Loks kann das DCC-Protokoll eigentlich nicht sinnvoll ansprechen. Eine DCC-Message dauert etwa 8-12ms, je nach Adresse und Fahrstufen, d.h. bei 10 oder mehr gleichzeitig bremsenden Loks beginnt es interessant zu werden. Es können aber durchaus mehr Loks vorhanden sein, der Lokspeicher und Repeatbuffer werden bei Platzproblemen durch Verdrängen der "ältesten" Lok angepasst. Diese "älteste Lok" wird dann nicht mehr refreshed.

    OpenDCC kann die Loks mit DCC14, DCC28 bzw. DCC128 ansprechen. Das wird für den Fall des Lenz-Protokolls einfach durch den Fahrbefehl festgelegt. Für den Fall des IB-Protokoll gibt es keinen Befehl, welcher das Format definiert. Es wurden daher zwei zusätzliche Befehle definiert, welche die Übergabe eines Lokformats vom PC erlauben:
    P50X-ASCII LS {Lok#, [Format], [Steps]}
    als Format ist nur "2" (=DCC) erlaubt.
    P50X-BINÄR 0x86: XLokCfgSet - length 1+3;
    byte1+byte2 = addr, byte3 = format

    Manche PC Steuerungsprogramme speichern das Lokformat nicht selbst, sondern fragen bei der Modellbahnzentrale nach, welches Format die einzelne Lok hat. OpenDCC unterstützt das dadurch, dass ein einmal gesendetes Lokformat für eine bestimmte Lok im EEPROM der Zentrale gespeichert wird und bei der der nächsten Abfrage des PC-Programms wird dann dieses gespeicherte Format zurückgemeldet.

    Wenn eine Lok noch nie gefahren wurde, so wird das DEFAULT Format zurückgemeldet. OpenDCC arbeitet mit DCC28 als default-Einstellung (Dies ist durch eine CV änderbar). Um nun eine Lok auf ein anderes Format umzustellen, genügt es, einmal diese Lok in dem gewünschten Format anzusprechen. Es können maximal 64 Loks gespeichert werden, die ein von der default-Einstellung abweichendes Format haben.

    Intern werden alle Geschwindigkeiten im DCC128-Format abgespeichert. Innerhalb des Parsers wird fallweise vom reduzierten Lenz-Format auf DCC128 umgesetzt. (Routinen: convert_speed_to_rail() und convert_speed_from_rail()). Diese Umsetzung erfolgt auch bei der Gleisausgabe je nach aktuell für diese Lok eingestelltem Format.
    Wenn als Parser der Intellibox(R)-Parser verwendet wird, so ist keine Umsetzung auf der Parserseite erforderlich, P50X liefert immer 0..127 als Geschwindigkeit. Im MSB der Geschwindigkeit ist die Fahrrichtung kodiert.
    Zusammenfassung der Funktionsaufrufe des ORGANIZER
    init_organizer(void)
    organizer_ready(void)
    do_loco_speed_f(addr, speed, format)   Geschwindigkeit und Format einer Lok einstellen
    do_loco_speed(addr, speed)             Geschwindigkeit einer Lok einstellen
    do_loco_func_grp0(addr, funct)         Lichtfunktion
    do_loco_func_grp1(addr, funct)         Funktionen f1-f4
    do_loco_func_grp2(addr, funct)         Funktionen f5-f8
    do_loco_func_grp3(addr, funct)         Funktionen f9-f12
    do_accessory(addr, output, activate)   Weichenschaltbefehl
    do_all_stop(void)                      Bremsbefehl
    

RS232.C, Kontrolle der seriellen Schnittstelle

    OpenDCC läuft in der Voreinstellung mit 19200 Baud (das ist auch default bei Lenz V3.0). Diese Rate kann mit dem Befehl BAUD (0xF2) auch auf 38400, 57600 und 115200 Baud umgestellt werden bzw. schon beim Übersetzen auf einen anderen Wert gestellt werden. (init_rs232-Aufruf in main.c)

    Das Datenformat ist immer 8 Datenbits, kein Parity, 1 Stopbit (8n1).

    Die gesamte Kommunikation erfolgt interruptgesteuert und wird mit Fifos (Tiefe je 64 Bytes) gepuffert. 5 Bytes bevor der Eingangsspeicher voll läuft, wird per Hardware-Handshake der PC angehalten.

    Wenn OpenDCC ein BREAK empfängt (d.h. Rx liegt sehr lange auf +12V, bzw. es werden lauter 0 empfangen), dann wird wieder automatisch 19200 Baud eingestellt. Siehe hierzu auch die Kommentare in ISR(SIG_UART_RECV).

PROGRAMMER.C, Servicemode

    Die Software kann DCC-direct, aber auch die veralteten Register oder Paged mode-Programmierung.
    Im Direct-Mode werden mindestens 3 führende Reset-Packets, dann mind. 5 Servicemode-Packets, dann nochmal 6 Resetpackets gesendet. Die Servicemode-Pakets werden vorzeitig beendet, sobald ein ACK erkannt wird.
    Die Zahl der Packets ist einstellbar, jedoch nur innerhalb zulässiger Grenzen (um Fehlkonfigurationen auszuschließen) In der default-Einstellung werden noch je 3 führende Resetpackets und 3 servicemode-Packets draufgepackt, die zusätzlichen Packets kann der Anwender über eine CV-Einstellung verändern.
    Die ACK-Erkennung geht per Hardware, Stromerhöhung von 50mA wird über zwei RC-Glieder unterschiedlicher Zeitkonstante detektiert.

MAIN.C, Hauptprogramm

    Es gibt 4 Interruptroutinen:
    • DCC Counter: Dieser Interrupt veranlaßt das Neuprogrammieren des Counters 1. Damit werden die Sequenzen für DCC0 und DCC1 auf den Vergleichsausgängen dieses Zählers erzeugt.
    • Timer Tick: damit werden Tastaturabfragen und Timeouts gesteuert.
    • UART Rx: Empfangenes Byte wird in Fifo abgelegt.
    • UART Tx: Ein Byte im Sendefifo wird abgeschickt.

    Diese 4 Interrupts übernehmen somit alle zeitkritischen Funktionen. Die Abarbeitung der Befehle und die Kontrolle wird vom Hauptprogramm gemacht, das zyklisch die Module aufruft. Die Routinen in den Modulen müssen zurückgeben, sofern sie nichts zu tun haben.

    Das Hauptprogramm gibt diese Struktur wieder:
    int main(void)
      {
    
        init_main();                       // all io's
        init_dccout();                     // timing engine for dcc
        init_organizer();                  // engine for command repetition,
                                           // memory of loco speeds and types
        init_rs232();                      // isrs+fifos from/to pc
        init_interrupt();
        init_tick();                       // 5ms timer tick
        init_programmer();                 // dcc programmer
        init_parser();                     // command parser
    
        set_opendcc_state(RUN_OFF);        // abgeschaltet
    
        while(1)
         {
           run_state();                    // check short and keys
           run_organizer();                // let run command organizer
           run_parser();                   // check commands from pc
         }
      }

Links

    Protokoll und Analyse des Gleissignals: mit ShowDCC und einem kleinen Adapter für die Soundkarte:

    (Offenbar hat digitoys das tool vom Web entfernt, aber das Internet vergißt nichts, siehe hier.)