/*
railraod crossing lights with different blink pattern and smoothed to imitate incandescent light bulbs
https://forum.arduino.cc/t/2-pushbutton-on-off/1293385/23
https://youtu.be/k_Dbmhv0Nbg
2024-08-21 by noiasca - Version1 - the red lights are on at the same time at 50%
*/
class Light {
protected:
const uint8_t pinWhite; // GPIO for white output
const uint8_t pinRedA; // GPIO for red output
const uint8_t pinRedB; // GPIO for red output
uint32_t previousMillis = 0; // time management
uint8_t dimm = 0; // actual brightness level
const uint8_t interval = 2; // incandescent interval for smooth switch on / switch off
enum Requested {WHITE, RED} requested; // what face should be shown
enum Phase {
WHITE_UP, // the white LED gets brighter
WHITE_DOWN, // the white LED gets darker
WHITE_PAUSE, // white LED is off ... we accept the phase change to "RED"
A_UP, // only the left red LED gets brighter
A_DOWN_B_UP, // left darker - right brighter
A_UP_B_DOWN, // left brighter - right darker - we accept the phase change to "WHITE"
B_DOWN // but we still need to dimm down the right LED before we go back to WHITE_UP
} phase; // current internal phase (state)
public:
Light(const uint8_t pinWhite, const uint8_t pinRedA, const uint8_t pinRedB) : pinWhite(pinWhite), pinRedA(pinRedA), pinRedB(pinRedB) {}
void red() {
requested = RED;
}
void white() {
requested = WHITE;
}
void begin() {
pinMode(pinWhite, OUTPUT);
pinMode(pinRedA, OUTPUT);
pinMode(pinRedB, OUTPUT);
white();
}
void update(uint32_t currentMillis = millis()) {
switch (phase) {
case WHITE_UP :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 255)
phase = WHITE_DOWN; // change phase
else
dimm++;
analogWrite(pinWhite, dimm);
}
break;
case WHITE_DOWN:
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 0)
phase = WHITE_PAUSE; // change phase
else
dimm--;
analogWrite(pinWhite, dimm);
}
break;
case WHITE_PAUSE:
if (currentMillis - previousMillis > 500) { // white is dark for a longer period
previousMillis = currentMillis;
phase = WHITE_UP; // change phase
}
if (requested == RED) phase = A_UP; // or start with red phase
break;
case A_UP :
if (currentMillis - previousMillis > 2) {
previousMillis = currentMillis;
if (dimm == 255)
phase = A_DOWN_B_UP; // now as A will get full power - we can start with B also in the next step
else
dimm++;
analogWrite(pinRedA, dimm);
}
break;
case A_DOWN_B_UP :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 0)
if (requested == WHITE)
phase = B_DOWN; // A is off, so next step is to switch off B
else
phase = A_UP_B_DOWN; // default is we stay in red blinking but other phase
else
dimm--;
analogWrite(pinRedA, dimm);
analogWrite(pinRedB, 255 - dimm);
}
break;
case A_UP_B_DOWN :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 255)
phase = A_DOWN_B_UP; // we stay in red blinking but other phase
else
dimm++;
analogWrite(pinRedA, dimm);
analogWrite(pinRedB, 255 - dimm);
}
break;
case B_DOWN : // last phase before we can go back to white
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 255) {
phase = WHITE_UP;
dimm = 0; // white should start with 0
break;
}
else
dimm++;
analogWrite(pinRedB, 255 - dimm);
}
break;
}
}
};
Light light(9, 10, 6); // PWM Pins on Uno, Nano, Mini are 3, 5, 6, 9, 10, 11
void setup() {
Serial.begin(115200);
Serial.println("x");
light.begin();
//light.white(); // an action
//light.red(); // another action
}
void loop() {
light.update();
int in = Serial.read();
switch (in) {
case -1 : break;
case 'r': light.red(); break;
case 'w': light.white(); break;
}
}
//