/*
Forum: https://forum.arduino.cc/t/changing-led-state-with-ir-sensors/1434325/2
Wokwi: https://wokwi.com/projects/457942657328082945
Simple Signal Light, both directions, considering that the release my be triggered several times while the train
passes the end of block
starts with green signal
press red or green button (train enters block from LEFT or RIGHT)
signal switches to red
press green or red button (train starts leaving block to the RIGHT or to the LEFT)
release green or red button for at least minReleaseTime (train hast completely left the block)
signal switches to green again
If the button that signalizes the leaving of a block is pressed again within minReleaseTime the block will
be considered to be still occupied.
ec2021
*/
constexpr byte redPin {12};
constexpr byte greenPin {11};
constexpr byte blockLeftPin {7};
constexpr byte blockRightPin {6};
constexpr unsigned long minReleaseTime {1000}; // The time that is required after a release to change state back to FREE
enum class BLOCK {FREE, OCCUPIED, INTERRUPTED};
BLOCK blockState = BLOCK::FREE;
unsigned long releaseTime;
class blockSensor {
private:
byte pin;
byte state = HIGH;
byte lastState = HIGH;
unsigned long lastChange = 0;
boolean changed() {
byte actState = digitalRead(pin);
if (actState != lastState) {
lastChange = millis();
lastState = actState;
}
if (actState != state && millis() - lastChange > 30) {
state = actState;
return true;
}
return false;
};
public:
void init(byte Pin) {
pin = Pin;
pinMode(pin, INPUT_PULLUP);
};
boolean pressed() {
if (changed()) {
return !state;
} else {
return false;
}
};
boolean released() {
if (changed()) {
return state;
} else {
return false;
}
};
};
blockSensor blockLeft, blockRight;
blockSensor *blockPtr;
void setup() {
Serial.begin(115200);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
blockLeft.init(blockLeftPin);
blockRight.init(blockRightPin);
signalToGreen();
Serial.println("Start");
}
void loop() {
stateMachine();
}
void signalToRed() {
digitalWrite(redPin, HIGH);
digitalWrite(greenPin, LOW);
}
void signalToGreen() {
digitalWrite(redPin, LOW);
digitalWrite(greenPin, HIGH);
}
void stateMachine() {
switch (blockState) {
case BLOCK::FREE:
if (blockLeft.pressed()) {
blockOccupied("LEFT");
blockPtr = &blockRight;
}
if (blockRight.pressed()) {
blockOccupied("RIGHT");
blockPtr = &blockLeft;
}
break;
case BLOCK::OCCUPIED:
if (blockPtr->released()) {
Serial.println("Sensor released ...");
releaseTime = millis();
blockState = BLOCK::INTERRUPTED;
}
break;
case BLOCK::INTERRUPTED:
if (millis() - releaseTime >= minReleaseTime) {
Serial.println("Train left block ...");
signalToGreen();
blockState = BLOCK::FREE;
}
if (blockPtr->pressed()) {
//if the sensor triggers again let's go back to occupied
Serial.println("Oops, train still in block ...");
blockState = BLOCK::OCCUPIED;
}
break;
}
}
void blockOccupied(char *msg) {
Serial.print("Train entered block from ");
Serial.println(msg);
signalToRed();
blockState = BLOCK::OCCUPIED;
}