EthicsComputerCourses
Join training +91 90532 10052

Digital Output: LEDs & Traffic Lights

IoT & Arduino · Lesson 10 of 29 Beginner 6 min read Updated

By the end of this lesson you will be able to wire LEDs to any digital pin, build a traffic light that runs through its colours with correct timing, and control a row of LEDs with an array and a loop. You will also learn the difference between a pin that gives current and a pin that takes it.

Digital output means a pin can be in only two states: HIGH (5 V on an UNO) or LOW (0 V). It is like a light switch on your wall: on or off, nothing in between.

Step 1: One external LED

First, move from the built-in L LED to an LED on the breadboard. Unplug the USB cable before wiring.

PartPin or legConnects to
ArduinoD12470 Ω resistor, leg 1
470 Ω resistorLeg 2Red LED anode (long leg)
Red LEDCathode (short leg)Arduino GND (through the - rail)

The resistor limits the current to about 6 mA, safely below the UNO R4's 8 mA pin limit, as you worked out in Ohm's Law & Power.

C++
const int RED_PIN = 12;

void setup() {
  pinMode(RED_PIN, OUTPUT);
  Serial.begin(9600);
  while (!Serial && millis() < 3000) { }
}

void loop() {
  digitalWrite(RED_PIN, HIGH);
  Serial.println("red ON");
  delay(500);
  digitalWrite(RED_PIN, LOW);
  Serial.println("red OFF");
  delay(500);
}
Output
red ON
red OFF
red ON
red OFF

After uploading, the red LED should flash twice per second, and the monitor shows a matching line for each change. If the LED stays dark, check that the long leg faces the resistor.

Step 2: Wire the traffic light

Add two more LEDs. Each LED gets its own resistor and its own pin.

PartPin or legConnects to
Red LED + 470 ΩResistor to D12, LED cathode to GNDStop light
Yellow LED + 470 ΩResistor to D11, LED cathode to GNDWait light
Green LED + 470 ΩResistor to D10, LED cathode to GNDGo light
ArduinoGNDBreadboard - rail, shared by all three cathodes

All three cathodes can share the same GND rail. Do not try to share one resistor between three LEDs: each LED needs its own.

Step 3: Program the sequence

A simple traffic signal, like the one at a crossing in Lucknow, goes red, then green, then yellow, then back to red. A helper function sets all three lights at once, which keeps the main loop short and readable:

C++
const int RED_PIN = 12;
const int YELLOW_PIN = 11;
const int GREEN_PIN = 10;

void setLights(bool red, bool yellow, bool green) {
  digitalWrite(RED_PIN, red ? HIGH : LOW);
  digitalWrite(YELLOW_PIN, yellow ? HIGH : LOW);
  digitalWrite(GREEN_PIN, green ? HIGH : LOW);
}

void setup() {
  pinMode(RED_PIN, OUTPUT);
  pinMode(YELLOW_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  Serial.begin(9600);
  while (!Serial && millis() < 3000) { }
}

void loop() {
  setLights(true, false, false);
  Serial.println("RED: stop (5 s)");
  delay(5000);

  setLights(false, false, true);
  Serial.println("GREEN: go (4 s)");
  delay(4000);

  setLights(false, true, false);
  Serial.println("YELLOW: get ready to stop (1 s)");
  delay(1000);
}
Output
RED: stop (5 s)
GREEN: go (4 s)
YELLOW: get ready to stop (1 s)
RED: stop (5 s)
GREEN: go (4 s)
YELLOW: get ready to stop (1 s)

One full cycle takes 5 + 4 + 1 = 10 seconds. bool is a type that holds true or false. The expression red ? HIGH : LOW means "if red is true, use HIGH, otherwise LOW".

Step 4: Many LEDs with an array

Writing pinMode ten times is boring and error-prone. An array stores many values under one name, like the numbered seats in a railway coach. You reach each seat with an index that starts at 0.

This "running light" lights the three LEDs one after another, then runs back, like the lights on a festive decoration:

C++
const int pins[] = {10, 11, 12};
const int COUNT = 3;

void setup() {
  for (int i = 0; i < COUNT; i++) {
    pinMode(pins[i], OUTPUT);
  }
  Serial.begin(9600);
  while (!Serial && millis() < 3000) { }
}

void showOnly(int index) {
  for (int i = 0; i < COUNT; i++) {
    digitalWrite(pins[i], i == index ? HIGH : LOW);
  }
  Serial.print("LED on pin ");
  Serial.println(pins[index]);
  delay(300);
}

void loop() {
  for (int i = 0; i < COUNT; i++) {        // forwards: 0, 1, 2
    showOnly(i);
  }
  for (int i = COUNT - 2; i > 0; i--) {    // backwards: 1 (skip the ends)
    showOnly(i);
  }
}
Output
LED on pin 10
LED on pin 11
LED on pin 12
LED on pin 11
LED on pin 10
LED on pin 11
LED on pin 12
LED on pin 11

The backward loop skips both end LEDs, so the ends do not light twice in a row. With three LEDs it only visits index 1. Add more pins to the array and change COUNT, and the same code runs a longer chain.

Sourcing and sinking

So far each pin sources current: it pushes current out through the LED to GND, so HIGH means on. A pin can also sink current: connect the LED from 5V, through the resistor, into the pin. Then LOW means on, because current flows into the pin when it is at 0 V.

WiringLED on whenOften used for
Pin → resistor → LED → GND (sourcing)Pin is HIGHMost beginner circuits
5V → resistor → LED → pin (sinking)Pin is LOWSome modules, relay boards and LED displays

This is why some modules are called active LOW. Neither way is wrong, but your code must match your wiring. The same 8 mA limit applies in both directions.

Common mistakes

  • Forgetting pinMode(pin, OUTPUT). The pin stays an input, and the LED glows very dimly or not at all.
  • One resistor shared by several LEDs in parallel. The brightness becomes uneven and one LED can take most of the current. Use one resistor per LED.
  • Array index out of range. pins[3] in a three-element array reads random memory. Valid indexes are 0, 1 and 2.
  • Mixing up active HIGH and active LOW wiring and code.

Key points

  • Digital outputs are HIGH or LOW; digitalWrite switches them after pinMode(pin, OUTPUT).
  • Every LED needs its own series resistor; 470 Ω keeps an UNO R4 pin within its 8 mA limit.
  • Helper functions such as setLights() keep sequences readable.
  • Arrays and for loops control many pins with little code; indexes start at 0.
  • A pin can source (HIGH = on) or sink (LOW = on) current; match code to wiring.

Exercise

Add a pedestrian signal to the traffic light: a second green LED on pin 9 that is ON only while the main signal is RED. Print a line such as RED: stop (5 s), walk ON for each step. What is the full cycle time?

Show solution
C++
const int RED_PIN = 12;
const int YELLOW_PIN = 11;
const int GREEN_PIN = 10;
const int WALK_PIN = 9;

void setLights(bool red, bool yellow, bool green) {
  digitalWrite(RED_PIN, red ? HIGH : LOW);
  digitalWrite(YELLOW_PIN, yellow ? HIGH : LOW);
  digitalWrite(GREEN_PIN, green ? HIGH : LOW);
  digitalWrite(WALK_PIN, red ? HIGH : LOW);   // walk only while cars stop
}

void setup() {
  const int all[] = {RED_PIN, YELLOW_PIN, GREEN_PIN, WALK_PIN};
  for (int i = 0; i < 4; i++) pinMode(all[i], OUTPUT);
  Serial.begin(9600);
  while (!Serial && millis() < 3000) { }
}

void loop() {
  setLights(true, false, false);
  Serial.println("RED: stop (5 s), walk ON");
  delay(5000);
  setLights(false, false, true);
  Serial.println("GREEN: go (4 s), walk OFF");
  delay(4000);
  setLights(false, true, false);
  Serial.println("YELLOW: get ready (1 s), walk OFF");
  delay(1000);
}
Output
RED: stop (5 s), walk ON
GREEN: go (4 s), walk OFF
YELLOW: get ready (1 s), walk OFF

The pedestrian light simply follows the red light. The cycle time is still 5 + 4 + 1 = 10 seconds.

Quick Quiz

1. What voltage does a HIGH digital output give on an Arduino UNO?

2. In the array {10, 11, 12}, what is pins[0]?

3. An LED is wired from 5V through a resistor into a pin. When does it light?

4. Why should each LED have its own resistor?

Learn IoT & Arduino with a mentor

Free lessons get you started. Our IoT & Embedded Systems training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call