/*
A traffic light version 4
Operating mode is saved as an enum
Current light is also kept in an enum
The traffic light does not block, so we can add an LCD
which is also updated periodically.
Djordje Herceg and Milan Vidaković, 9.4.2024.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 16, 2);
#define LED1 18
#define LED2 17
#define LED3 16
#define KEY1 39 // VN pin
int leds[] = {LED1, LED2, LED3};
// Current light
enum Light {Red, Yellow, Green};
Light light = Green;
// Current operating mode
enum Mode {Mode_TrafficLight, Mode_BlinkingYellow, Mode_Off};
Mode mode = Mode_TrafficLight;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("A traffic light with enums example V4");
for (int i = 0; i < 3; i++){
pinMode(leds[i], OUTPUT);
}
// The VN pin has no builtin pullup resistor, so one was added in the schematic
pinMode(KEY1, INPUT);
// LCD initialization
LCD.init();
LCD.backlight();
LCD.setCursor(0, 0);
printMode();
}
void loop() {
// call the 'loop' functions for both 'processes'
buttonLoop();
trafficLightLoop();
delay(3);
}
void buttonLoop() {
static unsigned long mils = millis();
static bool oldState = false;
if (millis() - mils > 20) {
mils = millis();
bool newState = !digitalRead(KEY1); // Invert, because LOW when pressed, HIGH when released
if (oldState != newState) {
oldState = newState;
if (newState) {
// reaction to button press
changeMode();
}
}
}
}
void changeMode() {
// turn off all LEDs when changing mode
for (int i = 0; i < 3; i++){
digitalWrite(leds[i], LOW);
}
switch (mode) {
case Mode_TrafficLight:
LCD.backlight();
mode = Mode_BlinkingYellow;
break;
case Mode_BlinkingYellow:
LCD.noBacklight();
mode = Mode_Off;
break;
case Mode_Off:
LCD.backlight();
mode = Mode_TrafficLight;
light = Green;
break;
}
printMode();
}
void printMode() {
LCD.clear();
switch (mode) {
case Mode_TrafficLight:
LCD.print("Traffic light");
break;
case Mode_BlinkingYellow:
LCD.print("Blinking yellow");
break;
case Mode_Off:
LCD.print("Off");
break;
}
}
void trafficLightLoop() {
static unsigned long mils = millis();
switch (mode) {
case Mode_TrafficLight:
if (millis() - mils > 1500) {
mils = millis();
trafficLight();
}
break;
case Mode_BlinkingYellow:
if (millis() - mils > 500) {
mils = millis();
blinkYellow();
}
break;
}
}
void trafficLight() {
// first turn off the current light:
switch (light) {
case Red:
digitalWrite(leds[0], LOW);
light = Yellow;
break;
case Yellow:
digitalWrite(leds[1], LOW);
light = Green;
break;
case Green:
digitalWrite(leds[2], LOW);
light = Red;
break;
}
// then, turn on the next light:
switch (light) {
case Red:
digitalWrite(leds[0], HIGH);
break;
case Yellow:
digitalWrite(leds[1], HIGH);
break;
case Green:
digitalWrite(leds[2], HIGH);
break;
}
}
void blinkYellow() {
static bool isOn = false;
digitalWrite(leds[1], isOn);
isOn = !isOn;
}