7.8 LED Traffic Light

This project recreates a miniature traffic light using three LEDs and the NULA MINI board.
The LEDs change automatically between green, blinking green, orange, red, and red + orange, just like a real traffic light.
This example introduces the concept of a finite state machine (FSM) — a simple but powerful way to control sequential actions in embedded systems.
In this documentation you will learn:
- How to simulate a traffic light sequence with multiple LEDs.
- How to structure your code using a finite state machine (FSM).
- How to use
millis()for non-blocking timing instead ofdelay(). - How to create a blinking LED effect using timing logic.
Hardware required
- 1× Soldered NULA MINI board
- 1× Red LED
- 1× Orange LED
- 1× Green LED
- 3× 330 Ω resistors
- Breadboard
- Jumper wires
- USB-C cable

How it works
A finite state machine (FSM) is a simple programming pattern where the system moves between a set of states — one at a time — based on timing or events.
In this project, the LEDs cycle through the following states:
| State | LEDs ON | Duration |
|---|---|---|
| Green | 🟢 | 5 seconds |
| Blinking Green | 🟢 (blinks) | 3 seconds |
| Orange | 🟠 | 2 seconds |
| Red | 🔴 | 5 seconds |
| Red + Orange | 🔴🟠 | 2 seconds |
After the Red + Orange phase, the light returns to Green and repeats indefinitely.
The blinking green is handled by a separate timer that toggles the LED ON and OFF every 0.4 seconds, while millis() keeps track of how long each phase should last.

Wiring and connections
| Component | NULA MINI Pin | Description |
|---|---|---|
| Green LED | IO2 | Traffic light green signal |
| Orange LED | IO3 | Traffic light orange signal |
| Red LED | IO4 | Traffic light red signal |
| All LED cathodes | GND | Common ground connection |
| 220 Ω resistors | In series with each LED | Limit current for each LED |

Full code
Below is the full example code for this project:
const int LED_GREEN = 4;
const int LED_ORANGE = 3;
const int LED_RED = 2;
// Define the states of the traffic light
enum TrafficState {
GREEN,
GREEN_BLINK,
ORANGE,
RED,
RED_ORANGE
};
TrafficState state = GREEN;
unsigned long lastChange = 0;
unsigned long stateDuration = 0;
// Blinking green timing
bool greenOn = true;
const unsigned long blinkInterval = 400; // 0.4 s blink interval
unsigned long lastBlink = 0;
void setup() {
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_ORANGE, OUTPUT);
pinMode(LED_RED, OUTPUT);
// Start in green state
state = GREEN;
lastChange = millis();
stateDuration = 5000; // stay green for 5 s
}
void loop() {
unsigned long now = millis();
switch (state) {
case GREEN:
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_ORANGE, LOW);
digitalWrite(LED_RED, LOW);
if (now - lastChange >= stateDuration) {
state = GREEN_BLINK;
lastChange = now;
stateDuration = 3000; // blink green for 3 s
}
break;
case GREEN_BLINK:
digitalWrite(LED_ORANGE, LOW);
digitalWrite(LED_RED, LOW);
if (now - lastBlink >= blinkInterval) {
greenOn = !greenOn;
digitalWrite(LED_GREEN, greenOn);
lastBlink = now;
}
if (now - lastChange >= stateDuration) {
state = ORANGE;
lastChange = now;
stateDuration = 2000; // orange for 2 s
}
break;
case ORANGE:
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_ORANGE, HIGH);
digitalWrite(LED_RED, LOW);
if (now - lastChange >= stateDuration) {
state = RED;
lastChange = now;
stateDuration = 5000; // red for 5 s
}
break;
case RED:
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_ORANGE, LOW);
digitalWrite(LED_RED, HIGH);
if (now - lastChange >= stateDuration) {
state = RED_ORANGE;
lastChange = now;
stateDuration = 2000; // red + orange for 2 s
}
break;
case RED_ORANGE:
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_ORANGE, HIGH);
digitalWrite(LED_RED, HIGH);
if (now - lastChange >= stateDuration) {
state = GREEN;
lastChange = now;
stateDuration = 5000; // back to green for 5 s
}
break;
}
}
Full example

Check out the full example code on the link below:
7.8_LED_Traffic_Light.ino
Traffic light simulation using NULA MINI and three LEDs. Demonstrates finite state machines, non-blocking timing, and LED control.