/*
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-25 by noiasca
code in thread
*/
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 = 5; // incandescent interval for smooth switch on / switch off
const uint16_t intervalWhite = 800; // on and off time for white lamp
const uint16_t intervalRed = 200; // on time for red lamps
const uint8_t pwmtable[16] {0, 2, 3, 4, 6, 8, 11, 16, 23, 32, 45, 64, 90, 128, 181, 255};
enum Requested {WHITE, RED} requested; // what face should be shown
enum Phase {
WHITE_UP, // the white LED gets brighter
WHITE_ON,
WHITE_DOWN, // the white LED gets darker
WHITE_OFF, // white LED is off ... we accept the phase change to "RED"
A_UP, // only the left red LED gets brighter
A_ON,
A_DOWN,
B_UP,
B_ON,
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()) {
//Serial.println(phase);
switch (phase) {
case WHITE_UP :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 15)
phase = WHITE_ON; // change phase
else
dimm++;
analogWrite(pinWhite, pwmtable[dimm]);
}
break;
case WHITE_ON :
if (currentMillis - previousMillis > intervalWhite) {
previousMillis = currentMillis;
phase = WHITE_DOWN;
}
break;
case WHITE_DOWN:
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 0)
phase = WHITE_OFF; // change phase
else
dimm--;
analogWrite(pinWhite, pwmtable[dimm]);
}
break;
case WHITE_OFF:
if (currentMillis - previousMillis > intervalWhite) { // 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 > interval) {
previousMillis = currentMillis;
if (dimm == 15)
phase = A_ON; // now as A will get full power - we can start with B also in the next step
else
dimm++;
analogWrite(pinRedA, pwmtable[dimm]);
}
break;
case A_ON :
if (currentMillis - previousMillis > intervalRed) {
previousMillis = currentMillis;
phase = A_DOWN;
}
break;
case A_DOWN :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 0) {
if (requested == WHITE)
phase = WHITE_UP; // A is off, so it is save to start white
else
phase = B_UP; // otherwise start the other LED
}
else
dimm--;
analogWrite(pinRedA, dimm);
//Serial.println(dimm); //just testing
}
break;
case B_UP :
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 15)
phase = B_ON; // next phase down
else
dimm++;
analogWrite(pinRedB, pwmtable[dimm]);
}
break;
case B_ON :
if (currentMillis - previousMillis > intervalRed) {
previousMillis = currentMillis;
phase = B_DOWN;
}
break;
case B_DOWN : // last phase before we can go back to white
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (dimm == 0) {
if (requested == WHITE)
phase = WHITE_UP; // either switch to WHITE
else
phase = A_UP; // otherwise start the other LED
}
else
dimm--;
analogWrite(pinRedB, pwmtable[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;
}
}
//