Arduino - Points/turnout/accessory Control




Update 26 January 2019: I have added a third sketch above with all 8 output pairs set to be momentary

See: DCC_turnout_control_t1_t8_all_momentary.ino

Updated 19 December 2018: changed Arduino sketch - removed conflict in output logic.

Updated 21 October 2018: New section added to include control of Tortoise slow motion points / turnouts

Updated 18 October 2018: To include accessory control.

Updated 17 September 2018:

Amended Arduino sketch to cure bug whereby multiple switching of points / turnouts occurred.
See new sketch attached in step 2.

Updated 18 August 2018:

I now have a PCB designed for this application - available from eBay during 2018.
An Arduino Nano module provides 8 turnouts and if more are required, you will need to add more modules or use a larger Arduino (Mega perhaps).

Step 1: Arduino Sketch

Update 26 January 2019: I have added a third sketch above with all 8 output pairs set to be momentary
See: DCC_turnout_control_t1_t8_all_momentary.ino

Update 17 September 2018:
Amended sketch to stop multiple switching by trapping the first DCC message and only responding when a new turnout value is activated.
int state;
int last_state;
int last_tun = 0;

state = (Msg->Data[1] & 0x01);
if (last_tun == tun && last_state == state) return;
last_tun = tun; last_state = state;
Note: There are 2 Arduino Nano sketches, one for turnouts T1-T8 and another for T5-T8.

From an excellent tutorial by Geoff Bunza in the Model Railroad Hobbyist Magazine forum. It described how an Arduino Pro Mini (a low cost Arduino board) could be wired and programmed to respond to function keys on a DCC controller. This opens up a wide world of control options for animations, sound and other options on a DCC equipped model railroad.

I have made use of this circuit to capture DCC packets from my Arduino based Command Station
(see DCC Command Station). The Command station may control up to 16 turnouts.

Basic Accessory decoder packet is :

From analysing the packet used by Lenz (Compact / Atlas) for points control, I have used the following binary packet format for bytes 1 and 2 :
tunAddr = 1 //Accessory decoder address
Turnout 1a : 1000 0001 1111 1000 / Turnout 1b : 1000 0001 1111 1001
Turnout 2a : 1000 0001 1111 1010 / Turnout 2b : 1000 0001 1111 1011
Turnout 3a : 1000 0001 1111 1100 / Turnout 3b : 1000 0001 1111 1101
Turnout 4a : 1000 0001 1111 1110 / Turnout 4b : 1000 0001 1111 1111

tunAddr = 2
Turnout 5a : 1000 0010 1111 1000 / Turnout 5b : 1000 0010 1111 1001
Turnout 6a : 1000 0010 1111 1010 / Turnout 6b : 1000 0010 1111 1011
Turnout 7a : 1000 0010 1111 1100 / Turnout 7b : 1000 0010 1111 1101
Turnout 8a : 1000 0010 1111 1110 / Turnout 8b : 1000 0010 1111 1111

tunAddr = 3
Turnout 9a : 1000 0011 1111 1000 / Turnout 9b : 1000 0011 1111 1001

etc .........

By manipulation of the binary packet, we can extract the turnouts required and send a pulse of 250 ms.

looking at first byte:

0x80 in HEX = 1000 0000 in Binary

tunAddr = (Msg->Data[0] - 0x80);

looking at second byte:

0xf8 in HEX = 1111 1000 in Binary, then shift bitwise >>1 to eliminate last bit

f1a on:

if (tunAddr == 1){
   if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 1){ 
digitalWrite(FunctionPin1a, 1); //pin 3 to '1'
digitalWrite(FunctionPin1a, 0); //pin 3 to '0' }

The diagram includes SN754410 Quad driver (supplies 2 turnouts per IC).

All digital outputs are used in pairs to produce a pulse that fires the turnout solenoids via motor drivers or power darlington transistors. The code may be changed to match the drivers used from a '1' pulse to a '0' pulse.

Download NMRA library NMRA Version 1.2.2
Note: Later versions of NMRA library do not work on Mac OS 10.13.6

Step 2: Turnout Control - Components

Bill of Materials:
All components including PCB are available from eBay.

1 off PCB eBay link

4 off Ceramic Capacitor voltage 6.3V; capacitance 100 nF; package 200 mil

1 off Capacitor Polarized variant pth1; package cpol-radial-100uf-25v

1 off 10kΩ Resistor bands 5; tolerance ±5%; pin spacing 400 mil;

2 off Screw terminal - 2 pins pins 2; hole size 1.0mm,0.508mm; pin spacing 0.197in (5.0mm);

1 off 1kΩ Resistor bands 5; tolerance ±5%; pin spacing 400 mil;

1 off 1.5kΩ Resistor bands 5; tolerance ±5%; pin spacing 400 mil;

1 off Diode variant 1n4148;

1 off Ceramic Capacitor voltage 6.3V; capacitance 100 nF; package 100 mil

8 off Screw terminal - 3 pins pins 3; hole size 1.0mm,0.508mm; pin spacing 0.137in (3.5mm);

1 off 4.7kΩ Resistor bands 5; tolerance ±5%; pin spacing 400 mil;

1 off 5v reg Voltage Switching Regulator RECOM 5v 500mA;

1 off 0.47Ω Resistor bands 5; tolerance ±5%; pin spacing 400 mil;

1 off 6N137 IC chip label IC; pins 8; hole size 1.0mm,0.508mm; true; pin spacing 300mil; package DIP

2 off Generic female header - 15 pins; hole size 1.0mm,0.508mm; pin spacing 0.1in (2.54mm);; row single

17 off Diode variant pth; package diode-1n4001

4 off H-Bridge SN754410

1 off TIP120 NPN power transistor ; package TO220

1 off Arduino Nano module (5v)

Step 3: Current Limit Control

Current sense circuit to protect turnout coils and H-bridge devices etc from over current.

int analogPin = 7;

const int Power_shut_off = 19; // A5 as digital

pinMode(Power_shut_off, OUTPUT);

digitalWrite(Power_shut_off, HIGH);

In void loop():

amp = analogRead(analogPin);

if (amp > 5){

Serial.println(amp); }

if (amp > 200 ){ // approx 2 amps

digitalWrite(Power_shut_off, LOW); }

When 2 amps is exceeded, the TIP 120 shuts off the power (12 volt or 15 volt supply) to the turnouts.


Step 4: Accessory Control

The Arduino sketch may be modified to include on/off switching or timed switching for control of lights, signals, etc. The SN544110 h-bridge can supply at least 250mA per output.
Alter the code for the output pin required to be on or off, for example for f1a (pin3) and f1b (pin 4) to control a signal light with 2 colours:
if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 1){ // f1a on
digitalWrite(FunctionPin1a, 1); // signal light red
digitalWrite(FunctionPin1b, 0);

if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 0){ // f1a off
digitalWrite(FunctionPin1a, 0);
digitalWrite(FunctionPin1b, 1); // signal light green

The signal common wire is connected to the middle pin of connector f1a / f1b.
Remember, turnout / point motors are designed to activate on momentary applied voltage for around 250 milli-seconds. Always be careful NOT to connect a turnout / point motor to this on / off pin as it will over heat and probably burn out.

Step 5: Tortoise Points/turnouts

The Arduino sketch may be modified to operate Tortoise slow motion motorised points.
The DC power connections are made to f1a and f1b (or any other output required)
The common middle pin connection is not required.

Alter the code for the output pin required to be on or off,
for example for f1a (pin3) and f1b (pin 4):
if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 1){
digitalWrite(FunctionPin1a, 1); // motor on
digitalWrite(FunctionPin1b, 0); }

if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 0){
digitalWrite(FunctionPin1a, 0);
digitalWrite(FunctionPin1b, 1); // motor on (reversed)

If the stall current is <100 mA, there is no need to switch the motor off.
If required, simply add a delay of around 3 seconds to ensure full motion of the points is completed before turning off.

if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 1){
digitalWrite(FunctionPin1a, 1); // motor on
digitalWrite(FunctionPin1b, 0);
delay (3000);
digitalWrite(FunctionPin1a, 0); } // motor off

if ((((Msg->Data[1]) - 0xf8>>1) + 1) == 1 && (Msg->Data[1] & 0x01) == 0){
digitalWrite(FunctionPin1a, 0);
digitalWrite(FunctionPin1b, 1); // motor on (reversed)
delay (3000);
digitalWrite(FunctionPin1b, 0); } // motor off



    • Pie Contest

      Pie Contest
    • Remix Contest

      Remix Contest
    • Tape Contest

      Tape Contest

    13 Discussions


    Question 7 days ago on Introduction

    Hi Bill, first of all, let me thank you for your work. I joined "Instructables" today, partly to have access to your work and partly for the great wealth of Arduino information represented here. This brings me to my question/s. I am not able to download the PDF, does that take some time before I am approved? Second, I am inspired by DCC++ to control my trains and turnouts. The train part is working well but, the learning curve is very rough with respect to setting up RPi and Arduino pin/output identification. I am hopping your work will help me through this process. Again, thanks for your work, looking forward to hearing from you. Bill

    3 answers

    Answer 6 days ago

    Hi Bill,
    The pdf download requires you to have a premium membership. You should be able to download the individual files.
    If you are controlling solenoid turnouts for all outputs then you must use the code for all momentary outputs - this sketch is included in above for T1 - T8.
    Please let me know if you require a sketch for T9 -T16 for all momentary turnouts also. I could send it directly to you if required.


    Reply 6 days ago

    Bill, thank you for your reply. I think I may have gotten myself in over my head, I am subject to doing that. Let me make the following comments then please feel free to advise me to go back to square one and start over. First, I did join Instructables by signing up for the second option. The 4.95 quarterly seemed to fit my need best at this time. And, did receive the "welcome to instructables" email. That took place about 24 hours ago. Second, my goal was to build a stand alone DCC++ system using a Raspberry Pi. and an Arduino Mega, running the system designed by Geoff Bunza. I became very confused by how to address i/o pins on the arduino through JMRI which is running on a connected Pi. Having said that, my final goal is to use your boards to control a number (12) solenoid momentary outputs with an arduino via JMRI. However, the deeper I travel into this forest the more I feel momentary switches may be the best (and easiest) solution. Thank you again for your help and please feel wrong in telling me to rethink this journey.


    Reply 6 days ago

    Hi Bill, I have JMRI running on my Mac with a USB connected Sprog device. This supplies DCC power and instruction packets to the rails. The Arduino based turnout control board is connected across the rails (DCC output) which then decodes the DCC packets and operates each set of turnouts.
    This is the same setup for use with any other Command Station. The input ('Track DCC' on the PCB) is connected to the DCC rails.
    I am not sure if I have helped you with this reply.
    Please try again if I can be of assistance.


    6 days ago

    Hi Bill,
    I did order 2 of your boards.
    I want to control 16 switches.
    How do I modify the code to get there.
    It is not obvious to me how to change it.
    Thank you!

    1 reply

    Reply 6 days ago

    Hi Jay, thanks for buying 2 boards. Do you want to have ON/OFF switches ? If so, I can send you an Arduino sketch with the correct coding. If you are controlling solenoid turnouts, then you must use the momentary switching. Either way, I can provide the code for 1 to 8 and another sketch for 9 to 16. I shall email you directly with these files if you wish.


    1 year ago

    Hi! Great project! I was wondering if using an Arduino 16 Relay board could be used. That would simplify things considerably as an Arduino can drive the relays directly. I need to drive at least 16 solenoid switches. An Arduino Mega 2560 has enough digital pins on the end header to do the job. Question, which pin does the DCC Signal com in? D2?

    4 replies

    Reply 1 year ago

    Hi jay

    Thanks for your interest in this project. You could use the 16 relay boards in this circuit. I think you would need 2 relays per railway point giving 8 points served from one board. If you have the space to use these then fine. Remember to add diodes across all solenoid contacts to protect against induction spikes.

    Yes, D2 has the DCC signal input from the packet receiver circuit.

    Good luck and enjoy the project.


    Reply 1 year ago

    Hi Bill
    The relay board I am using is opto-isolated.
    I have modified the code mapped the outputs to 22 - 53.
    I also removed the current monitoring as it will not be needed.
    My command station is DCC++.
    It goes to the DCC circuit. That feeds pin 2.
    I am using JMRI to test it.
    Nothing is happening.
    I tested the connection from the Mega to the board with a custom sketch. It hits each relay, in order, for 150ms.
    Any ideas?
    Thanks!! Jay


    Reply 1 year ago

    Hi jay,

    First thing to check is the Arduino serial monitor for the decoded values.

    You should get burst of code printed on the monitor ending with:

    tun = turnout number

    If you want to send me an email directly, please use

    You can send me more detail if required e.g. circuit diagram, code etc


    Reply 1 year ago

    I will be using this board.
    It takes a 5v logic signal to drive the relays. It has the driver chips on it.
    I am using DCC++ for my DCC System. It doesn't appear that it is sending switch packets. That's another issue I am working on now.
    Thank you!!


    2 years ago

    Bill, great Instructable! I wondered if you could share which points you're using? I'm using Hornby R8243 surface mounted point motors, and my sn754410s are struggling to supply enough current. Whilst the point motor switches definitely off-load, when under load (i.e. attached to points), whilst there is movement, it just does not seem to meet the instantaneous current requirements needed to be fully switched in either direction. I have even tried piggybacking the sn754410s and even then, switching is only successful in one direction of travel. I had wondered if you are using points with a high resistance/impedance?

    1 reply

    Reply 2 years ago

    Hi Simo, glad you like this Instructable. I used Hornby R8014 points motors (not surface mount) but should operate with same voltage and current. Please check the Vcc2 power supply which must be about 15 volts and capable of supplying peak current of at least 1 amp. Do your point motors operate of the track ok i.e. in free air movement? Please check alignment and freedom of movement of lever to points. You may have to adjust the timing in the Arduino sketch. I have 150 to 250 milliseconds on time delay (250);