Model Railroad DCC Command Station V2

Introduction: Model Railroad DCC Command Station V2

Update 16th Aug 2018:
Now includes a CV1 write function to programme loco address numbers. This is a software modification only with no change to hardware. See updated Arduino Nano sketch. To access this CV1 write facility, hold down button 'A' on membrane keypad while turning on power. Ensure that only the loco to be addressed is on the track. Choose loco number 1-19 from the keypad then press 'A' again to programme new value for CV1. See step 3 for more details.

This is version 2 of my original DCC Command Station Instructable.

I have learned a number of things from the original experience about the Arduino Nano, the h-bridge LMD18200t and the TFT LCD display.

1. The analog pins on the Nano may be used for serial communications e.g. A3/A4 for Rx/Tx. The original used D0 and D1 making serial monitoring impossible. I have also used A2 and A5 as a digital outputs to control the on/off of the bridge output in event of over-current. Note: A6 and A7 cannot be used as digital output pins on the Nano.

2. The LMD18200t current sense pins on the actual IC package, do not work well and in some cases not at all. Therefore, I have added a 0.1 ohm 5 watt resistor to monitor current through the bridge. This is sensitive to within 50mA which is ok for the purpose of detecting overloads/shorts.

3. The TFT LCD display requires lower values on the voltage divider inputs (was 4k7 and 10k ohm), 1k0 and 1k5 ohm values work fine. The TFT is slow in response compared to response of turning the speed pot and recording on the display. The time lag gives incorrect values. I have included a special void in the Arduino sketch to transmit speed data only and change one line on the display instead of refreshing the whole display.

4. The DCC command signal timing has been improved by switching state of the output using binary register coding instead of digitalWrite(D10, High) e.g.
DDRB = B00000100; // register B for digital pin 8 to 13, pin 10 as an OUTPUT
PORTB = B00000100; // using register control to speed up switching speed pin 10 switched HIGH (DIR)
PORTB = B00000000; // pin 10 switched LOW (DIR)

5. The input keys on the membrane key pad are selected in void get_key() I have improved the response time taken in the void by using 'case' and 'return' rather than 'if' statements.

6. The NMRA standard requires a continuous flow of DCC data every 30 ms. This has been added to the sketch for speed and direction on all running locos (not for function controls which are only sent when keypad is pressed).

7. The DCC Command packet for 128 speed steps is 4 bytes long whereas the function Commands are 3 bytes long. I have included a means to assemble 4 or 3 byte packets by altering the length of the Message array:
void amend_len4 (struct Message & x) { x.len = 4; z = 4; }
void amend_len3 (struct Message & x) { x.len = 3; z = 3; }

8. On review of the power requirements of the Nano and LCD and the H-bridge voltage (12v to 14v) I have used a 9v regulator to supply the Vin pins of the Nanos and the input of the 3.3v regulator for the LCD. This gives optimum power dissipation on the regulators. The Arduino Nanos should not be relied upon to supply enough current to the LCD display from their 3v outputs.

9. A PCB design from Fritzing and manufacturing in China has enabled me to provide bare PCB's of the circuit included here. If you are interested purchasing one, please search e-bay for 'DCC Command Station PCB' (should be available during August 2018)

Step 1: Components:

All available on eBay:

4x4 Matrix Array 16 Key Membrane Switch Keypad £2
2.2 inch 240x320 Serial SPI TFT LCD Display Module £7
Nano V3.0 For Arduino with CH340G 5V 16M compatible ATmega328P 2 x £3.30 = £6.60

Motor Driver Module LMD18200T for Arduino R3 £7
*Voltage Regulators: 3v3 (UA78M33C) and 9v (7809) in TO220 packages £2

3v3 zener diode, 1N4004 rectifier diode, 1N5817 Schottky diode £0.50
Connectors, wire, vero board, resistors, potentiometer: approx £3
PCB (available on e-bay from Aug 2018) £5
Box / Enclosure

*Note: Voltage regulators will run at 23 degrees C above ambient and may require a require heatsink, depending on air circulation within enclosure. If Vsupply is 14v , then a temp rise of 36 degrees C above ambient on 9v Regulator will probably need a heat sink.

Step 2: Arduino Nano With Keypad

Make serial communications between the Nanos using Analog pins A3/A4:

#include "SoftwareSerial" // download this library
SoftwareSerial dcc(A3,A4); // RX TX

The 4x4 membrane keypad is configured in the sketch as follows:

#include "Keypad.h" // download this library

const byte ROWS = 4; //four rows const byte COLS = 4; //four columns
char keys[ROWS][COLS] = { {'1','2','3', 'A'}, {'4','5','6', 'B'}, {'7','8','9', 'C'}, {'*','0','#', 'D'} };
byte rowPins[ROWS] = {2,3,4,5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {6,7,8,11}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
char key = keypad.getKey();

void SetupTimer2()
This void starts the clock which is amended by the DCC binary code to provide a DCC signal.
Each of 4 byte of loco/speed commands:
byte 1 = loco number
byte 2 = speed steps
byte 3 = speed value / direction / front light on/off
byte 4 = checksum (error)

For function commands, 3 bytes:
byte 1 = loco number
byte 2 = function (F1 to F8) on/off
byte 3 = checksum (error)

A current sense resistor 0.1 ohm 5 watt monitors the current through the h-bridge.
The LMD18200t module used has a max current of 3 Amps
I have set the working limit to 2.6 Amps in the sketch:
void current(){
sensorValue = analogRead(AN_CURRENT);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V) = 4.9mv per division
// 0.1 ohm resistor on current sense gives 200mv at 2 Amps or, 100mv per Amp
// 100/4.9 = 20 divisions per Amp or 20 divisions per 1000mA or 1 division = 50mA
A = 50 * sensorValue ; // mA }

Within void setup() :
Amax = 2600; // max current

Within the void read_loco() :
if (A >= Amax){ // current limit
Atrig = 1;
changed_l = true;
return changed_l; }

The system can control 1 - 19 engines, direction, lights, 8 functions, emergency stop and auto current limit.
The max current of 2.6 amps makes it suitable for all scales including G-scale (garden trains). The mains power supply and electronics are suitable for indoor use only unless you can make it all weather proof. I have the command station in the summer house with rail connecting wires running out through the wall to the track.

Step 3: CV1 Loco Address

Holding the 'A' key down while turning on power, will provide access to the CV1 write feature.

This is achieved in the Arduino Nano sketch through a sequence of reset, page preset and write packets as specified in NMRA S-9.2.3

//CV1 coding for Address only mode

void cv1_prog(){
4 x (preamble (16 x '1') plus reset_packet) // 3 or more required
6 x (preamble (16 x '1') plus page_preset_packet) // 5 or more required
7 x (preamble (16 x '1') plus reset_packet) // 6 or more required
6 x (long preamble (24 x '1') plus cv1_write_packet() // 5 or more required
11 x (long preamble (24 x '1') plus cv1_write_packet() // 10 or more required

void reset_packet()
Creates 'preamble' of 2 bytes of (8 x '1') followed by 3 bytes of '0'

void page_preset_packet()
Creates 'preamble' of 2 bytes of (8 x '1') followed by 3 bytes 01111101 00000001 01111100

void cv1_write_packet()
Creates 'long preamble' of 3 bytes of (8 x '1') followed by 3 bytes 0111C000 0DDDDDDD EEEEEEEE
C=1 write address used here (C=0 verify address)
Value of DDDDDDD is written into CV1
The decoder must be powered off after each CV1 write and switched on again prior to another CV1 write.
This is done by switching the pins on the h-bridge:
Turn ON : PWM = High : Brake = Low. Turn OFF : PWM = Low : Brake = HIGH
To sense the smaller currents, Analog Internal Ref is used during CV1 write
1.1v ref gives 1.08 mv per division, current Acv = 10.8 X sensor value using 0.1 ohm sense resistor
If Acv > 15mA then a valid CV1 write is achieved.

Step 4: Arduino Nano With TFT LCD Display

The Nano used to control the TFT display is configured as follows:

#include "SoftwareSerial.h"
SoftwareSerial dcc(A3,A4); // RX TX

#include "Adafruit_GFX_AS.h" // Core graphics library
#include "Adafruit_ILI9341_AS.h" // Hardware-specific library
#include "SPI.h"

// hardware SPI pins for Nano
#define _sck 13 // D13
#define _mosi 11 //D11
#define _cs 10 //D10
#define _dc_rs 9 //D9
#define _reset 7 //D7

Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(_cs, _dc_rs, _reset);
A valid command received from the Nano with keypad must start with 'A', end with '\n' and have 18 ',' characters.
Each valid command is decoded and the result displayed.



    • Fix It! Contest

      Fix It! Contest
    • Water Contest

      Water Contest
    • Tiny Home Contest

      Tiny Home Contest

    2 Discussions

    Simon, I have repeated the DCC signal to ensure continuous operation when locos have intermittent track connections. When CV11 is set to zero the loco does not respond to time outs. When set, it is usually in terms of seconds, I believe, rather than within 30mS. Thanks for your input.