Erläuterungen zur Software von OpenDecoder
- dcc_receive
Empfang des DCC Signals (interruptgesteuert) und Bereitstellen der empfangenen Nachricht. - dcc_decode
Analyse der empfangenen Nachricht; falls Servicemode oder PoM: Abwicklung der entsprechenden CV-Zugriffe - servo_engine
Frei programmierbarer Servo-Kontroller mit Zeit-Ortskurven. - port_engine
Programmierbarer Kontroller für IO (mit Zustandsautomaten, inkl. Blinken)
Interprozess-Kommunikation
-
OpenDecoder arbeitet im kooperativem Multitasking, wobei die
zeitkritischen Teile in Interrupts ausgelagert sind. Der
Nachrichtenaustausch zwischen diesen Modulen erfolgt mittels
Semaphor-Operationen. Diese erfolgen unter gesperrten
Interrupts, damit die Operationen sicher sind:
- Es gibt maximal 8 Semaphor-Bits, diese sind in config.h definiert, z.B. C_Received oder C_Save.
- Der Sender einer Nachricht ruft z.B. semaphor_set(C_Received) auf. Das zugehörige Semaphorbit wird gesetzt.
- Der Empfänger dieser Nachricht ruft semaphor_get(C_Received)
auf. Das zugehörige Semaphorbit abgefragt und gleichzeitig
zurückgesetzt.
Beispiel:
if (semaphor_get(C_Received)) analyze_received_message(); - Zusätzlich gibt es für *Spionagezwecke* noch die Methode semaphor_query(C_Received), mit der das Semaphor abgefragt werden kann, es aber dabei nicht verändert wird. Parallel zu diesen Semaphor-Operationen, welche die jeweiligen Ereignisse mitteilen, werden die Nachrichteninhalte über globale Variablen (z.B. ReceivedAddr) übermittelt. Dies ist nicht ganz sauber, jedoch sind die Zeitbedingungen recht entspannt, so daß kein Mailboxsystem erforderlich ist.
Timingsteuerung
-
Um den Decoder leicht auf verschiedene Anwendungsfälle anpassen
zu können, ist eine allgemeine Zeitsteuerung für jeden
Augangsport vorgesehen. Diese Timingsteuerung benutzt drei
Variablen je Ausgangsport:
- Port soll dauernd ein sein: Port = on, rest = 0;
Durch "rest=0" wird weiteres Umschalten dieses Ports verhindert. - Port soll einen einzelnen Puls mit 0,5s ausgeben: Port =
on, rest = 500ms, offtime = 0;
Der "rest" von 500ms bewirkt ein Umschalten und Nachladen nach 500ms, danach erfolgt keine weitere Umschaltung mehr, da ja "rest" mit 0 nachgeladen wurde. - Port mit um 1s verzögertem Puls von 2s Dauer: Port = off, rest = 1000ms, ontime = 2000ms, offtime = 0
- Wechselblinker:
Port1 = on, rest = 500ms, ontime = 500ms, offtime = 500ms;
Port2 = off, rest = 500ms, ontime = 500ms, offtime = 500ms
Jeweils nach 500ms wird nachgeladen, ontime + offtime ergeben zusammen die Periodendauer des Blinkens. - Lauflicht, Baustellenblitzer:
Port1 = off, rest = 100ms, ontime = 25ms, offtime = 975ms;
Port2 = off, rest = 150ms, ontime = 25ms, offtime = 975ms;
Port3 = off, rest = 200ms, ontime = 25ms, offtime = 975ms;
Port4 = off, rest = 250ms, ontime = 25ms, offtime = 975ms;
Port5 = off, rest = 300ms, ontime = 25ms, offtime = 975ms;
Port6 = off, rest = 350ms, ontime = 25ms, offtime = 975ms;
Port7 = off, rest = 400ms, ontime = 25ms, offtime = 975ms;
Port8 = off, rest = 450ms, ontime = 25ms, offtime = 975ms;
Alle 8 Ports haben die gleiche Periodendauer von einer Sekunde, werden allerdings um 50ms versetzt gestartet. Durch die kurze ontime entsteht der Blitzeffekt.
Variable | Bedeutung |
---|---|
rest | Restdauer des aktuellen Zustands |
ontime | Dauer des Einschaltzustands |
offtime | Dauer des Auschaltzustands |
Beispiele:
Dimmersteuerung:
-
Die Dimmersteuerung für das Überblenden geschieht mit einer
interruptgesteuerten achtfachen Pulsweitenmodulation (PWM).
Diese ist wie folgt implementiert:
- Es gibt 60 Helligkeitstufen. Der gewünschte Heilligkeitswert je Port wird in dimm_val hinterlegt.
- Alle 300us erfolgt ein Interrupt, dieser schaltet den
Dimmer um eine Stufe weiter, nach 60 Stufen wird wieder von
vorne begonnen. In jeder Stufe wird nun folgende Überprüfung
durchgeführt:
Stufe Aktion MIN alle Ports mit einem dimm_val > DIMM_MIN werden eingeschaltet. i Ein Port, dessen dimm_val kleiner x ist, wird abgeschaltet. MAX Restart und Meldung an den DIMMER (C_Dimmstep). - Folge: Alle Ports mit einem dimm_val kleiner DIMM_RANGE_MIN sind dauerhaft aus, alle Ports mit einem dimm_val größer DIMM_RANGE_MAX sind dauerhaft ein. Alle dazwischen liegenden Helligkeitswerte werden mit einer entsprechende PWM ausgegeben.
- Da die PWM 60 Stufen hat und alle 300us ein Interrupt erfolgt, wird dieser Durchlauf alle 18ms durchgeführt. Dies entspricht einer Refreshrate von 55Hz.
Die Rampe und Verzögerung wird für die normalen Signale mit der Funktion set_new_light_val eingestellt; dieser Funktion braucht man nur das Bitfeld der neuen Zustände zu übergeben, eine Anpassung an verschiedene Signalbilder sollte daher leicht möglich sein.
Der Weg zum eigenen Decoder
-
Nach Installieren der Tools (AVR Studio, WinAVR und Ponyprog)
wird AVR-Studio geöffnet und ein neues Project angelegt. Für
dieses wird als Simulationsumgebung AVR-Simulator und als
Prozessor ATtiny2313 ausgewählt. Für OpenDecoder V2 entsprechend
Atmega8515.
Nun wird unter Project->Configuration Options die Taktrate und Optimierungshinweise für den Compiler eingestellt (man beachte besonders -Os = optimize for size):
Hinweis: AVR Studio erwartet die Eingabe der Taktrate als Zahl (ohne UL), stellt die eingegebene Zahl dann jedoch mit angehängtem UL (=unsigned long) dar.
Das Orginalfile wird dann mit rechter Maus auf den Reiter Source-File und "add existing source file" zum Project hinzugefügt und nun wird zuerst mal ohne das Sourcefile zu verändern übersetzt. Damit kann man kontrollieren, ob die Umgebung richtig eingerichtet ist.