No communication between Throttle and DCC++ base station using 2 Arduino Unos

Hi All,

(This is about the digital control of a model railroad layout)

I'm trying to add a Throttle to the DCC++ base station I have already running.

I have built a Throttle using an Arduino Uno, a breadboard and several components.
(Originally an Arduino pro mini should be used but I don't have it available at the moment)

It is being build to move this locomotive back and forth:

Everything seems to be OK, when I select a locomotive or change the address the display displays everything correct. The only but important thing that seems to be lacking is communication over pin 1(TX).
When a USB cable is connected there is communication indicated by the onboard LED. But not over pin 1. When I remove the USB cable the LED doesn't even blink anymore.

What can I do to solve this?

The code used is in the next post:

I will try to verify tomorrow, but think that it is normal that leds are not blinking. They are connected to the usb-to-ttl chip and (if memory serves me well) only work when usb is connected.

Did you check the signal on the tx pin?

Hi, I don't know how to check the signal on the TX pin.

The strange thing is that I now discovered sometimes the Throttle works, to loco moves back and forth, but the function buttons all have the same effect, the horn sounds. At a random point in time the loco doesn't respond anymore. As long as it has track power it gives the engine sound and often nothing more.

Here the first part of the code:

/*
  VERSION WITH 3x4 KEYPAD, not capacitive touch unit
  Modified to use * and # in place of two buttons

  d. bodnar  revised 5-23-2016
   To Do:
   1.  LCD to show Loco #, speed, direction   L=5721 S=88 D=>    16 Characters
   2.  LCD line two Function display    0000 0000 0000 ?????
   3.  Left button calls up Menu
   4.  Right button used to change loco in focus
   5.  POT center = stop, CCW = reverse to max, CW = forward to max

*/
#include "Arduino.h"
byte Key;
#include<EEPROM.h>
char key ;
int LED = 13; // LED to blink when DCC packets are sent in loop
byte Fx = 0;
// Array set for 4 Loco2 - change the 7 numbers in the next 7 declarations
int maxLocos = 4;// number of loco addresses
int LocoAddress[4] = {1830, 3, 999, 4444};
int LocoDirection[4] = {1, 1, 1, 1};
int LocoSpeed[4] = {0, 0, 0, 0};
byte LocoFN0to4[4];
byte LocoFN5to8[4];
byte Locofn9to12[4];// 9-12 not yet implemented
int xxxxx = 0;
int pot1Pin = A3;
int potValue = 0;
int NewPotValue = 0;
int potValueOld = 0;
int counter = 0;
int Trigger1 = 3;
int Trigger2 = 4;
int TrigVal1 = 0;
int TrigVal2 = 0;
int old_speed = 0;
int ZeroSpeedFlag = 0;
int ActiveAddress = 0; // make address1 active
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR    0x27 // <<----- Add your address here.  Find it from I2C Scanner
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
LiquidCrystal_I2C  lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
int z = 0;
int powerTemp = 0;
int i = 0;
char VersionNum[] = "1.7F "; ///////////////////////// //////////////////////VERSION HERE///////
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {5, 6, 7, 8 }; //{8,7,6,5 }; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 10, 11}; // {11,10,9}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
byte ledPin = 13;
boolean blink = false;
boolean ledPin_state;
int debug = 0; // set to 1 to show debug info on serial port - may cause issues with DCC++ depending on what is sent

void setup() {
  pinMode(Trigger1, INPUT);
  pinMode(Trigger2, INPUT);
  digitalWrite(Trigger1, HIGH);// turn on pullup resistors
  digitalWrite(Trigger2, HIGH);// turn on pullup resistors
  // randomSeed(analogRead(0));
  pinMode(LED, OUTPUT);
  lcd.begin (16, 2); //  LCD is 16 characters x 2 lines
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(HIGH);  // Switch on the backlight
  lcd.home (); // go home
  Serial.begin (115200);
  lcd.setCursor(0, 0);
  lcd.print("DCC++ Throttle");
  lcd.setCursor(0, 1);
  lcd.print("5-26-16 - v");
  for (int i = 0; i < 4; i++) {
    lcd.print(VersionNum[i]);
    //delay(500);
  }
  getAddresses();  // read eeprom
  Serial.print("5-22-2016  version ");
  for (int i = 0; i < 4; i++) {
    Serial.print(VersionNum[i]);
    //delay(500);
  }
  if (debug == 1) Serial.println("");
  Serial.print("<0>");// power off to DCC++ unit
  delay(1500);

  pinMode(ledPin, OUTPUT);              // Sets the digital pin as output.
  digitalWrite(ledPin, HIGH);           // Turn the LED on.
  ledPin_state = digitalRead(ledPin);   // Store initial LED state. HIGH when LED is on.
  keypad.addEventListener(keypadEvent); // Add an event listener for this keypad

  // showFirstLine();
  lcd.clear();

}  // END SETUP

void loop() {
  TrigVal1 = digitalRead(Trigger1);   // read the input pin
  TrigVal2 = digitalRead(Trigger2);   // read the input pin
  key = keypad.getKey();
  // if (key) {
  if (key == 42) { // *
    all2ZeroSpeeed();
    getLocoAddress();
    key = 0;
  }
  // }
  if (TrigVal1 == 0) {
    all2ZeroSpeeed();
    getLocoAddress();
    //   showFirstLine();
  }
  potValue = analogRead(pot1Pin);    // read the value from the sensor
  if (potValue != potValueOld) {
    NewPotValue = 1;
    //doMainLCD();
  }
  else NewPotValue = 0;
  potValueOld = potValue;
  potValue = (potValue / 4) - 128;
  if (potValue <= 0) {
    LocoDirection[ActiveAddress] = 0; // backward
  }
  else LocoDirection[ActiveAddress] = 1; // forward
  potValue = abs(potValue);
  if (potValue >= 126) potValue = 126; // max is 127
  if (potValue <= 3) potValue = 0; // set to zero if close to zero
  LocoSpeed[ActiveAddress] =   potValue;
  if (NewPotValue == 1) {
    doDCC();
    doMainLCD();
    NewPotValue = 0;
    delay(50);
  }
  if (key == 35) { // #
    ActiveAddress++;
    if (ActiveAddress >= 4) ActiveAddress = 0;
    //showFirstLine();
    doMainLCD();
    delay(200);
    key = 0;
  }
  if (TrigVal2 == 0) {   // change loco # on right button press
    ActiveAddress++;
    if (ActiveAddress >= 4) ActiveAddress = 0;
    //showFirstLine();
    doMainLCD();
    delay(200);
  }
  //  key = keypad.getKey();
  //    Serial.print("KKKKKKKKKKKKKKKKKEY =");
  //    Serial.println(key);
  if (key != 42 && key != 35 && key >= 40) {
    //   if (key == 42) Serial.println("****************************");
    //   Serial.print("KEY =");
    //   Serial.println(key);
    doFunction();
  }
  // doMainLCD();
}  //END LOOP


//START DO FUNCTION BUTTONS
int doFunction() {
  key = key - 48 - 1; // convert from ascii value
  lcd.setCursor (14, 1);       // go to end of 2nd line
  ///  lcd.print("FN code ");
  lcd.print(key, DEC);
  if (debug == 1) Serial.print("got a keypad button ");
  if (debug == 1) Serial.println(key, DEC);
  if (key <= 4) {
    if (bitRead(LocoFN0to4[ActiveAddress], key) == 0 ) {
      bitWrite(LocoFN0to4[ActiveAddress], key, 1);
    }
    else {
      if (bitRead(LocoFN0to4[ActiveAddress], key) == 1 ) {
        bitWrite(LocoFN0to4[ActiveAddress], key, 0);
      }
    }
    doDCCfunction04();
    Serial.print(LocoFN0to4[ActiveAddress], BIN);
    if (debug == 1) Serial.println(" LocoFN0to4[ActiveAddress] d ");
    Serial.print(LocoFN0to4[ActiveAddress], DEC);
    if (debug == 1) Serial.println(" LocoFN0to4[ActiveAddress]");
  }
  if (key >= 5 && key <= 8) {
    key = key - 5;
    if (bitRead(LocoFN5to8[ActiveAddress], key) == 0 ) {
      bitWrite(LocoFN5to8[ActiveAddress], key, 1);
    }
    else {
      if (bitRead(LocoFN5to8[ActiveAddress], key) == 1 ) {
        bitWrite(LocoFN5to8[ActiveAddress], key, 0);
      }
    }
    doDCCfunction58();
    Serial.print(LocoFN5to8[ActiveAddress], BIN);
    if (debug == 1) Serial.println(" LocoFN5to8[ActiveAddress] d ");
    Serial.print(LocoFN5to8[ActiveAddress], DEC);
    if (debug == 1) Serial.println(" LocoFN5to8[ActiveAddress]");
  }
  if (key == -1)
  {
    lcd.setCursor (14, 1);       // go to end of 2nd line
    ///    lcd.print("FN code ");
    lcd.print(key, DEC);
    key = 0;
    LocoFN0to4[ActiveAddress] = B00000000; //clear variables for which functions are set
    LocoFN5to8[ActiveAddress] = B00000000;
    doDCCfunction04();
    doDCCfunction58();
    delay(500);
    key = 0;
  }
  key = 0;
  // delay(500);
  doMainLCD();
}
//END DO FUNCTION BUTTONS

The rest will be posted later due to restrictions on my account?!.

Second and last part of the code:

void showFirstLine() {
  // break;
  if (debug == 1) Serial.println(" ");
  lcd.setCursor(0, 0);
  lcd.print("                ");// clear
  lcd.setCursor(0, 0);
  lcd.print("L");
  lcd.print(ActiveAddress + 1);
  lcd.print("=");
  lcd.print(LocoAddress[ActiveAddress]);

  for (int zzz = 0; zzz <= 3; zzz++) {
    if (debug == 1) Serial.print("add # ");
    if (debug == 1) Serial.print(zzz + 1);
    if (debug == 1) Serial.print(" ");
    if (debug == 1) Serial.println(LocoAddress[zzz]);

  }


}

void getLocoAddress() {
  Serial.print("<0>");// power off to DCC++ unit
  int total = 0;
  counter = 0;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Set Dcc Addr # ");
  lcd.print(ActiveAddress + 1);
  if (debug == 1) Serial.println(" @ top");
  do {
    TrigVal2 = digitalRead(Trigger2);   // read the input pin
    if (TrigVal2 == 0) break; // exit routine if right button pressed - ABORT new address
    key = keypad.getKey();
    if (key) {
      counter++;
      int number =  key - 48;
      total = total * 10 + number;
      if (debug == 1) Serial.print("TOTAL= ");
      if (debug == 1) Serial.println(total);
      lcd.setCursor(0, 1);
      if (total == 0) {   // print multiple zeros for leading zero number
        for (int tempx = 1; tempx <= counter; tempx++) {
          lcd.print("0");
        }
      }
      else lcd.print(total);
      if (debug == 1) Serial.print("Counter = ");
      if (debug == 1) Serial.print(counter);
      if (debug == 1) Serial.print("  key= ");
      if (debug == 1) Serial.print(key);

      if (debug == 1) Serial.print("   val =");
      if (debug == 1) Serial.println(number);
    }
    TrigVal2 = digitalRead(Trigger2);   // read the input pin
  }
  while (counter <= 3); //  collect exactly 4 digits
  //  while (  TrigVal2 == 1);
  LocoAddress[ActiveAddress] = total;
  saveAddresses();
  lcd.clear();
  doMainLCD();
}


// Taking care of some special events.
void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      if (key == '#') {
        digitalWrite(ledPin, !digitalRead(ledPin));
        ledPin_state = digitalRead(ledPin);        // Remember LED state, lit or unlit.
      }
      break;

    case RELEASED:
      if (key == '*') {
        digitalWrite(ledPin, ledPin_state);   // Restore LED state from before it started blinking.
        blink = false;
      }
      break;

    case HOLD:
      if (key == '*') {
        blink = true;    // Blink the LED when holding the * key.
      }
      break;
  }
}


void doDCC() {
  //Serial.print("d = ");
  if (debug == 1) Serial.println(LocoDirection[ActiveAddress] );
  Serial.print("<1>");
  Serial.print("<t1 ");
  Serial.print(LocoAddress[ActiveAddress] );//locoID);
  Serial.print(" ");
  Serial.print(LocoSpeed[ActiveAddress] );
  Serial.print(" ");
  Serial.print(LocoDirection[ActiveAddress] );
  Serial.write(">");
}

void doDCCfunction04() {
  Serial.write("<f ");
  Serial.print(LocoAddress[ActiveAddress] );
  Serial.print(" ");
  int fx = LocoFN0to4[ActiveAddress] + 128;
  Serial.print(fx);
  Serial.print(" >");
}

void doDCCfunction58() {
  Serial.write("<f ");
  Serial.print(LocoAddress[ActiveAddress] );
  Serial.print(" ");
  int fx = LocoFN5to8[ActiveAddress] + 176;
  Serial.print(fx);
  Serial.print(" >");
}

void all2ZeroSpeeed() {  // set flag to 1 to stop, set to 0 to restore
  for (int tempx = 0; tempx <= maxLocos; tempx++) {
    Serial.print("<t1 ");
    Serial.print(LocoAddress[tempx] );//locoID);
    Serial.print(" ");
    if (ZeroSpeedFlag == 1) {
      Serial.print(0);//LocoSpeed[0] );
    }
    else Serial.print(LocoSpeed[0] );
    Serial.print(" ");
    Serial.print(LocoDirection[1] );
    Serial.write(">");
  }
}

void getAddresses() {
  int xxx = 0;
  for (int xyz = 0; xyz <= maxLocos - 1; xyz++) {
    LocoAddress[xyz] = EEPROM.read(xyz * 2) * 256;
    LocoAddress[xyz] = LocoAddress[xyz] + EEPROM.read(xyz * 2 + 1);
    if (LocoAddress[xyz] >= 10000) LocoAddress[xyz] = 3;

    if (debug == 1) Serial.println(" ");
    if (debug == 1) Serial.print("loco = ");
    if (debug == 1) Serial.print(LocoAddress[xyz]);
    if (debug == 1) Serial.print("  address# = ");
    if (debug == 1) Serial.print(xyz + 1);
  }
  if (debug == 1) Serial.println(" ");
}

void saveAddresses() {
  int xxx = 0;
  for (int xyz = 0; xyz <= maxLocos - 1; xyz++) {
    xxx = LocoAddress[xyz] / 256;
    if (debug == 1) Serial.println(" ");
    if (debug == 1) Serial.print("loco = ");
    if (debug == 1) Serial.print(LocoAddress[xyz]);
    if (debug == 1) Serial.print("  address# = ");
    if (debug == 1) Serial.print(xyz);
    if (debug == 1) Serial.print(" msb ");
    if (debug == 1) Serial.print(xxx);
    if (debug == 1) Serial.print(" writing to ");
    if (debug == 1) Serial.print(xyz * 2);
    if (debug == 1) Serial.print(" and ");
    if (debug == 1) Serial.print(xyz * 2 + 1);
    EEPROM.write(xyz * 2, xxx);
    xxx = LocoAddress[xyz] - (xxx * 256);
    if (debug == 1) Serial.print(" lsb ");
    if (debug == 1) Serial.print(xxx);
    EEPROM.write(xyz * 2 + 1, xxx);
  }
}


void doMainLCD() {
  //lcd.setCursor(0, 0);
  //lcd.print("               ");
  lcd.setCursor(0, 0);
  lcd.print("S=");
  lcd.print(LocoSpeed[ActiveAddress], DEC);
  lcd.print("  ");
  lcd.setCursor(6, 0);
  if (LocoDirection[ActiveAddress] == 1 ) {
    lcd.print(">");
  }
  else {
    lcd.print("<");
  }

  lcd.setCursor(8, 0);

  lcd.print("L=");
  if (LocoAddress[ActiveAddress] <= 9) {
    lcd.print("0");  // add leading zero for single digit addresses
  }
  lcd.print(LocoAddress[ActiveAddress] , DEC);
  lcd.print("   ");
  lcd.setCursor(14, 0);
  lcd.print("#");
  lcd.setCursor (15, 0);       // go to end of 1st line
  lcd.print(ActiveAddress + 1);
  lcd.setCursor(5, 1); // start of 2nd line
  String temp = "0000" + String(LocoFN0to4[ActiveAddress], BIN);  // pad with leading zeros
  int tlen = temp.length() - 5;
  lcd.print(temp.substring(tlen));
  temp = "000" + String(LocoFN5to8[ActiveAddress], BIN);
  tlen = temp.length() - 4;
  lcd.setCursor(0, 1); // start of 2nd line
  lcd.print(temp.substring(tlen));

}

I've confirmed the behaviour on a real Uno and a SparkFun RedBoard. For the TX led to flash, you have to open serial monitor (or another terminal program).

leo_groeneveld:
Hi, I don't know how to check the signal on the TX pin.

Do you have a second Arduino? Or a USB-to-TTL cable? If so, hook that up to the TX pin and check with a simple sketch. I did that and I get the expected response.

If you have an oscilloscope, you can easily measure the signal.

Else you can try with a multimeter; the TX pin should be high if you don't send anything and possibly show a slightly lower voltage when you send data.

I will look at your code later and see if there is something obvious that is wrong.

PS
If your code is too big, you can attach it.

This is at least one bug in your code although I do not expect this one to cause the problem.

  for (int tempx = 0; tempx <= maxLocos; tempx++) {

The warning I get

C:\Users\sterretje\AppData\Local\Temp\arduino_modified_sketch_393051\sketch_oct01c.ino:358:37: warning: iteration 4 invokes undefined behavior [-Waggressive-loop-optimizations]

     Serial.print(LocoAddress[tempx] );//locoID);

You have 4 LocoAddresses but try to access number 5; change the <= to < and test again. In other loops, you have a -1 so should be OK.

It’s the only thing I can find at this moment and, as said, not likely the cause of your problem. Will dig a bit further later on.

I think that your code can do with some optimisations, but that’s another story.

Hi Thank you so far.

I would like to state that the code is not written by me, I'm not able to write code like this.
The code is written by Dave Bodnar and is free to download and use.

If I get to understand the code a bit better I would like to reduce the maximum speed of 126 to 20-25 as I'm going to build (in a couple of years) me a branch line, branch lines often have a very low speed limit due to the condition the tracks are in.
Also I would like the have a bit of a dead band at the center of the potmeters reach, now the switch between forward and reverse is very sensitive.

Most important thing is that the control of the loco works and seems to be stable.
Only unfortunate thing (I noticed, maybe there's more) is that when I use the functions F1, F3, F4 and so on also function F2 (horn) is audible.

Does the code error you mentioned have to do with the index? So maxloco 4 (index 4) is the fifth place in the list. (just asking for my understanding)

Thanks again so far.

Leo

Yes

People count from one, computers from zero. So an array with 4 elements has indices 0…3 and one should not exceed 3. As maxLocos equals 4, the for-loop that I showed translates to

for (int tempx = 0; tempx <= 4; tempx++) {

and with the last iteration you do access the element with index 4 (the 5th element) of the array.

Do I understand correctly that it principle works but you have a flaw where certain keys on your keypad trigger the behaviour of a specific other key?

I’m not familiar with DCC; how do your keys 0…9, * and # translate to F1…F4?

Yes, the principle works, the loco can move back and forth and now that part is working stable so far.
Also the engine sound is correct and the engine revs up and down when accelerating/decelerating.

Expectations:
When I push “1” on the keypad I expect to turn on and off the bell (it’s like a cowbell)
When I push “2” on the keypad I expect the horn to sound for x seconds or when pressed again within x seconds the horn should stop.
When I push “9” on the keypad 3 times I expect the engine to shut down and the loco should become irresponsive to DCC commands.

Pratice:
When I push “1” on the keypad I hear the horn sounding for x seconds and after that I can hear the bell.
When I push “1” again on the keypad I hear the horn sounding for x seconds and after that no bell.
When I push “2” on the keypad I hear the horn for x seconds.
When I push “2” on the keypad within x seconds the horn stops.
When I push “9” on the keypad 3 times the engine is shutdown and becomes irresponsive to DCC commands.
When I push “9” or another function on the keypad the engine starts and the loco again responds to DCC commands.

The other functions I don’t use (coupling sound, compressor sound, wheel squeel and so on) but there are several others functions when touched the horn sounds over the other (intended) sounds.

The commands described above are called CAB functions and should work like this. (when I try them over the serial monitor (without the throttle) it also doesn’t work like it should, only the horn sounds correctly, the other functions do nothing.)

The decoder should get a command like this <f 3 130>
< start of a DCC command
f tells the decoder it is a CAB function command.
3 is the decoder address (a loco decoder has the short address of 3 by default, it can be changed by the user and when operating more than 1 loco at least one must be changed)
130 this is the number 128 plus the function number (horn has function number 2), this is valid for the functions F1 - F4, the other function groups have a different start and their own function number.

end of a DCC command

When sending a DCC command in a function range the number of the all functions from that range that need to be turned on or have to stay on have to be added to 128.

As I’m typing this even the situations above differ, when trying now sometimes the bell sounds without the horn but after a couple of tries it starts to go wrong again.

My wish list is:

  • reduce the max speed to 20-25 instead of 126 (I think I can do that by changing constrain from 126 to 20-25)
  • create a dead band at the center of the potmeter to reduce sensitivity between forward and reverse.
  • Have the functions work stable

Leo

EDIT:

“*” button is to assign a decoder address to the loco number in the Throttle.
“#” button is to scroll through the different locomotives

EDIT2:

I now discovered when I push button 2 and push it again within the time the horn sounds (so I break the horn sound) I can press 1 and get the bell sound without the horn sounding.

I have changed the following part of the code:
It works, the dead band is more broad now and the max speed is reduced to 25 instead of 126.

else LocoDirection[ActiveAddress] = 1; // forward
  potValue = abs(potValue);
  if (potValue >= 25) potValue = 25; // max is 127 changed from 126 to 25 by Leo Groeneveld
  if (potValue <= 8) potValue = 0; // set to zero if close to zero changed from 3 to 8 by Leo Groeneveld
  LocoSpeed[ActiveAddress] =   potValue;
  if (NewPotValue == 1) {
    doDCC();
    doMainLCD();
    NewPotValue = 0;
    delay(50);

However, I also introduced two disadvantages, those are:
1 I would like the speed setting to start at 8. So from 8 the loco should reveive speed 1 and not start at speed level 9.
2 I now miss a lot of resolution in the potmeter, after 25 I have a lot of stroke left doing nothing. It should be used (mapped) to 25 to get a more sensitive control.

Can I use mapping (and if so how?) to solve this?

EDIT:

I have changed this part of the code and it seems to work, a wider dead band and I can map to the maximum speed using the full stroke of the potmeter.

  potValue = analogRead(pot1Pin);    // read the value from the sensor
  if (potValue != potValueOld) {
    NewPotValue = 1;
    //doMainLCD();
  }
  else NewPotValue = 0;
  
  potValueOld = potValue;
  potValue = (potValue / 4) - 128;
  
  if (potValue <= 0) {
    LocoDirection[ActiveAddress] = 0; // backward
  }
  else LocoDirection[ActiveAddress] = 1; // forward
  
  potValue = abs(potValue);

  potValue = map(potValue, 9, 126, 4, 25);
  
  if (potValue >= 126) potValue = 126; // max is 127
  if (potValue <= 4) potValue = 0; // set to zero if close to zero changed from 3 to 8 by Leo Groeneveld
  
  LocoSpeed[ActiveAddress] =   potValue;
  
  if (NewPotValue == 1) {
    doDCC();
    doMainLCD();
    NewPotValue = 0;
    delay(50);

NICE :)!

I have now added an emergency stop function:

void emergencyStop(){
  int xxx = 0;
  for (int xyz = 0; xyz <= maxLocos - 1; xyz++) {
    LocoAddress[xyz] = EEPROM.read(xyz * 2) * 256;
    LocoAddress[xyz] = LocoAddress[xyz] + EEPROM.read(xyz * 2 + 1);
    Serial.print("<t1 ");
    Serial.print(LocoAddress[xyz] );    //locoID);
    Serial.print(" ");
    Serial.print(LocoSpeed[LocoAddress[xyz]] = 0 );
    Serial.print(" ");
    Serial.print(LocoDirection[LocoAddress[xyz]] );
    Serial.write(">");
  }
  delay(50);
  Serial.print("<0>");
  stop();
  }

/*
void emergencyStop(){
  LocoSpeed[ActiveAddress] = 0;
  Serial.print("<t1 ");
  Serial.print(LocoAddress[ActiveAddress] );    //locoID);
  Serial.print(" ");
  Serial.print(LocoSpeed[ActiveAddress] );
  Serial.print(" ");
  Serial.print(LocoDirection[ActiveAddress] );
  Serial.write(">");
  delay(50);
  Serial.print("<0>");
  stop();
  }
*/

void stop()
{
 while(1);
}

This is how I call the function in the void loop:
"
if (emergencyVal == 0) {
emergencyStop ();
}
"

It works by pushing a button connected to digital pin 12. The pin has a pull-up resistor to +5V and when the button is pushed it connects the pin to ground.

Only thing bothering me now is the horn function. When pushed for a second time within the x seconds every other function works fine. I should be able to push the horn button and leave it.
This really is the only thing that needs to be fixed for a flawless operation.

I’m going to design a case for the controller and maybe have it 3D printed if the price is not too high, otherwise I will make it from multiplex 3 or 5mm sheets and glue them together, that will cost me a couple of euros and some time which I don’t count financially.

I have decided to use a dedicated Uno instead of a seperate 328 chip because it is as expensive as a seperate chip and now I will be able to update the code with ease. Just open the case and connect a USB cable.

@leo_groeneveld you can contact Dave Bodnar directly and he can answer all of your questions as he has already done with me in the future