16×2 I2C LCD Display Using Arduino Uno – Step-by-Step Guide (Beginner Friendly)

 


Introduction

In this project, we will learn how to interface a 16×2 I2C LCD display with Arduino Uno. Using the I2C module reduces wiring complexity and makes your Arduino projects cleaner and easier to build.

This tutorial is perfect for:

  • Beginners learning Arduino

  • School robotics projects

  • IoT display systems

  • Sensor data monitoring projects

By the end of this guide, you’ll understand how to display text, sensor values, and custom messages on a 16×2 LCD using I2C communication.

Code:

/*
 * 16x2 I2C LCD Display with Arduino
 * Features: Text display, scrolling messages, custom characters, sensor readings
 * I2C Address: 0x27 (or 0x3F)
 */

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Initialize LCD with I2C address 0x27, 16 columns and 2 rows
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Custom character definitions (heart, smile, degree symbol, etc.)
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
};

// Variables for demonstration
int counter = 0;
unsigned long lastUpdate = 0;
const int updateInterval = 1000; // Update every second

void setup() {
  Serial.begin(9600);
 
  // Initialize LCD
  lcd.init();
 
  // Turn on backlight
  lcd.backlight();
 
  // Create custom characters
  lcd.createChar(0, heart);
  lcd.createChar(1, smile);
  lcd.createChar(2, degree);
  lcd.createChar(3, arrow);
  lcd.createChar(4, bell);
 
  // Display startup message
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("I2C LCD Display");
  lcd.setCursor(0, 1);
  lcd.print("Initializing...");
  delay(2000);
 
  // Clear and show welcome message
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Arduino + LCD");
  lcd.setCursor(0, 1);
  lcd.write(0); // Heart
  lcd.print(" Hello World! ");
  lcd.write(1); // Smile
  delay(2000);
 
  Serial.println("16x2 I2C LCD Display Initialized");
  Serial.println("I2C Address: 0x27");
  Serial.println("Displaying various examples...");
}

void loop() {
  unsigned long currentMillis = millis();
 
  // Cycle through different display examples
  int example = (currentMillis / 5000) % 6; // Change example every 5 seconds
 
  switch(example) {
    case 0:
      displayCounter();
      break;
    case 1:
      displayTemperature();
      break;
    case 2:
      displayCustomChars();
      break;
    case 3:
      displayScrollingText();
      break;
    case 4:
      displaySensorData();
      break;
    case 5:
      displayClock();
      break;
  }
 
  delay(100);
}

// Example 1: Counter Display
void displayCounter() {
  static unsigned long lastCount = 0;
 
  if (millis() - lastCount >= 1000) {
    lastCount = millis();
    counter++;
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Counter Display");
    lcd.setCursor(0, 1);
    lcd.print("Count: ");
    lcd.print(counter);
   
    Serial.print("Counter: ");
    Serial.println(counter);
  }
}

// Example 2: Temperature Display
void displayTemperature() {
  static unsigned long lastTemp = 0;
  static float temperature = 25.5;
 
  if (millis() - lastTemp >= 1000) {
    lastTemp = millis();
    temperature += random(-10, 11) / 10.0; // Simulate temperature change
    if (temperature < 0) temperature = 0;
    if (temperature > 50) temperature = 50;
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Temperature:");
    lcd.setCursor(0, 1);
    lcd.print(temperature, 1);
    lcd.write(2); // Degree symbol
    lcd.print("C");
   
    lcd.setCursor(10, 1);
    lcd.print(temperature * 9/5 + 32, 1);
    lcd.write(2);
    lcd.print("F");
   
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.println("°C");
  }
}

// Example 3: Custom Characters Display
void displayCustomChars() {
  static unsigned long lastChar = 0;
 
  if (millis() - lastChar >= 1000) {
    lastChar = millis();
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Custom Chars:");
    lcd.setCursor(0, 1);
    lcd.write(0); lcd.print(" ");
    lcd.write(1); lcd.print(" ");
    lcd.write(2); lcd.print(" ");
    lcd.write(3); lcd.print(" ");
    lcd.write(4); lcd.print(" ");
    lcd.print("Icons!");
   
    Serial.println("Displaying custom characters");
  }
}

// Example 4: Scrolling Text
void displayScrollingText() {
  static int scrollPos = 0;
  static unsigned long lastScroll = 0;
  String message = "   Arduino 16x2 LCD Display - I2C Communication   ";
 
  if (millis() - lastScroll >= 300) {
    lastScroll = millis();
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Scrolling Text:");
   
    lcd.setCursor(0, 1);
    String displayText = message.substring(scrollPos, scrollPos + 16);
    lcd.print(displayText);
   
    scrollPos++;
    if (scrollPos > message.length() - 16) {
      scrollPos = 0;
    }
  }
}

// Example 5: Sensor Data Display
void displaySensorData() {
  static unsigned long lastSensor = 0;
  static int lightLevel = 512;
  static int humidity = 65;
 
  if (millis() - lastSensor >= 1000) {
    lastSensor = millis();
   
    // Simulate sensor readings
    lightLevel += random(-50, 51);
    humidity += random(-5, 6);
    lightLevel = constrain(lightLevel, 0, 1023);
    humidity = constrain(humidity, 0, 100);
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Light: ");
    lcd.print(lightLevel);
   
    lcd.setCursor(0, 1);
    lcd.print("Humidity: ");
    lcd.print(humidity);
    lcd.print("%");
   
    Serial.print("Light: ");
    Serial.print(lightLevel);
    Serial.print(" | Humidity: ");
    Serial.print(humidity);
    Serial.println("%");
  }
}

// Example 6: Clock Display
void displayClock() {
  static unsigned long lastClock = 0;
  static int seconds = 0;
  static int minutes = 30;
  static int hours = 12;
 
  if (millis() - lastClock >= 1000) {
    lastClock = millis();
   
    seconds++;
    if (seconds >= 60) {
      seconds = 0;
      minutes++;
      if (minutes >= 60) {
        minutes = 0;
        hours++;
        if (hours >= 24) {
          hours = 0;
        }
      }
    }
   
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("  Digital Clock");
   
    lcd.setCursor(3, 1);
    if (hours < 10) lcd.print("0");
    lcd.print(hours);
    lcd.print(":");
    if (minutes < 10) lcd.print("0");
    lcd.print(minutes);
    lcd.print(":");
    if (seconds < 10) lcd.print("0");
    lcd.print(seconds);
   
    Serial.print("Time: ");
    if (hours < 10) Serial.print("0");
    Serial.print(hours);
    Serial.print(":");
    if (minutes < 10) Serial.print("0");
    Serial.print(minutes);
    Serial.print(":");
    if (seconds < 10) Serial.print("0");
    Serial.println(seconds);
  }
}


Why Use I2C LCD Instead of Normal LCD?

A regular 16×2 LCD requires 6–12 connections.
With an I2C module, you only need 4 wires:

  • VCC

  • GND

  • SDA

  • SCL

This makes wiring simple and beginner-friendly.

Diagram.json:

{
  "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": {}
}



Components Required

  • Arduino Uno

  • 16×2 LCD with I2C module

  • Jumper wires

  • USB cable


Step-by-Step Connection Guide

Step 1: Identify I2C Pins on Arduino Uno

I2C PinArduino Uno Pin
VCC5V
GNDGND
SDAA4
SCLA5

Step 2: Connect LCD to Arduino

  • Connect VCC → 5V

  • Connect GND → GND

  • Connect SDA → A4

  • Connect SCL → A5

Your wiring is now complete.


Step 3: Install Required Library

Open Arduino IDE:

  1. Go to Sketch → Include Library → Manage Libraries

  2. Search for LiquidCrystal I2C

  3. Install the library

FAQ

Q1: What is the I2C address of my LCD?

Usually 0x27 or 0x3F.

Q2: Can I display sensor values?

Yes! You can use lcd.print(sensorValue);

Q3: Is this beginner friendly?

Yes, this is one of the easiest Arduino display projects.


Conclusion

The 16×2 I2C LCD Display using Arduino Uno is one of the most essential and beginner-friendly projects. With just four wires, you can display sensor data, messages, and real-time information easily.

This project is perfect for robotics students, IoT beginners, and electronics enthusiasts.

Comments