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 …



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.


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.


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


#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() { 
// 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

  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);
      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 —



27 thoughts on “Fun with Arduino 29 DCC Accessory Decoder

  1. Hallo Rudy,

    Als ik je voorbeeldbestand compileer, dan krijg ik de onderstaande melding. Ik heb dan nog niets aangepast en alleen van te voren de DCC bibliotheek geïnstalleerd. Wat gaat er fout?

    C:\Users\Gebruiker1\Documents\Arduino\sketch_dec14c\sketch_dec14c.ino:7:1: warning: ‘typedef’ was ignored in this declaration

    typedef struct DCCAccessoryData {

    Groeten, Mark


  2. Hi Rudy,
    This is a great code and circuit, thank you. When trying to use it to control 16 outputs through 2 sets of 8 x relays, the digital ports 3 to 12 work fine but with the analog pins A0 to A5 (13-18) the reaction is terribly slow, useless in practice. Any clue? Thank you. Joaquin.


    • Well, that is strange, I never noticed any delay on A0-A5. Could it have anything to do with A0-A5 having pin numbers 14-19, and not 13-18 like you mentioned?


      • Thank you for your reply. Yes, the analog pins are 14-19, sorry, was a mistake. I begin to think this is not a problem with the analog pins. It is some kind of saturation (optocoupler?). I have tried with a Mega 2560 (so with lots of digital pins) and everything goes well until I increase the number of pins connected to the relay array. The connectivity is fast until 8 relays are connected but when I index more accesories the control progressively slows down. Everything above 11 is impossible. I think I will use and independent card for every 8-array. the only way i find.


      • Well, this is very strange of course, since the Arduino is not aware what kind of unit is connected to its outputs. Have you checked the speed if you test the outputs with an LED plus resistor?


      • Rudy, I may confirm now that the problem is reproduced with led+resistor array. So this is not a poblem with the load or any other problem with the relay array. I have checked the relay array with a simple script and the arduino board is able to control the array with no problem. Any other idea? thank you!


  3. OK, that is what I expected, the type of unit connected to output pins should not make any difference. So the issue is that with the DCC decoder software, when you try to control ports 14 – 19 they respond slow? Weird, because in the code it makes no difference if you control pin 5 or pin 15. What happens if you configure it to only control 6 outputs on pins 14 – 19. Then add outputs 3 -12. Are you sure your DCC signals are coming through with the speed you expect?


    • I agree, the type of output is irrelevant. It seems that there is no difference with the order or pin type. For example you can use 14-19 plus 3-4 efficiently -no problem at all- but then as soon as you incorporate 5-6 then you begin to get troubles. So it is not related to the nature of the pins but connected with the number of pins (>8 pins = trouble). In fact, as I told you you, I can use a Mega just with logical pins and the problem is exactly reproduced; cannot control more than 8 pins efficiently. What about the DCC signal converter through the optocoupler, may be a problem with the number of signals being controlled?


      • have you tried using a switch statement instead of a for loop ? A loop iterates through all the addresses, whereas a switch statement with a whole heap of cases can be a lot quicker. This is not something that is recommended by modern coding standards, but is very common in old embedded firmware implementations.
        Also, although it doesn’t usually make a difference, I have noticed that the Arduino compiler doesn’t always handle compound statements correctly I would always use curly brackets to encapsulate the contents of a IF statement – even if it is just a single line.


  4. Hi Rudy. My name is Hans. I’m running g scale in my garden and want to use your accessory decoder idea at remote places, powered by the DCC signal from the track. I was thinking of using the input ports of the Arduino Uno also for sending block occupancy (reed switches) status to the command station (Arduino Mega). Is this possible and does it need extra doing or is it handled by the dcc-decoder.h library. Thanks for answering.


    • Hans, DCC decoders and sensor feedback can not be combined in one Arduino. For the feedback you need an S88 bus and the Arduino S88 software available in my download, or you can use Arduino based Loconet module. I’d advise you to have a look at this website: and get yourself the DDCnext modules and the Arloco shields. They are cheap and all the software you need is free and extensive user manuals are available.


  5. Hi, This looks fantastic. I want to get this running and control some scenery LED lights on my son’s railway. Can you point me to the bits I need to buy? I have a background in programming but no experience with arduinos.


      • Hi Rudy,
        So I got the parts, built the circuit, no joy – I can’t get it to work.
        We’re using a Hornby Select controller, Arduino Uno, and the parts from your circuit.
        Should the LED flash? Ours isn’t doing anything. Occasionally the Hornby Select goes OL for overload. I’ve checked the circuit and can’t find a problem.
        I used your code above and when I verify it says the typedef is ignored. Not sure why.
        I set it up with one accessory, address 15, Arduino output 13.
        I then pick address 15 on the Select. I tried forwards / backwards direction, function on / off, and turning the speed dial. No LED from the arduino.

        What do you suggest?


      • A bit more progress, but we’re still stuck.
        First off, our LED was the wrong way around on pins 2 and 3 of the opto. It now illuminates but we still can’t get the uno to turn output LEDs on and off in response to DCC packets.

        I wrote a script to test the circuit and check the uno is getting interrupts and YES it is getting them.

        The time between interrupts (timed using the micros function) is 12 or 16 us, ocassionally 40us.
        I did try getting the uno to count the interruprs and it came to about 27,300 per second. That suggests they’re every 36us on average. Every second my script records the gap between the two most recent interrupts so that could be correct, but it mostly says 12us or 16us rather than the 40us which surprises me.

        I notice in the DCC_Decoder.cpp it defines the min and max micros for zeros and ones to be:
        #define kONE_Min 52
        #define kONE_Max 64
        #define kZERO_Min 90
        #define kZERO_Max 10000

        So if we’re getting an interrupt every 12, 16 or 40us then it’s not a zero or a one in DCC binary. So the library isn’t getting any valid packets.

        So I’m still confused. Unfortunately I don’t have a oscilloscope to check what’s actually happening.

        Any suggestions?


  6. For anyone else picking this up – we got it working. The Hornby Select controller seems to need to have a railway connected to it as well as the arduino. At first I just had the Select and the Arduino and no packets were received. Once I connected up the trains too the arduino decodes accessories on addresses 60-99.


  7. Hi Rudy,
    I have made the decoder as shown in the video but it is not working for me (I have tested the optocoupler and I tried 3 arduino boards too). Maybe the problem is that I am using a Roco Z21Start?


    • With Roco the DCC addresses are shifted by 4, which means when you want to activate address 1 in the Arduino you need to activate 5 on the Roco. Of course we can change the Arduino code to subtract 4 to get them in sync. An alternative is to use the free software from , you can configure it via PC and you can tell it to work with Roco.


  8. I shifted the addresses in the code but it is not working. I tried the DCC decoder library example called DCC monitor but it is just showing 0 packages. It seem like it is not reading the dcc signal.


    • This indeed sounds as if the signal on Arduino pin 2 is not OK. Is the hardware 100% according to the schematics? Do you have any means to measure? Can you try another opto coupler?


  9. For me this works fine and solves a problem or two I had.. so thank you 🙂 As a question… all the addresses seem hardcoded in the program.. is there a way to add a programming button with a LED so that when pressed, the first address received is the one that is accepted with the rest daisy chaining as needed to the maximum no of adresses and once programmed resets so the LED goes out?

    Whilst hard coded works without a problem, it would be nice to get a little more flexibility for multiple boards etc without having to check the right board is setup for the right addresses. Currently I have three sketches for my three boards and I have to remember on changes which board is being changed 🙂




Leave a Reply

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

You are commenting using your 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