16×2 I²C LCD Display
with Arduino Uno
Connect a 16-character × 2-row LCD display to Arduino using just 4 wires via I²C — no resistors, no complex wiring. Includes 6 live demo examples, full code, and free Wokwi simulation.
Introduction
OverviewIn this project you'll learn how to connect a 16×2 LCD display with I²C module to an Arduino Uno. The I²C interface dramatically reduces wiring — from 12 wires down to just 4 — making it the preferred method for Arduino beginners and professionals alike.
Just 4 Wires
VCC, GND, SDA, SCL — that's all you need
Text Display
Print any string, number, or variable value
Custom Chars
Create heart, smile, degree symbol and more
Scrolling Text
Marquee-style scrolling messages
Sensor Readout
Display live temperature, humidity, light
Digital Clock
Running HH:MM:SS clock using millis()
This tutorial is perfect for:
- Beginners learning Arduino display output
- School and robotics club projects
- IoT sensor monitoring dashboards
- Any project needing a human-readable output
By the end of this guide you'll be able to display text, sensor values, custom icons, scrolling messages, and a working clock — all on a single LCD screen!
Why Use I²C Instead of Standard LCD?
Key ConceptA regular 16×2 LCD requires up to 12 connection wires. The I²C backpack module reduces this to just 4 — a massive simplification, especially for beginners.
- Needs 6–12 data connections
- Uses up most of Arduino's digital pins
- Complex wiring — easy to make mistakes
- No room left for sensors/actuators
- Contrast requires a potentiometer
- Only 4 wires: VCC, GND, SDA, SCL
- Uses only 2 Arduino pins (A4 + A5)
- Simple wiring — hard to get wrong
- Plenty of pins left for your project
- Built-in contrast adjustment via trim pot
The I²C bus supports multiple devices on the same 2 wires. You can have an LCD, RTC module, and OLED all sharing SDA/SCL — each with a unique address like
Components Required
Step 1You need just 2 components (plus wires). All are available as virtual parts in Wokwi — no shopping required!
| # | Component | Purpose | Notes |
|---|---|---|---|
| 01 | Arduino UNO | Main microcontroller | Runs all the code |
| 02 | 16×2 LCD with I²C module | Display output | Backpack address: 0x27 or 0x3F |
| 03 | Jumper wires × 4 | Connections | VCC, GND, SDA, SCL only |
| 04 | USB cable | Power + upload | Wokwi handles this virtually |
Wiring Guide — Only 4 Connections!
Step 2This is the simplest wiring in all of Arduino LCD projects. Connect these 4 wires and you're done:
| LCD I²C Pin | Arduino Pin | Wire Colour | Purpose |
|---|---|---|---|
| VCC | 5V | Red | Power supply |
| GND | GND | Black | Ground reference |
| SDA | A4 | Green | I²C Data line |
| SCL | A5 | Blue | I²C Clock line |
On Arduino UNO, A4 and A5 are the dedicated hardware I²C pins. On Arduino Mega, use pins 20 (SDA) and 21 (SCL) instead.
If your LCD shows only blocks (squares) and no text, the contrast needs adjusting. Turn the small blue trimmer potentiometer on the I²C backpack with a screwdriver until text appears.
Install the Library
Step 3In Wokwi (Recommended — Instant!)
Create a file called
LiquidCrystal I2C
Wokwi downloads this library automatically when the simulation starts!
In Arduino IDE (Physical Hardware)
- Open Arduino IDE → Sketch → Include Library → Manage Libraries
- Search for "LiquidCrystal I2C"
- Install the library by Frank de Brabander
- Also make sure
Wire.h is available (it's built-in)
The Full Arduino Code — 6 Demo Examples
Step 4The sketch automatically cycles through 6 different display examples every 5 seconds. Paste the full code into the
① Libraries, Custom Characters & Variables
/* * 16x2 I2C LCD Display with Arduino * MakeMindz Summer Course | Wokwi Simulation * 6 Demo Examples: Counter, Temp, Custom Chars, * Scrolling, Sensor Data, Clock * I2C Address: 0x27 (or 0x3F on some modules) */ #include <Wire.h> // I2C communication bus #include <LiquidCrystal_I2C.h> // LCD control library // Initialize LCD: address 0x27, 16 columns, 2 rows LiquidCrystal_I2C lcd(0x27, 16, 2); // ── Custom character pixel bitmaps ──────────── // Each byte is one row of 5 pixels (right-aligned) byte heart[8] = { 0b00000,0b01010,0b11111,0b11111,0b11111,0b01110,0b00100,0b00000 }; byte smile[8] = { 0b00000,0b01010,0b01010,0b00000,0b10001,0b01110,0b00000,0b00000 }; byte degree[8] = { 0b00110,0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000 }; byte arrow[8] = { 0b00100,0b01110,0b11111,0b00100,0b00100,0b00100,0b00100,0b00000 }; byte bell[8] = { 0b00100,0b01110,0b01110,0b01110,0b11111,0b00000,0b00100,0b00000 }; // ── State variables ────────────────────────── int counter = 0;
② setup() — Initialise & Splash Screen
void setup() { Serial.begin(9600); lcd.init(); // Start the LCD lcd.backlight(); // Turn on the backlight // Register custom characters (slots 0–4) lcd.createChar(0, heart); lcd.createChar(1, smile); lcd.createChar(2, degree); lcd.createChar(3, arrow); lcd.createChar(4, bell); // Splash screen 1 lcd.clear(); lcd.setCursor(0, 0); lcd.print("I2C LCD Display"); lcd.setCursor(0, 1); lcd.print("Initializing..."); delay(2000); // Welcome message with custom chars lcd.clear(); lcd.setCursor(0, 0); lcd.print("Arduino + LCD"); lcd.setCursor(0, 1); lcd.write(0); // ♥ heart icon lcd.print(" Hello World! "); lcd.write(1); // ☺ smile icon delay(2000); Serial.println("LCD Initialized — I2C address 0x27"); } void loop() { // Auto-cycle through 6 examples every 5 seconds int example = (millis() / 5000) % 6; switch(example) { case 0: displayCounter(); break; case 1: displayTemperature(); break; case 2: displayCustomChars(); break; case 3: displayScrolling(); break; case 4: displaySensorData(); break; case 5: displayClock(); break; } delay(100); }
③ All 6 Display Functions
// ── Example 1: Counter (increments every second) ── void displayCounter() { static unsigned long t = 0; if (millis() - t >= 1000) { t = millis(); counter++; lcd.clear(); lcd.setCursor(0, 0); lcd.print("Counter Display"); lcd.setCursor(0, 1); lcd.print("Count: "); lcd.print(counter); } } // ── Example 2: Temperature in °C and °F ── void displayTemperature() { static unsigned long t = 0; static float temp = 25.5; if (millis() - t >= 1000) { t = millis(); temp += random(-10, 11) / 10.0; // Simulate reading temp = constrain(temp, 0, 50); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Temperature:"); lcd.setCursor(0, 1); lcd.print(temp, 1); lcd.write(2); lcd.print("C "); // °C lcd.print(temp * 9/5 + 32, 1); lcd.write(2); lcd.print("F"); } } // ── Example 3: Custom Characters showcase ── void displayCustomChars() { static unsigned long t = 0; if (millis() - t >= 1000) { t = millis(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Custom Chars:"); lcd.setCursor(0, 1); lcd.write(0); lcd.print(" "); // ♥ heart lcd.write(1); lcd.print(" "); // ☺ smile lcd.write(2); lcd.print(" "); // ° degree lcd.write(3); lcd.print(" "); // ↑ arrow lcd.write(4); lcd.print(" Icons!"); // 🔔 bell } } // ── Example 4: Scrolling text marquee ── void displayScrolling() { static int pos = 0; static unsigned long t = 0; String msg = " Arduino 16x2 LCD Display - I2C Communication "; if (millis() - t >= 300) { t = millis(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Scrolling Text:"); lcd.setCursor(0, 1); lcd.print(msg.substring(pos, pos + 16)); pos++; if (pos > msg.length() - 16) pos = 0; } } // ── Example 5: Simulated sensor readout ── void displaySensorData() { static unsigned long t = 0; static int light = 512, hum = 65; if (millis() - t >= 1000) { t = millis(); light = constrain(light + random(-50, 51), 0, 1023); hum = constrain(hum + random(-5, 6), 0, 100); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Light: "); lcd.print(light); lcd.setCursor(0, 1); lcd.print("Humidity: "); lcd.print(hum); lcd.print("%"); } } // ── Example 6: Software clock (HH:MM:SS) ── void displayClock() { static unsigned long t = 0; static int s = 0, m = 30, h = 12; if (millis() - t >= 1000) { t = millis(); s++; if (s >= 60) { s = 0; m++; } if (m >= 60) { m = 0; h++; } if (h >= 24) { h = 0; } lcd.clear(); lcd.setCursor(2, 0); lcd.print("Digital Clock"); lcd.setCursor(3, 1); if (h < 10) lcd.print("0"); lcd.print(h); lcd.print(":"); if (m < 10) lcd.print("0"); lcd.print(m); lcd.print(":"); if (s < 10) lcd.print("0"); lcd.print(s); } }
④ diagram.json — Auto-Wiring for Wokwi
In Wokwi, click the
{
"version": 1,
"author": "16x2 I2C LCD Display",
"editor": "wokwi",
"parts": [
{
"type": "wokwi-arduino-uno",
"id": "uno",
"top": 0, "left": 0, "attrs": {}
},
{
"type": "wokwi-lcd1602",
"id": "lcd1",
"top": -150.4, "left": -179.2,
"attrs": { "pins": "i2c" }
}
],
"connections": [
[ "lcd1:GND", "uno:GND.1", "black", [ "v0" ] ],
[ "lcd1:VCC", "uno:5V", "red", [ "v0" ] ],
[ "lcd1:SDA", "uno:A4", "green", [ "v0" ] ],
[ "lcd1:SCL", "uno:A5", "blue", [ "v0" ] ]
],
"dependencies": {}
}
The
Run the Simulation
Step 5Press Play — Watch the Splash Screen
Click the green ▶ Play button in Wokwi. The LCD should show:
- "I2C LCD Display / Initializing..." for 2 seconds
- "Arduino + LCD / ♥ Hello World! ☺" for 2 seconds
- Then Example 1 (Counter) starts automatically
If the LCD shows nothing but the backlight is on — check that your
Watch the Auto-Cycling Examples
Every 5 seconds the LCD switches to the next demo. Observe:
- Counter incrementing every second
- Temperature in °C and °F with degree symbol icon
- Heart ♥ Smile ☺ Degree ° Arrow ↑ Bell 🔔 characters on one line
- Text scrolling smoothly across the bottom row
- Light level and humidity updating live
- Clock ticking from 12:30:00 onwards
Try Modifying the Code
- Change the I²C address from
0x27 to0x3F if your physical LCD doesn't respond - Add
Serial.println() statements and check the Serial Monitor tab - Change the example interval from
5000 to2000 for faster switching - Design your own custom character using the 5×8 pixel grid
Each custom character is an 8-byte array. Each byte controls one row of 5 pixels. A
Open the Live Wokwi Simulation
All 6 examples cycle automatically. No sign-up required to view — click "Copy and Tinker" to edit your own version.
Open Wokwi SimulationFrequently Asked Questions
FAQMore MakeMindz Projects
Full CurriculumThis project is part of the MakeMindz structured curriculum. Follow the path below for a complete learning journey:
Comments
Post a Comment