const byte DCC_PIN = PB2;
const byte MY_ADDRESS = 15;
const byte OUT_FWD = PB0; // Pin 5
const byte OUT_REV = PB1; // Pin 6
// --------------------
// DCC Zustände
// --------------------
enum State {
SEARCH_PREAMBLE,
READ_BYTE,
READ_TRUNC_BIT
};
State state = SEARCH_PREAMBLE;
byte oneCount = 0;
byte bitCount = 0;
byte currentByte = 0;
byte phase = 0;
byte address = 0;
byte command = 0;
byte data = 0;
byte xorByte = 0;
// --------------------
// Timing
// --------------------
unsigned long lastTime = 0;
// ====================================
// SETUP
// ====================================
void setup()
{
pinMode(DCC_PIN, input);
pinMode(OUT_FWD, OUTPUT);
pinMode(OUT_REV, OUTPUT);
analogWrite(OUT_FWD, 0);
analogWrite(OUT_REV, 0);
}
// ====================================
// HAUPTSCHLEIFE
// ====================================
void loop()
{
// Flankenerkennung (muss noch validiert werden)
if (digitalRead(DCC_PIN) == HIGH)
{
while (digitalRead(DCC_PIN) == HIGH);
unsigned long now = micros();
unsigned long dt = now - lastTime;
lastTime = now;
byte bit;
// --------------------
// Bitentscheidung
// --------------------
if (dt < 80)
bit = 1;
else
bit = 0;
// ====================================
// 1. PRÄAMBEL SUCHE
// ====================================
if (state == SEARCH_PREAMBLE)
{
if (bit == 1)
{
oneCount++;
}
else
{
if (oneCount >= 10)
{
state = READ_BYTE;
phase = 0;
bitCount = 0;
currentByte = 0;
}
oneCount = 0;
}
}
// ====================================
// 2. BYTE LESEN
// ====================================
else if (state == READ_BYTE)
{
currentByte <<= 1;
currentByte |= bit;
bitCount++;
if (bitCount == 8)
{
// Byte je nach Phase zuordnen
if (phase == 0)
{
address = currentByte;
if (address != MY_ADDRESS)
{
state = SEARCH_PREAMBLE;
}
else
{
state = READ_TRUNC_BIT;
phase = 1;
}
}
else if (phase == 1)
{
command = currentByte;
state = READ_TRUNC_BIT;
}
else if (phase == 2)
{
data = currentByte;
state = READ_TRUNC_BIT;
}
else if (phase == 3)
{
xorByte = currentByte;
// XOR prüfen
if ((address ^ command ^ data) == xorByte)
{
executePacket();
}
state = SEARCH_PREAMBLE;
}
bitCount = 0;
currentByte = 0;
}>br>
}
// ===================================
// 3. TRENNBIT (0 oder 1 nach Byte)
// ===================================
else if (state == READ_TRUNC_BIT)
{
// DCC: 0 = nächstes Byte folgt
// 1 = Paketende
if (bit == 1 && phase < 3)
{
state = SEARCH_PREAMBLE;
return;
}
phase++;
state = READ_BYTE;
}
}
}
// =========================================
// AUSWERTUNG
// =========================================
void executePacket()
{
// 128 Fahrstufenformat (0x3F)
if (command == 0x3F)
{
byte direction = (data & 0x80);
byte speed = (data & 0x7F);
byte pwm = speed << 1; // grobe Skalierung 0..255
if (direction)
{
analogWrite(OUT_FWD, pwm);
analogWrite(OUT_REV, 0);
}
else
{
analogWrite(OUT_FWD, 0);
analogWrite(OUT_REV, pwm);
}
}
}
Ganz oben haben wir dem Programm beim Hochladen schon die Adresse der jeweiligen Lok 'MY_ADDRESS' mitgegeben. Denn in der Lok wollen wir das Programm nicht einem Arduino, sondern dem viel
kleineren ATtiny mitgeben und da heißt es Speicherplatz sparen.