/*This code is designed to replicate a traditional Island Approach Island Railroad Crossing Circut
that will be used for a 1/8 scale model railroad and function prototypically to the real circuit.
Hardware used is an Arduino Mega/Mega 2560 with a four channel relay shield where LOW=ON along
with a 12V incadescent flush mount trailer lights and either an authentic 12V RR crossing bell
or a SoundByte Crossing Bell speaker module. Track circuits are desinged to be 5V pullup signals but
may require an inline voltage step-up/step-down device to amplify the signals.
Track circuits are defined by insulating joins per the prototype.
*/
#define NORTH_APPROACH 5
#define ISLAND_CIRCUIT 6
#define SOUTH_APPROACH 7
#define LIGHT_RIGHT 10
#define LIGHT_LEFT 9
#define BELL_RELAY 11
void setup() {
pinMode(NORTH_APPROACH, INPUT_PULLUP); //Track circuit one. 60ft/39.5m long. Primary circuit the train activates 90% of the time.
pinMode(ISLAND_CIRCUIT, INPUT_PULLUP); //Island circuit. 30ft/9m long. Circuit travels through a #5 Right hand Turnout that diverges.
pinMode(SOUTH_APPROACH, INPUT_PULLUP); //Track circuit two. Same length as number one, but needs to be able to activate the crossing from the other direction.
pinMode(BELL_RELAY, OUTPUT); //RR Bell Coil/SoundByte Speaker.
pinMode(LIGHT_LEFT, OUTPUT); //Left Flashing Light.
pinMode(LIGHT_RIGHT, OUTPUT); //Right Flashing Light.
}
enum CROSSINGSTATES {
ST_OFF,
ST_APPROACH_N,
ST_APPROACH_S,
ST_ISLAND,
ST_CLEARING_N,
ST_CLEARING_S,
};
CROSSINGSTATES crossingState = ST_OFF;
void loop() {
int north = digitalRead(NORTH_APPROACH);
int island = digitalRead(ISLAND_CIRCUIT);
int south = digitalRead(NORTH_APPROACH);
int last = 0; //Previous state case. 0=ST_OFF, 1=ST_APPROACH_N, 2=ST_APPROACH_S, 3=ST_ISLAND, 4=ST_CLEARING_N, 5=ST_CLEARING_S.
int current = 0; //Current state case. 0=ST_OFF, 1=ST_APPROACH_N, 2=ST_APPROACH_S, 3=ST_ISLAND, 4=ST_CLEARING_N, 5=ST_CLEARING_S.
switch (crossingState) {
case ST_OFF:
crossingoff(north, island, south, last, current);
break;
case ST_APPROACH_N:
appnorth(north, island, south, last, current);
break;
case ST_APPROACH_S:
appsouth(north, island, south, last, current);
break;
case ST_ISLAND:
crossingblocked(north, island, south, last, current);
break;
case ST_CLEARING_N:
clearingnorth(north, island, south, last, current);
break;
case ST_CLEARING_S:
clearingsouth(north, island, south, last, current);
break;
}
}
void crossingoff(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, HIGH); //Code loop turns off all lights and bells until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, HIGH);
if (north == LOW && island == HIGH && south == HIGH && current == 0) { //If the north circuit activates first while the remaining two are empty. Start the light and bell sequence.
current = 1;
last = current;
crossingState = ST_APPROACH_N;
} else if (south == LOW && island == HIGH && south == HIGH && current == 0) { //If the south circuit activates first while the remaining two are empty. Start the light and bell sequence.
current = 2;
last = current;
crossingState = ST_APPROACH_S;
}
}
void appnorth(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, LOW); //Alternating flashing lights at 120 flashes per minute. Code block repeats until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, LOW);
delay(500);
digitalWrite(LIGHT_LEFT, HIGH);
digitalWrite(LIGHT_RIGHT, LOW);
digitalWrite(BELL_RELAY, LOW);
delay(500);
if (north == LOW && island == LOW && south == HIGH && last == 1) { //Keep the light and bell sequence going if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == LOW && last == 1) { //Keep the light and bell sequence going if all of the circuits are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == HIGH && last == 1) { //Keep the light and bell sequence going if the island is activated even if the approaches aren't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == HIGH && south == LOW && last == 1) { //Keep the light and bell sequence going if both approach circuits are activated even if the island isn't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == HIGH && south == LOW && last == 1) { //Stop the light and bell sequence if the train leaves the approach circuit.
current = 0;
last = current;
crossingState = ST_OFF;
}
}
void appsouth(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, LOW); //Alternating flashing lights at 120 flashes per minute. Code block repeats until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, LOW);
delay(500);
digitalWrite(LIGHT_LEFT, HIGH);
digitalWrite(LIGHT_RIGHT, LOW);
digitalWrite(BELL_RELAY, LOW);
delay(500);
if (north == LOW && island == LOW && south == HIGH && last == 2) { //Keep the light and bell sequence going if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == LOW && last == 2) { //Keep the light and bell sequence going if all of the circuits are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == HIGH && last == 2) { //Keep the light and bell sequence going if the island is activated even if the approaches aren't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == HIGH && south == LOW && last == 2) { //Keep the light and bell sequence going if both approach circuits are activated even if the island isn't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == HIGH && south == LOW && last ==2) { //Stop the light and bell sequence if the train leaves the approach circuit.
current = 0;
last = current;
crossingState = ST_OFF;
}
}
void crossingblocked(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, LOW); //Alternating flashing lights at 120 flashes per minute. Code block repeats until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, LOW);
delay(500);
digitalWrite(LIGHT_LEFT, HIGH);
digitalWrite(LIGHT_RIGHT, LOW);
digitalWrite(BELL_RELAY, LOW);
delay(500);
if (north == LOW && south == HIGH && island == HIGH && last == 3) { //If the train has reached the island and either crosses over it completely or backs off, stop the bell and light sequence even if the train is on an approach circuit.
current = 4;
last = current;
crossingState = ST_CLEARING_N;
} else if (south == LOW && island == HIGH && north == HIGH && last == 3) { //If the train has reached the island and either crosses over it completely or backs off, stop the bell and light sequence even if the train is on an approach circuit.
current = 5;
last = current;
crossingState = ST_CLEARING_S;
}
}
void clearingnorth(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, HIGH); //Code loop turns off all lights and bells until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, HIGH);
if (north == HIGH && island == HIGH && south == HIGH && last == 4) { //If all of the circuits are empty, return to the default state.
current = 0;
last = current;
crossingState = ST_OFF;
} else if (north == LOW && island == HIGH && south == LOW && last == 4) { //Reactivate the light and bell sequence if both approach circuits are activated even if the island isn't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == LOW && last == 4) { //Reactivate the light and bell sequence if all of the circuits are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == HIGH && last == 4) { //Reactivate the light and bell sequence if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == LOW && last == 4) { //Reactivate the light and bell sequence if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == HIGH && last == 4) { //Reactivate the light and bell sequence if the island is activated even if the approaches aren't.
current = 3;
last = current;
crossingState = ST_ISLAND;
}
}
void clearingsouth(int north, int island, int south, int last, int current) {
digitalWrite(LIGHT_LEFT, HIGH); //Code loop turns off all lights and bells until a meet break condition is satisfied.
digitalWrite(LIGHT_RIGHT, HIGH);
digitalWrite(BELL_RELAY, HIGH);
if (north == HIGH && island == HIGH && south == HIGH && last == 5) { //If all of the circuits are empty, return to the default state.
current = 0;
last = current;
crossingState = ST_OFF;
} else if (north == LOW && island == HIGH && south == LOW && last == 5) { //Reactivate the light and bell sequence if both approach circuits are activated even if the island isn't.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == LOW && last == 5) { //Reactivate the light and bell sequence if all of the circuits are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == LOW && island == LOW && south == HIGH && last == 5) { //Reactivate the light and bell sequence if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == LOW && last == 5) { //Reactivate the light and bell sequence if one of the approach circuits and the island circuit are activated.
current = 3;
last = current;
crossingState = ST_ISLAND;
} else if (north == HIGH && island == LOW && south == HIGH && last == 5) { //Reactivate the light and bell sequence if the island is activated even if the approaches aren't.
current = 3;
last = current;
crossingState = ST_ISLAND;
}
}
If anyone would still like to help me, I've rewrote my code using a state switch case format from the ground up taking in every piece of feedback I could along with formatting it to be cleaner. Currently my code gets stuck repeating ST_APPROACH_N after activating it from pin5 and won't progress on to any of the other states. Additionally, the program doesn't jump to ST_APPROACH_S when activating it from pin7.
The state flow is supposed to start at ST_OFF, go to either ST_APPROACH_N or ST_APPROACH_S depending on which track circuit is activated first. Followed by jumping to ST_OFF if the train backs off the approach circuits before reaching the island or jumps to ST_ISLAND while the train is on the island circuit. Once here the program should jump to ST_CLEARING_N or ST_CLEARING_S if the train crosses over the island to the opposite circuit it arrived on or backs up onto the circuit it arrived on. Only when the train is clear of all circuits should the program jump back to ST_OFF and reset.
Sorry if I haven't responded in a while. I had to put the project on hold to focus on some life events that have come about. I feel like I've angered some of you when I failed to post my original modification and I apologize if I did. I never meant to do that, and it was an honest mistake.