Aus den im Dezimalformat vorliegenden Carrera Datenworten erzeugt der Arduino mit Hilfe des hier
beschriebenen Sketches Manchester codierte Bits. Pin 3 des Arduinos wird dazu gemäß der
Carrera Protokolldefinitionen, synchron zum Takt, auf HIGH oder LOW geschaltet. Hier noch mal zur Erinnerung:
Bei der Manchester-Codierung wird jedes Datenbit in zwei Hälften geteilt,
wodurch der Leitungscode gleichzeitig das Taktsignal erhält. Die fallende Flanke, bezogen auf eine volle Taktrate,
steht bei Carrera für die logische 1, die ansteigende Flanke für die logische 0.
Abbildung 1
Zur Definition des Carrera Codes, fallende Flanken beim vollen Takt bedeuten eine 1 und steigende Flanken eine 0
Die Erzeugung von Manchester Bits ist grundsätzlich wesentlich einfacher als die Dekodierung.
Der Mikrocontroller muss bei der Codierung nicht umständlich mit dem Takt synchronisiert werden, was den
Algorithmus angenehm kurz hält. Lediglich eine Besonderheit des Carrera Codes, die unterschiedlichen
Wortlängen, müssen von dem Algorithmus berücksichtigt werden. Ziel ist eine möglichst einfache
Subroutine, die lediglich den dezimalen Wert des zu erzeugenden Datenworts übergeben bekommt und
anschließend autonom die notwendigen Bits an Pin 3 des Arduinos erzeugt.
Abbildung 2
Der Programmablaufplan zur Codierung der Carrera Bits.
Die Routine bekommt beim Aufruf das zu codierende Datenwort als 2 Byte Zahl (unsigned long) übergeben.
Die Carrera Worte können zwischen 13, 10 und 8 Bit lang sein, im ersten Schritt muss also das Startbit
in der 2 Byte langen Variablen gefunden werden.
Die Routine fängt dazu bei dem längsten möglichen Carrera Datenwort mit 13 Bits an und prüft ob
das Bit eine 1 oder eine 0 ist. Sobald eine 1 vorliegt, wurde das Startbit gefunden und die Routine kann
nachfolgend mit der Codierung der restlichen Bits beginnen. Je nach vorliegendem Bit wird dabei nach der halben
Taktrate ein Wechseln des Datenpins 3 von HIGH nach LOW oder umgekehrt ausgeführt.
void manchesterEncode(word dataWord){ //////
const int halfClockMicros = 40; // !!! experimental value for half clock rate of 50 microseconds !!!
int bitPos = 13; // bit counter for position of bit in dataWord
int currentBit = 0; // store current bit
while ( !currentBit ){ //
currentBit = ( dataWord >> bitPos ) & 1; // store bit on position bitPos in currentBit
bitPos--;} // switch to next postion
bitPos++; // get back to start bit
do{ //
currentBit = ( dataWord >> bitPos ) & 1; // store bit on position bitPos in currentBit
if ( currentBit == 1 ){ //
digitalWrite( dataOutPin, HIGH ); //
delayMicroseconds ( halfClockMicros ); //
digitalWrite( dataOutPin, LOW); //
delayMicroseconds ( halfClockMicros );} //
else{ //
digitalWrite( dataOutPin, LOW ); //
delayMicroseconds ( halfClockMicros ); //
digitalWrite( dataOutPin, HIGH ); //
delayMicroseconds ( halfClockMicros );} //
bitPos --; // goto next bit
} while ( bitPos >= 0 ); // until all bits are processed
digitalWrite(dataOutPin, HIGH ); // make sure to leave subroutine always with digital level HIGH
} //////
Ein bisschen Überlegung kostet die Bitoperation zum Herausfiltern des aktuellen Bits aus der Variablen dataWord.
currentBit = ( dataWord >> bitPos ) & 1;
Die Bits in dataWord werden dabei um die Anzahl bitPos nach
rechts "geshiftet", die frei werdenden Stellen links werden mit Nullen aufgefüllt. Anschließend
erfolgt eine bitweise UND-Verknüpfung mit 1, was dazu führt, dass alle Stellen bis auf die erste
ausgeblendet werden. Am Ende ist in currentBit das Bit der Stelle bitPos gespeichert und die Variable
hat entweder den Wert 1 oder 0.
Der Rest der Routine ist in Kombination mit dem Programmablaufplan selbsterklärend.
Wichtig ist die Konstante halfClockMicros. Hier habe ich mit 40 Mikrosekunden einen Wert gefunden, bei dem
mein mit 16 MHz getakteter Arduino Uno den Flankenwechsel im Durchschnitt nach 50 µs ausführt.
Diesen Wert habe ich durch
Ausprobieren und Nachmessen im Oszilloskop gefunden. Die Konstante wurde dabei so gewählt, dass die
Flanken von zwei aufeinander folgenden Bits genau 200 µs benötigen.
Das bedeutet, dass mein 16 MHz Arduino Uno
zur Ausführung der Schleife mit seinen Bitoperationen und dem digitalWrite() Befehl im Schnitt
ziemlich genau 10 µs benötigt. Dieser Wert ist für alle Nachbauer wichtig, wenn sie
einen anderen Arduino einsetzen möchten. Ein anderer Arduino wird höchstwahrscheinlich auch
andere Ausführungszeiten haben und die Konstante halfClockMicros muss dementsprechend angepasst werden.
Aber keine Panik, zur Anpassung ist kein Oszilloskop notwendig. Die Decoder der Carrera Wagen haben
eine gewisse Toleranz, was das Zeitverhalten des Bahnprotokolls angeht. Meine D143 Wagen haben
mit einer Konstanten halfClockMicros in dem Bereich zwischen 38 µs und 47 µs
auf die Signale reagiert. Das heißt, die Wagen
tolerieren eher einen zu langsamen Takt als einen zu schnellen. Falls also ein anderer Arduino
zum Einsatz kommt und der Decoder scheinbar nicht funktioniert, einfach die Konstante halfClockMicros
in 1 µs Schritten anpassen, irgendwann klappt es dann und die Flitzer setzen sich wie von
Geisterhand in Bewegung.
Experimentierkasten
Alle Dateien für eigene Experimente zum Download und auf einen Blick
- Carrera Protokoll Codier Definitionen, Open-Document Datei, odg
- Carrera Protokoll Codier Definitionen, PDF-Datei, pdf
- Manchester Codier Algortihmus Programmablaufplan, Open-Document Datei, odg
- Manchester Codier Algorithmus Programmablaufplan, PDF-Datei, pdf
Erstveröffentlichung: Februar 2013