Arduino DCC Function Decoder
Revised  10-07-14
click here for new software

A video is on YouTube here:
https://www.youtube.com/watch?v=WWlZJH2KPUQ


A video with the newest software is here:
http://youtu.be/oI-NjCDbUXo
 

You may have noted that I used a source of external power (a cell phone battery) to power the servos in the video.  I did that as the system was shutting down when I tried to operate two or three servos.  It turns out that the problem was not with the circuit or the servos but with the DCC system that I was using for testing.  It is composed of a laptop running JMRI and a SPROG II controller. 
 

The SPROG was the problem*.  It must have a very sensitive shutdown circuit that detected too much power being drawn.  When I tried 3 servos using the board's power supply with another DCC system and with the SPROG II and a 3 amp DCC booster it worked perfectly.

*I found this note in the user manual:
SPROG II will remove track power if output current exceeds 250mA as measured 100ms after applying power.
 

 

Introduction
Recently I have been experimenting with building DCC controllers and decoders based on Arduino microcontrollers.  My notes on these projects are here Arduino DCC Decoder and here
Arduino DCC Controller.

After hand wiring several of the DCC decoders I decided that a circuit board would make things much more convenient for me and other hobbyists.  I designed a board that would provide these features:

  • The decoder would connect to up to three servos
  • The servos can be powered by DCC power or by an external 5 volt power source
  • A 5 volt Double Pole Double Throw relay can be mounted on the board
  • Two small breadboard areas are on the board
  • Two different bridge rectifier styles can be used
  • All of the Arduino pins are brought out onto the board
  • accommodations are made for more filtering than may be needed
Schematic
The DCC power goes to the optocoupler via a 1K resistor and to the 7805 voltage regulator.  The 5 volt output from the 7805 if filtered before it goes to the optocoupler and Arduino.  More filtration options than may be necessary are provided.  My tests have had the board working reliably with D2 and C5 omitted.  I also used 4.7 uf Tantalum caps for C1 as they do an excellent job of cleaning up the DC.

There is an "X" on the back of the circuit board (shown below).  If you want to provide a supplementary soruce of 5 volts to operate the servos cut the trace and supply the power to the two pins marked "alt 5v".  I have had problems with the unit resetting itself when I ran two or three servos from the on-board power supply.  Cutting the trace and adding an external power connection cleared everything up.

The relay is a DPDT, 5 volt relay.  It is turned on and off through pin A0.  The three servos are connected to pins A1, A2 and A3 on the Arduino.

 

Circuit Board
The Gerber files for this board are here:
DCC_Decoder_Board.zip
The board was designed using FreePCB - the fpc file is included in the ZIP file.

The top of the circuit board is silk screened to show where to install components. 

The back of the board is shown here:

You can install either of two bridge rectifier styles - this photo shows both on the board - you only need ONE of them, either the small through hole unit in the lower left or the round one with long leads above it.

If you don't have either of the suggested bridge rectifiers you can easily make your own with four 1 amp diodes (1N4007 or similar) as shown here.  Take care to align the bands as shown.

Cut off every other lead.

Insert in the circuit board as shown.

The servos are normally powered from the 7805 voltage regulator on the board.  If you are using large servos more power may be needed for them.  To use an external source of 5 volts cut the trace shown here.

External power for the servos (5 volts, only!) is applied to the two terminals circled in yellow.  Positive on the right and negative on the left.

 

There is also a set of holes under the Arduino that can be used for additional filtering.  An electrolytic or non-electrolytic cap can be added there if needed.  The holes are circled in yellow in this photo.  Note that the hole on the right is positive should you use an electrolytic cap.

Software DCC_3_Servos_1_Relay_v4  9-26-14 
This version moves as many as three servos and controls one relay
Servo A3 - Pressing F1 moves to Clockwise extreme, Pressing F4 modes to Counterclockwise extreme
Servo A2 - Pressing F2 moves to Clockwise extreme, Pressing F5 modes to Counterclockwise extreme
Servo A1 - Pressing F3 moves to Clockwise extreme, Pressing F6 modes to Counterclockwise extreme
Relay - toggle with F11
/*
Ver 4 - working well with variables preset to 0 and 160
 next step it to try to change variables with other fn keys
 
 3 servos / 1 relay
 use the following to operate servos from DCC controller keypad
 F1 & F4 operate Servo 3
 F2 & F5 operate Servo 2
 F3 & F6 operate Servo 1
 toggle relay with F11
 */

#include <NmraDcc.h>
#include <SoftwareSerial.h>
//for serial port on USB
byte rxPin = 0;
byte txPin = 1;
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
// Working 14 Function DCC Decoder  DccAckPin not needed
int tim_delay = 500;
#define numleds  16  //using 17th as servo control pin (A3)
#include <Servo.h> 

Servo myservo;  // create servo object to control a servo 
// a maximum of eight servo objects can be created 
Servo myservo2;
Servo myservo3;
int pos1=90;    // variables to store the servo position 
int pos2=90;
int pos3=90;
int pos1CW = 10;    // variables to store Clockwise & Counter Clockwise positions
int pos1CCW = 160;   //  for all three servos
int pos2CW = 10;
int pos2CCW = 160;
int pos3CW = 10;
int pos3CCW = 160;

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;
const int FunctionPin2 = 5;
const int FunctionPin3 = 6;
const int FunctionPin4 = 7;

const int FunctionPin5 = 8;
const int FunctionPin6 = 9;
const int FunctionPin7 = 10;
const int FunctionPin8 = 11;

const int FunctionPin9 = 12;
const int FunctionPin10 = 13;
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 17

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()
{
  // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset 
  // to flag to the loop() function that a reset to Factory Defaults needs to be done
  FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
};
void setup()
{
  myservo.attach(A3);  // attaches the servo on pin A3 to the servo object 
  myservo2.attach(A2);
  myservo3.attach(A1);
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  mySerial.begin(9600);
  mySerial.println("DCC_3_Servos_1_Relay_v4  9-26-14 ");
  // initialize the digital pins as an outputs
  for (int i=1; i<= numleds; i++) {
    pinMode(ledpins[i], OUTPUT);
    digitalWrite(ledpins[i], LOW);
  }
  for (int i=1; i<= numleds; i++) {
    digitalWrite(ledpins[i], HIGH);
    //   delay (tim_delay/10);
  }
  delay( tim_delay);
  for (int i=1; i<= numleds; i++) {
    digitalWrite(ledpins[i], LOW);
    //  delay (tim_delay/10);
  }
  //  delay( tim_delay);

  // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up 
  Dcc.pin(0, 2, 0);
  // Call the main DCC Init function to enable the DCC Receiver
  Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
}
void loop()
{
  // myservo.write(pos1); 
  // myservo2.write(pos2);
  // myservo3.write(pos3);
  // delay (15);
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  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 );
    }
  }

  //Servo @A3 if F1 is pressed, servo to CW extreme
  if (digitalRead(4)==1){
    pos1=pos1CW;   
    myservo.write(pos1); 
  }
  //Servo  @A3 - if F4 is pressed, servo to CCW extreme
  if (digitalRead(7)==1){
    pos1=pos1CCW;
    myservo.write(pos1);   
  } 
  //Servo @A2 - if F2 is pressed, servo to CW extreme
  if (digitalRead(5)==1){
    pos2=pos2CW;
    myservo2.write(pos2);
  }
  //Servo @A2- if F5 is pressed, servo to CCW extreme
  if (digitalRead(8)==1){
    pos2=pos2CCW;
    myservo2.write(pos2);
  }
  //Servo @A1 - if F3 is pressed, servo to CW extreme
  if (digitalRead(6)==1){
    pos3=pos3CW;
    myservo3.write(pos3);
  }
  //Servo @A1- if F6 is pressed, servo to CCW extreme
  if (digitalRead(9)==1){
    pos3=pos3CCW;
    myservo3.write(pos3);
  }
}  
Notes on New Software (below)
The following function buttons on the DCC Throttle are used:
  • Servo A3 - Pressing F1 moves to Clockwise extreme, Pressing F2 modes to Counterclockwise extreme
  • Servo A2 - Pressing F3 moves to Clockwise extreme, Pressing F4 modes to Counterclockwise extreme
  • Servo A1 - Pressing F5 moves to Clockwise extreme, Pressing F6 modes to Counterclockwise extreme
  • On all of these function buttons make sure you hit it twice to release the button as most such controllers latch function control buttons
  •  
  • Adjust the Clockwise & Counterclockwise positions as follows:
    • Select one of the three servos by pressing F1 or F2 for Serv0 A3, F3 or F4 for Servo A1 or F5 or F6 for Servo A1
  • Once the servo to be adjusted has been selected the following will adjust its position
    • Press F7 to decrease the Clockwise setting (moves it more counterclockwise)
    • Press F8 to increase the Clockwise setting (moves it more clockwise)
    • Press F9 to increase the Counterclockwise setting (moves it more clockwise)
    • Press F10 to decrease the Counterclockwise setting (moves it more counterclockwise)
  • For all of the above you may need to hit the function button twice as most buttons latch. 
    BE SURE NOT TO LEAVE A BUTTON LATCHED as it will adversely effect movements.
Updated Software -- allows adjustment of extremes with DCC commands from throttle
/*  d. bodnar 10-7-14  filename:  DCC_3_Servos_1_Relay_adjustServo_v11_array
 3 servos / 1 relay - saves setting when shut down
 ------------- EEPROM read/write if you don't use final item (ie buffer above 1 item)
 use the following to operate servos from DCC controller keypad
 F1 & F4 operate Servo 3
 F2 & F5 operate Servo 2
 F3 & F6 operate Servo 1
 toggle relay with F11
 F7, F8, F9, F10 adjust settings of LAST SERVO ACCESSED
 BE CAREFUL with parenthesis on   mySerial.println((FuncState&0x04) >> 1, BIN); or it will not work as expected!
 */
#include <EEPROM.h>
#include <NmraDcc.h>
#include <SoftwareSerial.h>
//for serial port on USB
byte rxPin = 0;
byte txPin = 1;
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
// Working 14 Function DCC Decoder  DccAckPin not needed
int tim_delay = 500;
#define numleds  23  //using 17th as servo control pin (A3)
#include <Servo.h> 
int xx=0;
Servo myservo1;  // create servo object to control a servo 
// a maximum of eight servo objects can be created 
Servo myservo2;
Servo myservo3;
int pos1=90;    // variables to store the servo position 
int pos2=90;
int pos3=90;
int posCW[4] = {   // go to 4 rather than 3 so we can skip the "0" item in array 
  11,12,13,14};    // and count from 1 to 3
int posCCW[4] = {
  151,152,153,154};

int cwmin = 10;
int ccwmax = 160;
int cw1=0;   // these variables are flags to see which servo direction was used last
int ccw1=0;   // so that the adjustment function keys operate on the last servo direction used
int cw2=0;
int ccw2=0;
int cw3=0;
int ccw3=0;
int lastUsed=1;  // last servo used (1, 2 or 3)
int servoStep = 1;
int writeMemFlag = 0; // =1 if eeprom needs updated
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;   // SERVO A3cw
const int FunctionPin2 = 5;   // SERVO A3ccw
const int FunctionPin3 = 6;   // SERVO A2cw
const int FunctionPin4 = 7;   // SERVO A2ccw

const int FunctionPin5 = 8;   // SERVO A1cw
const int FunctionPin6 = 9;   // SERVO A1ccw
const int FunctionPin7 = 10;  //SERVO adjust 
const int FunctionPin8 = 11;  //SERVO adjust 

const int FunctionPin9 = 12;  //SERVO adjust 
const int FunctionPin10 = 13; //SERVO adjust 
const int FunctionPin11 = 14;     //A0   // RELAY
const int FunctionPin12 = 15;     //A1   // SERVO

const int FunctionPin13 = 16;     //A2   // SERVO
const int FunctionPin14 = 17;     //A3   // SERVO
const int FunctionPin15 = 18;     //A4   //Servo A1 last active LED //BOTH = A3 last active //RED
const int FunctionPin16 = 19;     //A5   //Servo A2 last active LED  //GREEN
int LEDa4=A4;  //red
int LEDa5=A5;  //green
NmraDcc  Dcc ;
DCC_MSG  Packet ;

#define This_Decoder_Address 17

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()
{
  // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset 
  // to flag to the loop() function that a reset to Factory Defaults needs to be done
  FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
};
void setup()
{
  // sets extremes to cwmin and ccwmax on first run only
  if (EEPROM.read(98)!= 98){
    posCW[1]=10;
    posCCW[1]=160;
    posCW[2]=10;
    posCCW[2]=160;
    posCW[3]=10;
    posCCW[3]=160;
    EEPROM.write(98,98);
    EEPROM.write(2,posCW[1]); 
    EEPROM.write(3,posCCW[1]); 
    EEPROM.write(4,posCW[2]); 
    EEPROM.write(5,posCCW[2]); 
    EEPROM.write(6,posCW[3]); 
    EEPROM.write(7,posCCW[3]); 
    EEPROM.write(9,posCCW[3]); 
    EEPROM.write(11,123);
  }  

  myservo1.attach(A3);  // attaches the servo on pin A3 to the servo object 
  myservo2.attach(A2);
  myservo3.attach(A1);

  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(LEDa5, OUTPUT);
  pinMode(LEDa4, OUTPUT);
  // Remove comment from next line to debug - servos WILL be jittery if removed
  // mySerial.begin(9600);
  mySerial.println("DCC_3_Servos_1_Relay_adjustServo_v11  10-07-14 ");

  for(int xx=2; xx<9;xx++){
    mySerial.print(xx,DEC);
    mySerial.print("\t");
    mySerial.println(EEPROM.read(xx));
  } 
  // will NOT allow writing to position 1 or it crashes - go figure!
  //  also strange on read item 7, sometimes returns 100 rather than set value!
  //     the extra reads above 7 seems to help

  posCW[1]  = EEPROM.read(2); 
  posCCW[1] = EEPROM.read(3); 
  posCW[2]  = EEPROM.read(4); 
  posCCW[2] = EEPROM.read(5); 
  posCW[3]  = EEPROM.read(6); 
  posCCW[3] = EEPROM.read(9); 
  int xyx  = EEPROM.read(8); 
  int xyxx  = EEPROM.read(11); 
  mySerial.println(xyxx,DEC);

  // set servos to counterclockwise settings on initialization
  myservo1.write(posCCW[1]); 
  myservo2.write(posCCW[2]); 
  myservo3.write(posCCW[3]); 
    // initialize the digital pins as an outputs
   for (int i=1; i<= numleds; i++) {
   pinMode(ledpins[i], OUTPUT);
   digitalWrite(ledpins[i], LOW);
   }
   for (int i=1; i<= numleds; i++) {
   digitalWrite(ledpins[i], HIGH);
   }
   delay( tim_delay);
   for (int i=1; i<= numleds; i++) {
   digitalWrite(ledpins[i], LOW);
   }
  

  // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up 
  Dcc.pin(0, 2, 0);
  // Call the main DCC Init function to enable the DCC Receiver
  Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
}
void loop()
{
  if (writeMemFlag==1){
    if (EEPROM.read(2)!=posCW[1]){
      EEPROM.write(2,posCW[1]); 
    }
    if (EEPROM.read(3)!=posCCW[1]){
      EEPROM.write(3,posCCW[1]); 
    }
    if (EEPROM.read(4)!=posCW[2]){
      EEPROM.write(4,posCW[2]); 
    }
    if (EEPROM.read(5)!=posCCW[2]){
      EEPROM.write(5,posCCW[2]); 
    }
    if (EEPROM.read(6)!=posCW[3]){
      EEPROM.write(6,posCW[3]); 
    }
    if (EEPROM.read(7)!=posCCW[3]){
      EEPROM.write(7,posCCW[3]); 
    }
    if (EEPROM.read(9)!=posCW[3]){
      EEPROM.write(9,posCCW[3]); 
    }

    EEPROM.write(11,123);

    writeMemFlag=0;   
    mySerial.print("CCW3 ");
    mySerial.println(posCCW[3]); 
    mySerial.println("written!");

  }
  if (lastUsed==1){
    digitalWrite(LEDa5, LOW);
    digitalWrite(LEDa4, HIGH);
  }
  if (lastUsed==3){
    digitalWrite(LEDa4, LOW);
    digitalWrite(LEDa5, HIGH);
  }
  if (lastUsed==2){
    digitalWrite(LEDa5, HIGH);
    digitalWrite(LEDa4, HIGH);
  }
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  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 ); //16
    digitalWrite( FunctionPin1, (FuncState&0x01 ));    //1
    digitalWrite( FunctionPin2, (FuncState&0x02)>>1 ); //2
    digitalWrite( FunctionPin3, (FuncState&0x04)>>2 ); //4
    digitalWrite( FunctionPin4, (FuncState&0x08)>>3 ); //pin 7 //8
  }
  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 )); //17 (16+1)
      digitalWrite( FunctionPin6, (FuncState&0x02)>>1 ); //18 (16+2)
      digitalWrite( FunctionPin7, (FuncState&0x04)>>2 ); //20 (16+4)
      digitalWrite( FunctionPin8, (FuncState&0x08)>>3 ); //pin11 //24 (16+8)
      /* sensVal = max(senVal, 20); // assigns sensVal to the larger of sensVal or 20
       (effectively ensuring that it is at least 20)
       sensVal = min(sensVal, 100); // assigns sensVal to the smaller of sensVal or 100
       ensuring that it never gets above 100.*/

      //F7 makes either the CW or the CCW position larger to either the max (160) or the other value 
      if ((FuncState&0x04)>>2){   //F7
        posCW[lastUsed] = min(posCW[lastUsed] +servoStep, ccwmax ); //was pos1 --- smaller of pos1CW+10 and pos1CCW(160) - really sets 160 as max
        posCW[lastUsed] = min(posCW[lastUsed], posCCW[lastUsed]);// can't go beyond current setting
        if (lastUsed==1){
          myservo1.write(posCW[1]); 
        }
        else if(lastUsed==2){
          myservo2.write(posCW[2]); 
        }
        else {
          myservo3.write(posCW[3]); 
        } 
        writeMemFlag=1;
        showCWmCCW();
      }
      //F8 makes either the CW or the CCW position smaller to either the min (10) or the other value 
      if ((FuncState&0x08)>>3){  //F8
        posCW[lastUsed]=max(posCW[lastUsed] -servoStep,cwmin); //was pos1--- larger of pos1CW-10 and pos1(variable) - really sets  pos1 as min
        posCW[lastUsed]= max(posCW[lastUsed], cwmin);
        if (lastUsed==1){
          myservo1.write(posCW[1]); 
        }
        else if(lastUsed==2){
          myservo2.write(posCW[2]); 
        }
        else {
          myservo3.write(posCW[3]); 
        }
        writeMemFlag=1;
        showCWmCCW();
      }    
    }
    else {
      digitalWrite( FunctionPin9, (FuncState&0x01 )); //1
      digitalWrite( FunctionPin10, (FuncState&0x02)>>1 ); //2
      digitalWrite( FunctionPin11, (FuncState&0x04)>>2 ); //4
      digitalWrite( FunctionPin12, (FuncState&0x08)>>3 ); //pin15 //8
      if (FuncState&0x01){  //F9
        posCCW[lastUsed] = min(posCCW[lastUsed] + servoStep, ccwmax); 
        posCCW[lastUsed]= min(posCCW[lastUsed], ccwmax);
        showCWmCCW();
        if (lastUsed==1){
          myservo1.write(posCCW[1]); 
        }
        else if(lastUsed==2){
          myservo2.write(posCCW[2]); 
        }
        else {
          myservo3.write(posCCW[3]); 
        }
        writeMemFlag=1;
      }
      if ((FuncState&0x02)>>1){  //F10
        posCCW[lastUsed]=max(posCCW[lastUsed] -servoStep,cwmin); 
        posCCW[lastUsed]= max(posCCW[lastUsed], posCW[lastUsed]);
        showCWmCCW();
        if (lastUsed==1){
          myservo1.write(posCCW[1]); 
        }
        else if(lastUsed==2){
          myservo2.write(posCCW[2]); 
        }
        else {
          myservo3.write(posCCW[3]); 
        }
        writeMemFlag=1;
      }
    }
  }
  else if (FuncNum==3) {  //Function Group 2 FuncState == F20-F13 Function Control
    digitalWrite( FunctionPin13, (FuncState&0x01 )); //1
    digitalWrite( FunctionPin14, (FuncState&0x02)>>1 ); //2
  }
  //Servo @A3 if F1 is pressed, servo to CW extreme
  if (digitalRead(4)==1){
    lastUsed=1;
    pos1=posCW[1];   
    myservo1.write(pos1); 
    cw1=1;
    ccw1=0;
    //    showCWmCCW();
  }
  //Servo  @A3 - if F2 is pressed, servo to CCW extreme
  if (digitalRead(5)==1){
    lastUsed=1;
    pos1=posCCW[1];
    myservo1.write(pos1);   
    cw1=0;
    ccw1=1;
    //    showCWmCCW();  
  } 
  //Servo @A2 - if F3 is pressed, servo to CW extreme
  if (digitalRead(6)==1){
    lastUsed=2;
    pos2=posCW[2];
    myservo2.write(pos2);
    cw2=1;
    ccw2=0;
    //    showCWmCCW();
  }
  //Servo @A2- if F4 is pressed, servo to CCW extreme
  if (digitalRead(7)==1){
    lastUsed=2;
    pos2=posCCW[2];
    myservo2.write(pos2);
    cw2=0;
    ccw2=1;
    //    showCWmCCW();
  }
  //Servo @A1 - if F5 is pressed, servo to CW extreme
  if (digitalRead(8)==1){
    lastUsed=3;
    pos3=posCW[3];
    myservo3.write(pos3);
    cw3=1;
    ccw3=0;
    //    showCWmCCW();
  }
  //Servo @A1- if F6 is pressed, servo to CCW extreme
  if (digitalRead(9)==1){
    lastUsed=3;
    pos3=posCCW[3];
    myservo3.write(pos3);
    cw3=0;
    ccw3=1;
    //    showCWmCCW();
  }
}  

int showCWmCCW(){
  //  mySerial.print("last pos1 CW 1-3 & CCW 1-3 ");
  //  mySerial.print(lastUsed,DEC);
  //  mySerial.print("  ");
  //  mySerial.print(pos1,DEC);
  //  mySerial.print("     ");
  mySerial.print(posCW[1], DEC);
  mySerial.print("  ");
  mySerial.print(posCCW[1], DEC);   
  mySerial.print("  ");
  mySerial.print(posCW[2], DEC);
  mySerial.print("  ");
  mySerial.print(posCCW[2], DEC); 
  mySerial.print("  ");
  mySerial.print(posCW[3], DEC);
  mySerial.print("  ");
  mySerial.println(posCCW[3], DEC); 
} 

A view of the DCC waveform as it enters the Arduino