/*
Arduino Nano - old bootloader
Robert Parnell.
28/6/23
Wascoe Siding - tunnel signal controller
(designed to be mounted on signal module PCB)
#############################
V1 - create basic structure
###########################
board outputs:
T1 red
T1 yellow
T1 green
T2 red
T2 yellow
T3 green
track circuit mimic
HB heartbeat - indicates that unit is operating
board inputs:
signalafterT1
signalafterT2
trackcct
stop
T1 proceed
T2 proceed
emergency stop
*/
//outputs:
int red1 = 2;// D2 etc
int yellow1 = 3;
int green1 = 4;
int red2 = 5;
int yellow2 = 7;
int green2 = 8;
int mimic = 9;
int HB = 10; // heartbeat indicator
//int RevAlert = 11;
//int S2grn = 12;
//inputs:
int nextT1 = A0;
int nextT2 = A1;
int trkcct = A2;
int stop = A3;
int T1proceed = A4;
int T2proceed = A6;
int emergencystop = A7;
// input values:
int nextT1Val = 1000;
int nextT2Val = 1000;
int trkcctVal = 1000;
int stopVal = 1000;
int T1proceedVal = 1000;
int T2proceedVal = 1000;
int emergencystopVal = 1000;
int testtime = 1000; // milliseconds for test lamp sequence
unsigned long HBstartMillis; // for heartbeat timer
unsigned long tunnelstartMillis; // for tunnel caution timer
unsigned long HBcurrentMillis; // what will be the current value to compare countdown to
unsigned long tunnelcurrentMillis;
unsigned long HBtimer = 500; // heartbeat timer
unsigned long tunneltimer = 10000; // timer to show caution, after train passes through tunnel
boolean caution = false; // tunnel timer up or not?
boolean HBtoggle = false; // HB LED toggle
boolean trackwasOCC = false;
boolean trackisOCC = false;
boolean displayingstop = false;
void setup() {
pinMode(red1, OUTPUT);
pinMode(yellow1, OUTPUT);
pinMode(green1, OUTPUT);
pinMode(red2, OUTPUT);
pinMode(yellow2, OUTPUT);
pinMode(green2, OUTPUT);
pinMode(mimic, OUTPUT);
pinMode(HB, OUTPUT);
pinMode(nextT1, INPUT);
pinMode(nextT2, INPUT);
pinMode(trkcct, INPUT);
pinMode(stop, INPUT);
pinMode(T1proceed, INPUT);
pinMode(T2proceed, INPUT);
pinMode(emergencystop, INPUT);
HBstartMillis = millis(); //start timing code for heartbeat
tunnelstartMillis = millis(); //start timing code for alert
startuptest();
displaySTOP();
}
void loop() {
// read input values
// display appropriate signal
// go back and do it again!
// flash heartbeat LED along the way
HBcurrentMillis = millis();
tunnelcurrentMillis = millis();
if (HBcurrentMillis - HBstartMillis >= HBtimer){
HBtoggle = !HBtoggle; // invert the status from true/false to false/true
digitalWrite(HB,HBtoggle); // turn HB on/off
HBstartMillis = HBcurrentMillis;
}
readinputvalues();
}
void readinputvalues(){
displayingstop = false;
nextT1Val = analogRead(nextT1); //
nextT2Val = analogRead(nextT2); //
trkcctVal = analogRead(trkcct); //
stopVal = analogRead(stop); //
T1proceedVal = analogRead(T1proceed); //
T2proceedVal = analogRead(T2proceed); //
emergencystopVal = analogRead(emergencystop); //
if (stopVal <= 500) {
displaySTOP();
displayingstop = true;
}
if (emergencystopVal <= 500){
displaySTOP();
displayingstop = true;
}
if (trkcctVal <=500){
digitalWrite(mimic, HIGH);
displaySTOP();
displayingstop = true;
trackwasOCC = true;
trackisOCC = true;
tunnelstartMillis = millis(); //start timing code for alert
// loop through until unoccupied, via true/false logic
delay (10); // track circuit debounce
}
else {
trackisOCC = false;
digitalWrite(mimic, LOW);
//if (trackwasOCC == true) tunnelstartMillis = millis();
}
tunnelcurrentMillis = millis(); //
if (tunnelcurrentMillis-tunnelstartMillis <= tunneltimer) caution = true;
else caution = false;
if (trackwasOCC==true && caution == false) trackwasOCC = false; //time delay since occupancy has now passed
//display other indications - only if track is NOT occupied
if (trackisOCC==false && displayingstop == false){
// check "proceed" switches
// if set, check if there was a recent train in the tunnel and display "caution"
// also check if the next signal is at stop and display "caution"
// if both next signal is not at stop and no recent train in tunnel, display "clear"
// do this for both directions
if (T1proceedVal<=500) displayT1proceed();
if (T2proceedVal<=500) displayT2proceed();
}
// end of readinputvalues() void ##############
}
void displayT1proceed(){
// signal 2 must be red
digitalWrite(green2,LOW); // off
digitalWrite(yellow2,LOW); // off
digitalWrite(red2,HIGH); // on
digitalWrite(red1,LOW); // T1 red must be off
if (trackwasOCC == true || nextT1Val <=500 ){
// display caution - since tunnel recently occupied or next signal is at stop
digitalWrite(green1,LOW); // off
digitalWrite(yellow1,HIGH); // off
}
else {
// display clear
digitalWrite(green1,HIGH); // off
digitalWrite(yellow1,LOW); // off
}
//
}
void displayT2proceed(){
// signal 1 must be red
digitalWrite(green1,LOW); // off
digitalWrite(yellow1,LOW); // off
digitalWrite(red1,HIGH); // on
digitalWrite(red2,LOW); // T2 red must be off
if (trackwasOCC == true || nextT2Val <=500 ){
// display caution - since tunnel recently occupied or next signal is at stop
digitalWrite(green2,LOW); // off
digitalWrite(yellow2,HIGH); // off
}
else {
// display clear
digitalWrite(green2,HIGH); // off
digitalWrite(yellow2,LOW); // off
}
//
}
void displaySTOP(){
digitalWrite(green1,LOW); // off
digitalWrite(yellow1,LOW); // off
digitalWrite(red1,HIGH); // on
digitalWrite(green2,LOW); // off
digitalWrite(yellow2,LOW); // off
digitalWrite(red2,HIGH); // on
}
void startuptest(){
// cycle through and test all outputs for a short time
digitalWrite(mimic,HIGH); // on
delay (testtime);
digitalWrite(mimic,LOW); // off
digitalWrite(green1,HIGH); // on
delay (testtime);
digitalWrite(green1,LOW); // off
digitalWrite(yellow1,HIGH); // on
delay (testtime);
digitalWrite(yellow1,LOW); // off
digitalWrite(red1,HIGH); // on
delay (testtime);
digitalWrite(red1,LOW); // off
digitalWrite(green2,HIGH); // on
delay (testtime);
digitalWrite(green2,LOW); // off
digitalWrite(yellow2,HIGH); // on
delay (testtime);
digitalWrite(yellow2,LOW); // off
digitalWrite(red2,HIGH); // on
delay (testtime);
digitalWrite(red2,LOW); // off
}