Fun with Arduino 29 DCC Accessory Decoder

Modern model railroads are digital controlled, using the Digital Command Control (DCC) protocol, whereby data is embedded in the AC voltage that is put on the track to drive the trains. DCC accessory- and servo decoders are available on the market to decode the DCC data and to act on it if the command was meant for their address. If we can use an Arduino to control our accessories and servos via DCC we can reduce cost by a factor 10. The good news is … we can!

Read on below the video …

 

Hardware

The DCC signal is an alternating voltage somewhere between 12 and 24V, depending on your DCC Command Station settings. We use a small electronic circuit to translate this to 5V, to safely connect it to our Arduino.

DCC-Opto

Beware that standard resistors have a 1/4W power rating … the 1k input resistor can get hot if your track voltage exceeds 15V. In that case use 2x2k2 in parallel.

We can’t use just any opto-coupler. The 6N137 is a fast one, which is needed because DCC decoding relies on measuring pulse width: 50µs is a ‘1’, 100µs is a ‘0’. A slow opto-coupler could distort this timing.

The output of the opto-coupler is connected to Arduino pin 2. This pin provides the hardware interrupt mechanism that is used with the Arduino DCC data decoding library. Do not change this pin or your DCC decoder won’t work.

Software

The software for a DCC accessory decoder is remarkably simple. Well … this is not entirely true, it is complex, but the complex part is taken care of in the DCC library … all we have to do is: #include <DCC_Decoder.h>

The DCC library can be downloaded here. Unzip it and move the folder to your Arduino libraries folder, usually found in My Documents/Arduino/libraries.

We need to configure our accessories. We fill in how many accessories are connected to this Arduino:

#define NUMACCESSORIES 2 // Enter the number of accessories here

Then in void setup() we fill in their Arduino pin numbers and the DCC addresses we want them to react to:

accessory[0].address   =  1; // DCC address
accessory[0].outputpin = 13; // Arduino pin

accessory[1].address   =  2; // DCC address
accessory[1].outputpin = 12; // Arduino pin

In this example only 2 accessories are configured. To add more, copy & paste, change the index pointer, pin number and DCC address.

The code for a complete DCC accessory decoder. The code contains a function (more about functions in a later later video) called: void BasicAccDecoderPacket_Handler(). This function switches our accessories on or off, based on DCC data read via the library. IMPORTANT: Roco decided to shift the addresses by 4. I don’t know why they did that, but if you use a Roco Maus or Z21, uncomment the line that says address = address  – 4.

#define NUMACCESSORIES 2 // Enter the number of accessories here

// GO TO setup() TO CONFIGURE DCC ADDRESSES AND PIN NUMBERS

#include <DCC_Decoder.h>

typedef struct DCCAccessoryData {
  int   address;   // User Configurable DCC address
  byte  outputpin; // User Configurable Arduino pin
  byte  dccstate;  // Internal use DCC state of accessory, 1=on, 0=off
};
DCCAccessoryData accessory[NUMACCESSORIES];

// The DCC library calls this function to set / reset accessories
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data) {
  address -= 1;
  address *= 4;
  address += 1;
  address += (data & 0x06) >> 1;
  // address = address - 4; // uncomment this line for Roco Maus or z21
  boolean enable = (data & 0x01) ? 1 : 0;
  for (byte i=0; i<NUMACCESSORIES; i++) {
    if (address == accessory[i].address) {
      if (enable) accessory[i].dccstate = 1;
      else accessory[i].dccstate = 0;
    }
  }
}

void setup() { 
// CONFIGURATION OF ACCESSORIES
// Copy & Paste as many times as you have accessories 
// The amount must be same as NUMACCESSORIES
// Don't forget to increment the array index
  accessory[0].address   =  1; // DCC address
  accessory[0].outputpin = 13; // Arduino pin

  accessory[1].address   =  2; // DCC address
  accessory[1].outputpin = 12; // Arduino pin
// END OF CONFIGURATION OF ACCESSORIES

  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  DCC.SetupDecoder( 0x00, 0x00, 0 );

  for(byte i=0; i<NUMACCESSORIES; i++) {
    pinMode     (accessory[i].outputpin, OUTPUT);
    digitalWrite(accessory[i].outputpin, LOW);
  }
}

void loop() {
  DCC.loop(); // Call to library function that reads the DCC data

  for(byte i=0; i<NUMACCESSORIES; i++) {
    if (accessory[i].dccstate)
      digitalWrite(accessory[i].outputpin, HIGH);
    else
      digitalWrite(accessory[i].outputpin, LOW);
  }
}

Just 60 lines of code … that’s it. The video shows it under test with my DR5000. I have 6 LEDs connected to pins 14-19 (A0-A5). The DCC output is connected to the opto-coupler input, a Switch window is opened and when I toggle DCC addresses 1 – 6 the LEDs switch on or off. Yes … that works perfect!

In the next video we are going to make a DCC servo decoder.

— 0 —

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s