New user needs help with train program

Im a PLC engineer, so Im not a complete new guy, but Im making a controller to be used to control some functions in Lionel newer trains.

  1. Operator cab light goes out when voltage is sensed on motor leads, so train in motion, LED goes OFF, train stopped LED is ON

  2. A IR sensor reads a tape encoder, counts the pules then activates a relay. This is to turn on and off a blower motor to simulate chuffing smoke out of the smoke unit. When drive motor has no voltage then let the fan just run constantly.

  3. Headlight LED dims when no voltage on motor and brightens when voltage at motor.

I managed to do some coding, please review it. I havent done any of #3 yet.
Thanks so much!!!

// Train Controller V1

// These constants won't change:
const int analogPin = A0; // Motor Voltage via 0-25vdc divider to 0-5vdc
const int ledPin = 2; // Cab Light LED
const int threshold = 400; // Motor Voltage at which the LED goes off
const int encoderPin = 3; // the pin that the encoder is attached to
const int relayPin = 3; // the pin that the Relay is attached to

// Variables will change:
int encoderCounter = 0; // counter for the number of encoder stripes
int encoderState = 0; // current state of the encoder
int lastEncoderState = 0; // previous state of the encoder

void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the Encoder pin as an input:
pinMode(encoderPin, INPUT);
// initialize the Relay as an output:
pinMode(relayPin, OUTPUT);
// initialize serial communication:
Serial.begin(9600);
}

void loop() {
// Cab Light Logic
// read the voltage of the motor:
int analogValue = analogRead(analogPin);

// if the analog value is high enough, turn on the LED:
if (analogValue > threshold) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}

// Chuff Logic
// read the encoder input pin:
encoderState = digitalRead(encoderPin);

// compare the encoderState to its previous state
if (encoderState != lastEncoderState) {
// if the state has changed, increment the counter
if (encoderState == HIGH) {
// if the current state is HIGH then the encoder went from off to on:
encoderCounter++;
Serial.println("on");
Serial.print("number of encoder pulses: ");
Serial.println(encoderCounter);
} else {
// if the current state is LOW then the encoder went from on to off:
Serial.println("off");
}
// Delay a little bit to avoid bouncing
delay(50);
}
// save the current state as the last state, for next time through the loop
lastEncoderState = encoderState;

// turns on the RELAY every four pulses by checking the modulo of the
// encoder counter. the modulo function gives you the remainder of the
// division of two numbers:
if (encoderCounter % 4 == 0) {
digitalWrite(relayPin, HIGH);
} else {
digitalWrite(relayPin, LOW);
}

}

You should post code by using code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

//  Train Controller V1



// These constants won't change:
const int analogPin = A0;    // Motor Voltage via 0-25vdc divider to 0-5vdc
const int ledPin = 2;       // Cab Light LED
const int threshold = 400;   // Motor Voltage at which the LED goes off
const int  encoderPin = 3;    // the pin that the encoder is attached to
const int relayPin = 4;       // the pin that the Relay is attached to

// Variables will change:
int encoderCounter = 0;   // counter for the number of encoder stripes
int encoderState = 0;         // current state of the encoder
int lastEncoderState = 0;     // previous state of the encoder



void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the Encoder pin as an input:
  pinMode(encoderPin, INPUT);
  // initialize the Relay as an output:
  pinMode(relayPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  // Cab Light Logic
  // read the voltage of the motor:
  int analogValue = analogRead(analogPin);

  // if the analog value is high enough, turn on the LED:
  if (analogValue > threshold) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

  // Chuff Logic
  // read the encoder input pin:
  encoderState = digitalRead(encoderPin);

  // compare the encoderState to its previous state
  if (encoderState != lastEncoderState) {
    // if the state has changed, increment the counter
    if (encoderState == HIGH) {
      // if the current state is HIGH then the encoder went from off to on:
      encoderCounter++;
      Serial.println("on");
      Serial.print("number of encoder pulses: ");
      Serial.println(encoderCounter);
    } else {
      // if the current state is LOW then the encoder went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastEncoderState = encoderState;


  // turns on the RELAY every four pulses by checking the modulo of the
  // encoder counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (encoderCounter % 4 == 0) {
    digitalWrite(relayPin, HIGH);
  } else {
    digitalWrite(relayPin, LOW);
  }

}
1 Like

Better names would help. For example, analogPin could be MotorVoltagePin.

Loop is very long. I would move the cab light code into its own function and call it from loop. The chuff stuff could have its own function too, making it easier to read.

There's nothing there yet that runs the blower when the engine power is off.

Can you help me with the function programming. The blower on constant if not receiving pulses I couldn’t figure out, any help there too?

I was thinking of something like this for the cab light:

void DoCabLight()
{
  // Cab Light Logic
  // read the voltage of the motor:
  int MotorVoltage = analogRead(MotorVoltagePin);
  // if the analog value is high enough, turn on the LED:
  if (MotorVoltage > threshold)
  {
    digitalWrite(ledPin, HIGH);
  }
  else
  {
    digitalWrite(ledPin, LOW);
  }
}

Would this replace the code in the loop section?

For the chuff functionality, read the motor voltage. Then wrap an if around the chuff code: if it's over the threshold, do what you have now, else turn the fan on.

Eventually, I'd add a function that checks for motor voltage and returns a boolean to tell me whether it is on or off since chuff and cab light and headlight dim all need to know about it.

It replaces the cab light code in the loop function with a simple call to DoCabLight. It basically is the code that was in loop refactored into a separate function. It's not identical because I tweaked some of the names.

I am completely behind the 8 ball here. This is my first Arduino and I have no clue how to do what you are saying. Im a ladder logic kinda guy. Thanks so much for the help, but Im clueless right now. Can you modify my code a bit so I can see what your talking about? Thanks

This is the first step:

// Train Controller V1

const int MotorVoltagePin = A0;   // Motor Voltage via 0-25vdc divider to 0-5vdc
const int ledPin = 2;       // Cab Light LED
const int threshold = 400;  // Motor Voltage at which the LED goes off
const int encoderPin = 3;   // the pin that the encoder is attached to
const int relayPin = 3;     // the pin that the Relay is attached to

int encoderCounter = 0;     // counter for the number of encoder stripes
int encoderState = 0;       // current state of the encoder
int lastEncoderState = 0;   // previous state of the encoder

void setup()
{
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the Encoder pin as an input:
  pinMode(encoderPin, INPUT);
  // initialize the Relay as an output:
  pinMode(relayPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}

void loop()
{
  DoCabLight();
  // Chuff Logic
  // read the encoder input pin:
  encoderState = digitalRead(encoderPin);
  // compare the encoderState to its previous state
  if (encoderState != lastEncoderState)
  {
    // if the state has changed, increment the counter
    if (encoderState == HIGH)
    {
      // if the current state is HIGH then the encoder went from off to on:
      encoderCounter++;
      Serial.println("on");
      Serial.print("number of encoder pulses: ");
      Serial.println(encoderCounter);
    }
    else
    {
      // if the current state is LOW then the encoder went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastEncoderState = encoderState;
  // turns on the RELAY every four pulses by checking the modulo of the
  // encoder counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (encoderCounter % 4 == 0)
  {
    digitalWrite(relayPin, HIGH);
  }
  else
  {
    digitalWrite(relayPin, LOW);
  }
}

void DoCabLight()
{
  // Cab Light Logic
  // read the voltage of the motor:
  int MotorVoltage = analogRead(MotorVoltagePin);
  // if the analog value is high enough, turn on the LED:
  if (MotorVoltage > threshold)
  {
    digitalWrite(ledPin, HIGH);
  }
  else
  {
    digitalWrite(ledPin, LOW);
  }
}

OK that is making more sense to me now

So I can do the same for the chuff code?

Yes. Perhaps another function for dimming the headlight too.

Hi,
What scale/gauge?
How much room do you have?

Tom... :grinning: :+1: :coffee: :australia:

You might be able to avoid the delay in your loop function if you used an interrupt... If you are concerned about bouncing your interrupt function could see how long it's been since it was last called.

Is this Lionchief or TMCC? I'm guessing Lionchief if it's recent and does't have chuffing built in.

It’s TMCC. Basically mimic the super chuffer board. Giving actual chuff and runs fan when not moving. Also turns off the cab light at motion. Making TMCC engines more like Legacy.

When it comes to the code, I have no clue. I’m a ladder logic guy and code is not my thing, so I need help with this stuff.

O scale, it’s a 10’x 30’ layout