// https://wokwi.com/projects/427977547001701377
// https://forum.arduino.cc/t/analog-reading-to-digital/1366479
// camsysca + hacking on the beach
// three tracks can be referred to as 0, 1 and 2 or
# define IN 0
# define CEN 1
# define OUT 2
# define DOCCUPIED LOW //... low is blocked is button or switch closed
struct TRACK {
byte currentState;
byte detPins[2]; // inputs: west detector, east detector
byte lampPins[4]; // outputs: green west, red west, green east, red east
};
// three tracks
TRACK track[3] = {
{0}, // track 0 not here yet
{ 0, //... make it clear : 0 = EMPTY by default
{A14, A1},
{34, 35, 14, 10}
},
{0} // track 2 not here yet
};
//... enum to give numbers nice names
enum {EMPTY = 0, WESTBOUND_ENTERED, WESTBOUND_DEPARTS, EASTBOUND_ENTERED, EASTBOUND_DEPARTS, DEADLOCK};
char *stateTags[] = {"EMPTY", "WEST ENTERED", "WEST DEPART", "EAST ENTERED", "EAST DEPART", "DEADLOCK"};
//... what functionality did I kill or frustrate -> int TrackCenState;
void setup() {
Serial.begin(115200); //... 21st century
setPinModes();
lampTest();
}
void loop() {
//... process_Track reads the inputs for now
process_Track(track + CEN); // (&track[CEN]) if you prefer
LEDSet(track + CEN);
delay(20); //... poor man's debounce
}
void process_Track(TRACK *theTrack)
{
bool det_East = digitalRead(theTrack->detPins[0]) == DOCCUPIED;
bool det_West = digitalRead(theTrack->detPins[1]) == DOCCUPIED;
static int printedState = -1;
if (printedState != theTrack->currentState) {
Serial.print(det_West ? "WEST blocked " : " <west> ");
Serial.print(det_East ? "EAST blocked " : " <east> ");
Serial.print("state is ");
Serial.println(stateTags[theTrack->currentState]);
printedState = theTrack->currentState;
}
switch (theTrack->currentState) {
case EMPTY:
if (det_East) theTrack->currentState = WESTBOUND_ENTERED;
if (det_West) theTrack->currentState = EASTBOUND_ENTERED;
break;
case WESTBOUND_ENTERED:
if (det_West) theTrack->currentState = WESTBOUND_DEPARTS;
break;
case EASTBOUND_ENTERED:
if (det_East) theTrack->currentState = EASTBOUND_DEPARTS;
break;
case WESTBOUND_DEPARTS:
if (!det_West) theTrack->currentState = EMPTY;
break;
case EASTBOUND_DEPARTS:
if (!det_East) theTrack->currentState = EMPTY;
break;
case DEADLOCK: //both entered simultaneously, must clear by backing one of them up; if perchance they both clear, we can go to empty
if (!det_East && !det_West) theTrack->currentState = EMPTY;
else if (!det_East) theTrack->currentState = EASTBOUND_ENTERED;
else if (!det_West) theTrack->currentState = WESTBOUND_ENTERED;
//last else would just remain in DEADLOCK
break;
}
}
enum signals {sGW = 0, sRW, sGE, sRE};
void LEDSet (TRACK *theTrack)
{
switch (theTrack->currentState) {
case EMPTY:
digitalWrite(theTrack->lampPins[sGW], HIGH);
digitalWrite(theTrack->lampPins[sGE], HIGH);
digitalWrite(theTrack->lampPins[sRW], LOW);
digitalWrite(theTrack->lampPins[sRE], LOW);
break;
case WESTBOUND_DEPARTS:
case WESTBOUND_ENTERED:
digitalWrite(theTrack->lampPins[sGW], LOW);
digitalWrite(theTrack->lampPins[sGE], HIGH);
digitalWrite(theTrack->lampPins[sRW], HIGH);
digitalWrite(theTrack->lampPins[sRE], LOW);
break;
case EASTBOUND_DEPARTS:
case EASTBOUND_ENTERED:
digitalWrite(theTrack->lampPins[sGW], HIGH);
digitalWrite(theTrack->lampPins[sGE], LOW);
digitalWrite(theTrack->lampPins[sRW], LOW);
digitalWrite(theTrack->lampPins[sRE], HIGH);
break;
case DEADLOCK: //both ends approached simultaneously; shouldn't happen often, but long de lays() increase the risk
digitalWrite(theTrack->lampPins[sGW], LOW);
digitalWrite(theTrack->lampPins[sGE], LOW);
digitalWrite(theTrack->lampPins[sRW], HIGH);
digitalWrite(theTrack->lampPins[sRE], HIGH);
break;
}
}
# define LAMPTIME 266 //... life very short
// just for TRACK 1 now. loop it over N tracks
void setPinModes() {
for (byte ii = 0; ii < 2; ii++)
pinMode(track[CEN].detPins[ii], INPUT_PULLUP);
for (byte ii = 0; ii < 4; ii++)
pinMode(track[CEN].lampPins[ii], OUTPUT); // Signal green Center West
}
// also TRACK 1 only
void lampTest() {
for (byte ii = 0; ii < 4; ii++) {
digitalWrite(track[CEN].lampPins[ii], HIGH);
delay(LAMPTIME);
digitalWrite(track[CEN].lampPins[ii], LOW);
}
delay(LAMPTIME * 4);
}
WEST EAST