Introduction
After blinking your first LED on Arduino, what's next? Before moving on to more complex concepts, you can design a real-world application for controlling LEDs using a microcontroller by simulating traffic lights.
This is a beginner-friendly tutorial on simulating traffic lights using Arduino. It also adds complexity by including a countdown timer using a 7-segment display.
At the end of the tutorial, you will be able to control three LEDs to mimic traffic lights. Additionally, you will have an understanding of what a 7-segment display is and how to program it with a microcontroller.
Prerequisites
This article makes use of the Wokwi simulator for designing. The same design concepts can be applied to any other microcontroller simulator of your choice, like Tinkercad or Fritzing. If you have the components, do well to connect them physically.
The following components are used in this tutorial:
- Arduino UNO
- Breadboard
- Three LEDs (red, yellow, and green)
- Four 200-ohm resistors
- A 7-segment display
- Jumper cables
The tutorial also assumes a basic understanding of how to use a breadboard.
Circuit Design
The circuit you will be designing in this tutorial will consist of two major parts:
- The traffic light control
- Countdown timer display
Connecting the LEDs
The traffic light control is made up of three LEDs (red, yellow, and green). You connect each LED in series with a 200-ohm resistor. The resistor limits the current flowing to the LED, thereby preventing the LED from burning out. You should note that it doesn't matter if you place the resistor before or after the LED.
To construct the circuit shown above on a breadboard, proceed with the following steps:
- Connect each LED across the central gap of the breadboard so that the terminals of the LED are on opposite sides of the breadboard.
- Connect the anode (the longer leg) of each LED to a digital output (PWM) pin on the Arduino. Specifically, the red, yellow, and green LEDs are connected to digital pins 4, 3, and 2, respectively.
- Connect one end of a resistor to the cathode (the shorter leg) of each LED. Connect the other end of the resistor to the negative (ground) rail of the breadboard.
- Finally, connect the negative rail of the breadboard to one of the Arduino’s ground (GND) pins.
Understanding the 7-Segment Display
A 7-segment display is an electronic component that is primarily used to display digits (0-9). As the name implies, a 7-segment display consists of seven different LEDs. Each LED on a 7-segment display represents a segment and is labelled from a through g. The segments of a 7-segment display are arranged to form digits by illuminating various combinations of segments, each of which can be illuminated independently.
There are 10 pins in a standard 7-segment display. These include:
- Pins a to g: These pins control the LEDs in individual segments.
- The Decimal Point (DP) pin: This pin controls the optional decimal point segment.
- Two common pins: The common pins are the shared connection for all the segments in the display. These are either connected to ground (in common cathode displays) or to a voltage source (in common anode displays).
7-segment displays are classified according to the common terminal type. There are two main types of 7-segment displays:
- The Common Cathode (CC).
- The Common Anode (CA).
The Common Cathode (CC)
In the common cathode 7-segment display, all the cathodes of the LEDs in each segment are connected to a LOW logic level (logic "0"). This requires you to connect either or both of the common pins to ground. Individual segments are illuminated by applying a HIGH to the signal pins. A Common Cathode 7-segment display is active HIGH.
Truth Table for Common Cathode 7-Segment Display
This tutorial makes use of the Common Cathode 7-segment display. A truth table showing the logic levels of individual segments corresponding to each decimal digit is as follows:
Digit | a | b | c | d | e | f | g |
---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
3 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
4 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
5 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
6 | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
7 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
8 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
9 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
The Common Anode (CA)
In the common anode 7-segment display, all the anodes of the LEDs in each segment are connected to a HIGH logic level (logic "1"). This implies that you connect the common pins to a voltage source. Individual segments are illuminated by applying a LOW to the signal pins. A Commode Anode display is active LOW.
Connecting the 7-segment Display
In this tutorial, you use the 7-segment display to display a countdown timer during the traffic light phases. To connect the 7-segment display, follow these steps:
- Insert the 7-segment display across the central gap of the breadboard. The top five pins of the display are connected in one half of the breadboard, the bottom five pins are connected in the other half.
- Recall that this tutorial uses a Common Cathode (CC) 7-segment display. This means that the common pins are connected to ground. Connect a 200-ohm resistor from the common pin to the negative rail of the breadboard (which should already be connected to the Arduino's GND pin). This resistor limits the current flowing to the display and protects the LEDs in the display.
- Connect each of the segment pins (a through g) of the display to separate digital output pins on the Arduino. The table below shows the mapping between the segment pins and the corresponding Arduino pins:
7-Segment Display Pin | Arduino Pin |
---|---|
A | D12 |
B | D13 |
C | D5 |
D | D6 |
E | D7 |
F | D11 |
G | D10 |
The complete circuit should look like this:
Traffic Light Phases
The traffic light simulation is a continuous cycle consisting of four different phases. Each phase runs for a specific period, and a countdown is displayed to indicate the time remaining in each phase.
- Red Phase (STOP): This phase mimics the red traffic light, signalling drivers to stop. In the stop phase, you turn on the red LED only. The countdown for this phase begins from 9 and decreases to 4. When the countdown reaches 3, the simulation transitions into the “GET-READY” phase.
- Red-Yellow Phase (GET READY): This phase mimics the "get-ready" traffic signal, signalling drivers that the lights are about to turn green. In this phase, you turn on both the red and yellow LEDs. The duration of this phase is 3 seconds, covering the last 3 seconds of the red phase countdown.
- Green Phase (GO): This phase mimics the green light, signalling drivers to proceed. In the green phase, you turn on the green LED only. The countdown is reset, restarting from 9 and decreasing to 4. When the countdown reaches 3, the simulation begins the “CAUTION” phase.
- Yellow Phase (CAUTION): This phase mimics the yellow traffic light, warning drivers that the lights are about to turn red. In the caution phase, you turn on the yellow LED only. The duration of this phase is 3 seconds, covering the last 3 seconds of the green phase countdown
Arduino Code
The software is a core aspect of any microcontroller-based project. It is where you describe the behaviour of the hardware components connected to the microcontroller.
In this section, you will develop the Arduino sketch responsible for simulating the behaviour of the traffic lights and the countdown display. You will work on the logic for controlling red, yellow, and green LEDs, the traffic phase timing logic, and displaying the countdown.
Pin Configuration
To improve code readability and maintainability, it’s best practice to define descriptive variable names for the pins you're using. This allows you to reference each pin by its function, rather than by its number.
In the sketch.ino
, begin by defining the three digital output pins used by the red, yellow, and green LEDs. Then, you define each of the seven digital output pins connected to the 7-segment display. Finally, create an array to group the pins used by the 7-segment display:
const int RED = 4;
const int YELLOW = 3;
const int GREEN = 2;
const int a = 12;
const int b = 13;
const int c = 5;
const int d = 6;
const int e = 7;
const int f = 11;
const int g = 10;
const int segmentPins[7] = {a, b, c, d, e, f, g};
Timing Constants
Next, you create variables storing the duration of each traffic light phase. Given that you are only using one 7-segment display, the maximum digit that can be displayed is 9. The “STOP” and “GO” phases will last for 9 seconds, and the two transition phases (“GET-READY” and “CAUTION”) will each last for 3 seconds. At your discretion, you can change the duration.
Add the following lines to the sketch.ino
file:
//...
const int DELAY_RED = 9;
const int DELAY_YELLOW = 3;
const int DELAY_GREEN = 9;
7-Segment Display Truth Table Array
You learned earlier that to display a digit on the 7-segment display, each segment (labelled a through g) is turned ON (logic level 1
) and OFF (logic level 0
) in a particular combination. A truth table is used to show the logic levels (0
and 1
) of each segment for a particular digit.
To implement this, you create an array to store the various combinations of logic levels used for displaying digits 0 through 9. The array digitMap
is a two-dimensional array where each row defines the logic levels for a particular digit, and each column represents a specific segment. The array has 10
rows (one for digit 0 to 9), and 7
columns (one for each segment a to g). The array digitMap
stores the truth table for the 7-segment display. This means that you can simply reference digitMap[digit][segment]
to determine what segments to activate when displaying a number.
Add the following lines to the sketch.ino
file:
//...
const bool digitMap[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 0, 0, 1, 1} // 9
};
The setup
Function
The setup
function in every Arduino sketch runs once when the microcontroller is powered on or reset. In the setup
function, you perform initialization tasks, such as setting pin modes, configuring peripherals, or initializing serial communication.
In the setup
function for this project, you perform the following:
- You configure the pins used by the red, yellow, and green LEDs as
OUTPUT
, so that the Arduino can send voltage signals to turn them ON and OFF. - You initialize the 7-segment display pins as
OUTPUT
, allowing you to control each segment. - You set the baud rate of the microcontroller to enable serial communication, which is useful for debugging.
Create the setup
function in the sketch.ino
file with the following contents:
//...
void setup() {
// Traffic lights
pinMode(RED, OUTPUT);
pinMode(YELLOW, OUTPUT);
pinMode(GREEN, OUTPUT);
// 7-segment display
for (int i = 0; i < 7; i++) {
pinMode(segmentPins[i], OUTPUT);
}
Serial.begin(9600);
}
Helper Functions
Before jumping into the loop
function, you should create a couple of functions that handle certain tasks. You do this to make the logic in the main loop readable and modular.
The helper functions in this project include:
-
Traffic light control functions: The
red_light()
,red_yellow_light()
,yellow_light()
, andgreen_light()
functions set the appropriate LEDs ON or OFF for their respective traffic phase. -
7-segment display functions: The
display()
function shows a digit on the display, and theclearDisplay()
function turns off all segments.
Add the following lines to the sketch.ino
file:
//...
void red_light() {
digitalWrite(RED, HIGH);
digitalWrite(YELLOW, LOW);
digitalWrite(GREEN, LOW);
}
void red_yellow_light() {
digitalWrite(RED, HIGH);
digitalWrite(YELLOW, HIGH);
digitalWrite(GREEN, LOW);
}
void yellow_light() {
digitalWrite(RED, LOW);
digitalWrite(YELLOW, HIGH);
digitalWrite(GREEN, LOW);
}
void green_light() {
digitalWrite(RED, LOW);
digitalWrite(YELLOW, LOW);
digitalWrite(GREEN, HIGH);
}
void display(int num) {
if (num < 0 || num > 9) {
clearDisplay();
return;
}
for (int i = 0; i < 7; i++) {
digitalWrite(segmentPins[i], digitMap[num][i] ? HIGH : LOW);
}
Serial.print("Countdown: ");
Serial.println(num);
}
void clearDisplay() {
for (int i = 0; i < 7; i++) {
digitalWrite(segmentPins[i], LOW);
}
}
In the red_light()
, red_yellow_light()
, yellow_light()
, and green_light()
functions, you set the state of red, yellow, and green LEDs for their respective traffic phase. The digitalWrite
function is used to send either a HIGH
(about 5V) or a LOW
(0V) to the specified pin. A HIGH
signal will turn on the LED, and a LOW
signal will turn off the LED.
The display()
function is responsible for displaying a particular digit on the 7-segment display. The function has a parameter num
, which is an integer specifying the digit to be displayed. The display()
function is written such that it prevents you from manually setting each segment anytime you want to update a digit.
The display()
function operates as follows when called with an integer argument:
- Firstly, it verifies if the value of
num
is within the valid range (0
to9
). If the value ofnum
is less than0
or greater than9
, the display is cleared usingclearDisplay()
and the function exits. - If the value of
num
is valid. The function loops through each 7-segment. Each segment is turned ON(HIGH
) or OFF(LOW
) based on the logic levels for the particular digit (num
) specified by thedigitMap
array. ThedigitalWrite(segmentPins[i], digitMap[num][i] ? HIGH : LOW);
line achieves that.
The clearDisplay()
function turns OFF(LOW
) all segments, and displays nothing on the 7-segment display.
Main Loop
The code in the loop()
function is run repeatedly by the microcontroller. The loop()
function is where you define the core logic of the traffic light simulation.
In this project, the loop()
function consists of two separate loops, corresponding to two stages:
-
The STOP Stage: In the first stage, you begin the
for
loop from the value specified inDELAY_RED
(9
seconds) to1
, with a-1
decrement. The red LED is turned ON for the "STOP" phase, and in the last3
seconds of the countdown (DELAY_YELLOW
), the red and yellow LEDs are turned ON for the "GET-READY" phase. -
The GO Stage: In the second stage, you start the
for
loop from the value specified inDELAY_GREEN
(9
seconds) to1
, with a-1
decrement. The green LED is turned ON for the "GO" phase, and in the last3
seconds of the countdown(DELAY_YELLOW
), the yellow LED is turned on for the "CAUTION" phase.
In both stages, the display()
function displays the countdown number on the 7-segment, and each iteration pauses for 1 second (delay(1000)
), so that the countdown updates every second.
Create the loop()
function in the sketch.ino
file, with the following contents:
//...
void loop() {
// STOP PHASE
for (int i = DELAY_RED; i > 0; i--) {
if (i <= DELAY_YELLOW) {
// RED/YELLOW TRANSITION
red_yellow_light();
display(i);
} else {
// RED LIGHT
red_light();
display(i);
}
delay(1000);
}
// GO PHASE
for (int i = DELAY_GREEN; i > 0; i--) {
if (i <= DELAY_YELLOW) {
// YELLOW TRANSITION
yellow_light();
display(i);
} else {
// GREEN LIGHT
green_light();
display(i);
}
delay(1000);
}
}
Final Code
After combining all the logic discussed above, the final code in the sketch.ino
is:
const int RED = 4;
const int YELLOW = 3;
const int GREEN = 2;
const int DELAY_RED = 9;
const int DELAY_YELLOW = 3;
const int DELAY_GREEN = 9;
const int a = 12;
const int b = 13;
const int c = 5;
const int d = 6;
const int e = 7;
const int f = 11;
const int g = 10;
const bool digitMap[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 0, 0, 1, 1} // 9
};
const int segmentPins[7] = {a, b, c, d, e, f, g};
void setup() {
// Traffic lights
pinMode(RED, OUTPUT);
pinMode(YELLOW, OUTPUT);
pinMode(GREEN, OUTPUT);
// 7-segment display
for (int i = 0; i < 7; i++) {
pinMode(segmentPins[i], OUTPUT);
}
Serial.begin(9600);
}
void loop() {
// STOP PHASE
for (int i = DELAY_RED; i > 0; i--) {
if (i <= DELAY_YELLOW) {
// RED/YELLOW TRANSITION
red_yellow_light();
display(i);
} else {
// RED LIGHT
red_light();
display(i);
}
delay(1000);
}
// GO PHASE
for (int i = DELAY_GREEN; i > 0; i--) {
if (i <= DELAY_YELLOW) {
// YELLOW TRANSITION
yellow_light();
display(i);
} else {
// GREEN LIGHT
green_light();
display(i);
}
delay(1000);
}
}
void red_light() {
digitalWrite(RED, HIGH);
digitalWrite(YELLOW, LOW);
digitalWrite(GREEN, LOW);
}
void red_yellow_light() {
digitalWrite(RED, HIGH);
digitalWrite(YELLOW, HIGH);
digitalWrite(GREEN, LOW);
}
void yellow_light() {
digitalWrite(RED, LOW);
digitalWrite(YELLOW, HIGH);
digitalWrite(GREEN, LOW);
}
void green_light() {
digitalWrite(RED, LOW);
digitalWrite(YELLOW, LOW);
digitalWrite(GREEN, HIGH);
}
void display(int num) {
if (num < 0 || num > 9) {
clearDisplay();
return;
}
for (int i = 0; i < 7; i++) {
digitalWrite(segmentPins[i], digitMap[num][i] ? HIGH : LOW);
}
Serial.print("Countdown: ");
Serial.println(num);
}
void clearDisplay() {
for (int i = 0; i < 7; i++) {
digitalWrite(segmentPins[i], LOW);
}
}
Simulation in Wokwi
Physical Connection
If you have access to the components, I encourage you to replicate the project on a breadboard. The connections are the same as in the simulation, so you won't need to change the code.
Here is what my final setup looked like:
Conclusion
By following this tutorial, you built a complete traffic light simulation with a countdown timer using an Arduino and a 7-segment display. You configured digital outputs to control LEDs representing traffic lights and used a truth table approach to drive the 7-segment display dynamically. You also explored how traffic light phases operate in practice and simulated your design using Wokwi, with the option to replicate it physically on a breadboard.
Consider extending this system by using multiple 7-segment displays, using an LCD, or implementing multi-intersection traffic control with ultrasonic sensors. The possibilities are limitless—the core concepts you've applied here can serve as a springboard into more advanced embedded systems projects.
References
Electronics Tutorials – 7 Segment Display Tutorial
Sun Founder Docs – 7-Segment Display (UNO/Mega Kit)
Components101 – 7-Segment Display: Pinout, Working & Datasheet
Top comments (0)