The DCC signal is an alternating voltage (AC) usually 16V, depending on your DCC controller. We use rectifier and LM7805 regulator to convert it to 5V (DC) that can safely power Arduino DCC decoder.
The 6N137 is a fast opto-coupler that is necessary because DCC decoding relies on measuring pulse width where 50µs represents 1 and 100µs represents 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 bye Arduino DCC data decoding library. Do not change this pin or your DCC decoder will not work.
Software
The software for a DCC decoder is remarkably simple thanks to NmraDcc DCC library.
NmraDcc library can be downloaded here. Unzip it and move it to your Arduino libraries folder, usually found in My Documents/Arduino/libraries.
You will need to edit
#define This_Decoder_Address 6 as this sets DCC address of Arduino DCC decoder to an address of your choice.
The following arduino sketch toggles 17 LEDs attached to the Arduino Pro Mini by pressing 6 (DCC address) on DCC controller, followed by function button and number that will toggle each LED independently.
#include <NmraDcc.h>
#include <SoftwareSerial.h>
byte rxPin = 0;
byte txPin = 1;
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
#define numleds 17
byte ledpins [] = {0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
const int FunctionPin0 = 3;
const int FunctionPin1 = 4; //D4
const int FunctionPin2 = 5; //D5
const int FunctionPin3 = 6; //D6
const int FunctionPin4 = 7; //D7
const int FunctionPin5 = 8; //D8
const int FunctionPin6 = 9; //D9
const int FunctionPin7 = 10; //D10
const int FunctionPin8 = 11; //D11
const int FunctionPin9 = 12;
const int FunctionPin10 = 13; //D3
const int FunctionPin11 = 14; //A0
const int FunctionPin12 = 15; //A1
const int FunctionPin13 = 16; //A2
const int FunctionPin14 = 17; //A3
const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5
NmraDcc Dcc;
DCC_MSG Packet;
#define This_Decoder_Address 6
extern uint8_t Decoder_Address = This_Decoder_Address;
struct CVPair {uint16_t CV; uint8_t Value; };
CVPair FactoryDefaultCVs [] = {{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},};
uint8_t FactoryDefaultCVIndex = 0;
void notifyCVResetFactoryDefault(){ FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); };
void setup(){
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
// initialize the digital pins as an outputs
for (int i=1; i<= numleds; i++){ pinMode(ledpins[i],OUTPUT); digitalWrite(ledpins[i],LOW); }
delay(500);
Dcc.pin(0, 2, 0); // Setup External Interrupt and enable the Pull-Up
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); // Enable DCC Receiver
}
void loop(){
Dcc.process();
if( FactoryDefaultCVIndex && Dcc.isSetCVReady()){
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
}
}
extern void notifyDccFunc( uint16_t Addr, uint8_t FuncNum, uint8_t FuncState) {
if (FuncNum==1) { //Function Group 1 F0 F4 F3 F2 F1
digitalWrite( FunctionPin0, (FuncState&0x10)>>4 );
digitalWrite( FunctionPin1, (FuncState&0x01 ));
digitalWrite( FunctionPin2, (FuncState&0x02)>>1 );
digitalWrite( FunctionPin3, (FuncState&0x04)>>2 );
digitalWrite( FunctionPin4, (FuncState&0x08)>>3 );
}
else if (FuncNum==2) { //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
if ((FuncState & 0x10)==0x10) {
digitalWrite( FunctionPin5, (FuncState&0x01 ));
digitalWrite( FunctionPin6, (FuncState&0x02)>>1 );
digitalWrite( FunctionPin7, (FuncState&0x04)>>2 );
digitalWrite( FunctionPin8, (FuncState&0x08)>>3 );
}
else {
digitalWrite( FunctionPin9, (FuncState&0x01 ));
digitalWrite( FunctionPin10, (FuncState&0x02)>>1 );
digitalWrite( FunctionPin11, (FuncState&0x04)>>2 );
digitalWrite( FunctionPin12, (FuncState&0x08)>>3 );
}
}
else if (FuncNum==3) { //Function Group 2 FuncState == F20-F13 Function Control
digitalWrite( FunctionPin13, (FuncState&0x01 ));
digitalWrite( FunctionPin14, (FuncState&0x02)>>1 );
digitalWrite( FunctionPin15, (FuncState&0x04)>>2 );
digitalWrite( FunctionPin16, (FuncState&0x08)>>3 );
}
}
Notes
- 1N4148 small signal diode may be used in place of 1N4152 diode
- Two 1N5819 diodes are not critical and may be omitted
- R17 5K resistor may be replaced by 10K resistor
- C8 270pF capacitor is not critical and may be omitted
- Use 1K resistors in place of 10K for powering LEDs
DCC decoder test circuit with 8 LEDs. Arduino Pro Mini powered by external 5V DC power source omitting DC regulator circuitry.