Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

I2C LCD 20×4: Displaying Multiple Lines with Arduino

I2C LCD 20×4: Displaying Multiple Lines with Arduino

March 11, 2026 /Posted byJayesh Jain / 0

The 20×4 LCD with an I2C backpack is one of the most useful display modules in any Arduino toolkit. It gives you four full rows of 20 characters each — enough to show sensor readings, status messages, menus, and debug output all at once. And with the I2C interface, you only need two wires (SDA and SCL) instead of the 6–10 GPIO pins that a parallel LCD requires.

If you have ever struggled with the classic 16×2 LCD and wished you had more screen real estate, the 20×4 is the natural upgrade. This guide walks you through every aspect of using the 20×4 I2C LCD with Arduino: wiring, finding the I2C address, library setup, displaying text on all four lines, creating custom characters, scrolling long messages, and building a practical multi-sensor display.

Table of Contents

  1. What Is an I2C LCD and Why Use the 20×4?
  2. Wiring the 20×4 I2C LCD to Arduino
  3. Finding the I2C Address with a Scanner
  4. Library Setup and Basic Display
  5. Displaying Data on All Four Lines
  6. Creating and Displaying Custom Characters
  7. Scrolling Text and Animations
  8. Practical Project: Multi-Sensor Dashboard
  9. Frequently Asked Questions

What Is an I2C LCD and Why Use the 20×4?

A standard character LCD (based on the HD44780 controller) uses a parallel data bus — you need 4 or 8 data pins, plus RS, EN, and sometimes R/W pins. On an Arduino Uno with its 14 digital pins, a parallel LCD consumes nearly half your available GPIO before you have connected a single sensor.

An I2C LCD backpack (typically using a PCF8574 I/O expander chip) sits between the LCD and your microcontroller. It converts the I2C serial protocol (just SDA and SCL) into the parallel signals the LCD needs. You get the same full-featured LCD display using only two wires, and those wires can be shared with other I2C devices on the same bus.

The 20×4 variant has four rows instead of the typical two, giving you:

  • Row 0: for a title or device name
  • Row 1: for primary sensor readings
  • Row 2: for secondary readings or status
  • Row 3: for error messages, timestamps, or menu items

This is especially useful for data loggers, weather stations, home automation panels, and any project where you need to display several values simultaneously without using a more expensive graphical display.

Recommended: Arduino Frequency Counter Kit with 16×2 LCD Display — a great project kit that shows you how to wire and code character LCDs in practice, with a real measurement application you can build and use immediately.

Wiring the 20×4 I2C LCD to Arduino

The I2C backpack on a 20×4 LCD module typically has four pins: VCC, GND, SDA, and SCL. The wiring is identical regardless of whether you use an Uno, Nano, Mega, or any other Arduino board — only the physical pin locations differ.

Arduino Uno / Nano:

  • VCC → 5V
  • GND → GND
  • SDA → A4
  • SCL → A5

Arduino Mega 2560:

  • VCC → 5V
  • GND → GND
  • SDA → Pin 20
  • SCL → Pin 21

Important notes on wiring:

  • Most I2C LCD backpacks include 4.7 kΩ pull-up resistors on SDA and SCL on the PCB. You do not need external pull-ups unless the bus is long (over 30 cm) or you have many I2C devices.
  • Some backpacks have a contrast adjustment potentiometer on the back — if the display shows squares or nothing after powering on, adjust this trimmer with a small screwdriver until characters become visible.
  • The PCF8574 chip on the backpack can be configured with three address pins (A0, A1, A2). Check whether any of these are bridged with solder jumpers — this determines the I2C address.
Recommended: Arduino Uno R3 Beginners Kit — includes an Arduino Uno plus breadboard, jumper wires, and basic components needed to prototype I2C LCD projects quickly without loose wires everywhere.

Finding the I2C Address with a Scanner

The most common reason an I2C LCD does not respond is an incorrect address in your code. PCF8574-based backpacks are typically at address 0x27, but some manufacturers use 0x3F. PCF8574A chips use a different address range (0x38–0x3F). Always scan first.

Upload this I2C scanner sketch:

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Serial.println("I2C Scanner starting...");
}

void loop() {
  byte count = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    byte err = Wire.endTransmission();
    if (err == 0) {
      Serial.print("Found device at 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
      count++;
    }
  }
  if (count == 0) Serial.println("No I2C devices found");
  delay(3000);
}

Open the Serial Monitor at 9600 baud. You will see the address printed — note it down for use in your LCD code.

Library Setup and Basic Display

The most widely used library for I2C LCD modules is LiquidCrystal I2C by Frank de Brabander (also maintained by Marco Schwartz). Install it via Sketch → Include Library → Manage Libraries, search for “LiquidCrystal I2C”, and install the version by Frank de Brabander.

Basic initialisation and Hello World:

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

// Parameters: I2C address, columns, rows
LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {
  lcd.init();
  lcd.backlight();

  lcd.setCursor(0, 0); // column, row (both 0-indexed)
  lcd.print("Hello, Zbotic!");
  lcd.setCursor(0, 1);
  lcd.print("I2C LCD 20x4");
  lcd.setCursor(0, 2);
  lcd.print("Row 2 of 4");
  lcd.setCursor(0, 3);
  lcd.print("Row 3 of 4");
}

void loop() {}

The setCursor(column, row) method takes the column first (0–19) and the row second (0–3). This is a common source of confusion — column always comes first.

Displaying Data on All Four Lines

The real power of the 20×4 LCD is showing multiple values simultaneously. Here is a pattern for a clean four-row display with labels and values:

void displayData(float temp, float humidity, float pressure, int uptime) {
  // Row 0: Header
  lcd.setCursor(0, 0);
  lcd.print("-- Weather Station --");

  // Row 1: Temperature (update only the value to avoid flicker)
  lcd.setCursor(0, 1);
  lcd.print("Temp: ");
  lcd.setCursor(6, 1);
  // Print with fixed width to overwrite old characters
  char buf[8];
  dtostrf(temp, 5, 1, buf);
  lcd.print(buf);
  lcd.print(" C  ");

  // Row 2: Humidity
  lcd.setCursor(0, 2);
  lcd.print("Hum:  ");
  lcd.setCursor(6, 2);
  dtostrf(humidity, 5, 1, buf);
  lcd.print(buf);
  lcd.print(" %  ");

  // Row 3: Pressure + uptime
  lcd.setCursor(0, 3);
  lcd.print("P:");
  lcd.setCursor(2, 3);
  dtostrf(pressure, 6, 1, buf);
  lcd.print(buf);
  lcd.print("hPa ");
  lcd.setCursor(15, 3);
  char uptimeBuf[6];
  sprintf(uptimeBuf, "%5ds", uptime % 100000);
  lcd.print(uptimeBuf);
}

Avoiding Flicker

A common mistake is calling lcd.clear() on every update. This causes visible flicker because clearing takes time (~1.5 ms) and blanks the screen. Instead, always overwrite characters in place using setCursor() and write enough characters to cover any previously displayed text. Use trailing spaces to erase leftover digits when a number becomes shorter.

Padding Numbers to Fixed Width

The dtostrf(value, width, decimals, buffer) function is your friend. It formats a float into a character array with a fixed total width, right-justified, padding with spaces. This ensures a 4-digit reading always overwrites a 5-digit reading cleanly.

Recommended: DHT20 SIP Packaged Temperature and Humidity Sensor — a modern I2C temperature and humidity sensor that pairs perfectly with the 20×4 I2C LCD for compact sensor dashboards, with both devices sharing the same two-wire I2C bus.

Creating and Displaying Custom Characters

The HD44780 controller supports up to 8 custom characters stored in CGRAM (character generator RAM). Each character is an 8×5 pixel bitmap defined as 8 bytes, where each byte is a row of 5 bits.

// Degree symbol (°)
byte degreeChar[8] = {
  0b00110,
  0b01001,
  0b01001,
  0b00110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

// Upward arrow
byte arrowUp[8] = {
  0b00100,
  0b01110,
  0b11111,
  0b00100,
  0b00100,
  0b00100,
  0b00100,
  0b00000
};

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, degreeChar); // slot 0
  lcd.createChar(1, arrowUp);   // slot 1

  lcd.setCursor(0, 0);
  lcd.print("Temp: 28");
  lcd.write(byte(0)); // print degree symbol from slot 0
  lcd.print("C");

  lcd.setCursor(0, 1);
  lcd.print("Trend: ");
  lcd.write(byte(1)); // upward arrow
}

Custom characters must be created after lcd.init() and they are lost when power is removed. If you use lcd.clear() after creating characters, the characters remain — clear only affects display memory, not CGRAM.

Scrolling Text and Animations

For messages longer than 20 characters, you need to scroll. The LCD has built-in hardware scrolling, but software scrolling gives more control:

void scrollText(int row, String text, int delayMs) {
  // Pad text with spaces so it scrolls cleanly off
  String padded = text + "                    "; // 20 spaces
  for (int i = 0; i < (int)padded.length() - 19; i++) {
    lcd.setCursor(0, row);
    lcd.print(padded.substring(i, i + 20));
    delay(delayMs);
  }
}

// Usage in loop:
void loop() {
  scrollText(3, "Zbotic.in - Electronics Store India", 300);
}

Hardware scrolling using lcd.scrollDisplayLeft() shifts the entire display one position, which is useful for ticker effects:

lcd.setCursor(20, 3); // write message starting off-screen
lcd.print("Scrolling message here");
for (int i = 0; i < 40; i++) {
  lcd.scrollDisplayLeft();
  delay(250);
}
lcd.home(); // reset scroll position

Practical Project: Multi-Sensor Dashboard

Here is a complete project combining a DHT11 temperature/humidity sensor with a BMP280 pressure sensor displayed across all four rows of the 20×4 LCD:

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

LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT dht(4, DHT11);
Adafruit_BMP280 bmp;

byte deg[8] = {0b00110,0b01001,0b01001,0b00110,0,0,0,0};

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, deg);
  dht.begin();
  bmp.begin(0x76); // or 0x77 depending on your module

  lcd.setCursor(0, 0);
  lcd.print("  ZBotics Weather  ");
  delay(2000);
}

void loop() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();
  float p = bmp.readPressure() / 100.0;
  float alt = bmp.readAltitude(1013.25);

  // Row 0 - static title
  lcd.setCursor(0, 0);
  lcd.print("  Weather Station   ");

  // Row 1 - temperature
  lcd.setCursor(0, 1);
  char buf[21];
  snprintf(buf, 21, "Temp:%5.1f", t);
  lcd.print(buf);
  lcd.write(byte(0));
  lcd.print("C        ");

  // Row 2 - humidity
  lcd.setCursor(0, 2);
  snprintf(buf, 21, "Humidity: %5.1f %%   ", h);
  lcd.print(buf);

  // Row 3 - pressure and altitude
  lcd.setCursor(0, 3);
  snprintf(buf, 21, "P:%6.1fhPa A:%4.0fm", p, alt);
  lcd.print(buf);

  delay(2000);
}

Both the I2C LCD (typically 0x27) and the BMP280 (0x76 or 0x77) share the same I2C bus — just SDA and SCL connected in parallel to both modules. The DHT11 uses a separate digital pin since it is not an I2C device.

Recommended: BMP280 Barometric Pressure and Altitude Sensor I2C/SPI Module — an I2C pressure sensor that fits perfectly in the multi-sensor dashboard project above, sharing the same two-wire bus as your I2C LCD.
Recommended: Arduino Mega 2560 R3 Board — when your project needs to drive a 20×4 LCD, multiple sensors, and additional shields simultaneously, the Mega’s 54 digital pins and hardware I2C leave plenty of room to expand without running out of GPIO.

Frequently Asked Questions

My 20×4 LCD powers on but shows only black boxes — what is wrong?

This almost always means the contrast is set too high. Find the small blue potentiometer (trimmer) on the back of the I2C backpack and turn it slowly with a flat-head screwdriver while the display is powered on. Turn it until characters become clear. If you see nothing at all (no boxes), check the I2C address — use the scanner sketch to confirm your LCD is being detected.

Can I use the 20×4 LCD with a 3.3V Arduino like the Nano 33 IoT?

The LCD itself and the PCF8574 backpack require 5V for reliable operation. The I2C logic on some backpacks is 3.3V tolerant, but the VCC pin must be 5V. If your Arduino is 3.3V-only, use a level shifter on SDA and SCL, and power the LCD from a 5V supply. Alternatively, search for I2C LCD modules specifically listed as 3.3V compatible.

How do I display special characters like rupee symbol (₹) on the LCD?

The HD44780 character ROM does not include the rupee symbol. You must create it as a custom character using lcd.createChar(). Design the character as an 8-row × 5-column bitmap and store it in one of the eight available CGRAM slots. The symbol will be an approximation since 5 pixels wide limits fine detail.

Why does my LCD show random characters or garbage after some time?

This is usually caused by I2C communication errors, often from long wires, missing pull-up resistors, or a noisy power supply. Make sure your SDA and SCL lines have 4.7 kΩ pull-ups to 5V (most backpacks have them, but check). Reduce wire length, and add a 100 µF electrolytic capacitor between VCC and GND close to the module. Also check that your Arduino’s 5V pin can supply enough current when both the LCD backlight and other peripherals are active.

Is there a way to reduce I2C LCD power consumption for battery projects?

Yes. Turn off the backlight when not needed with lcd.noBacklight() — the backlight is by far the largest current consumer (~80 mA for a 20×4). You can also call lcd.noDisplay() to blank the display content without clearing it, and turn it back on with lcd.display(). For deep sleep projects, consider adding a transistor to switch the LCD’s VCC completely off.

Add a Professional Display to Your Next Arduino Project

The 20×4 I2C LCD is one of the best ways to add a readable, low-power display to any Arduino project. With just two wires, four full rows of text, and support for custom characters and scrolling, it punches well above its price point.

Find all the Arduino boards, sensors, and display modules you need at Zbotic.in — Arduino & Microcontrollers, with fast delivery across India.

Tags: 20x4 LCD, Arduino, Arduino LCD, display tutorial, i2c lcd, LiquidCrystal I2C
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Raspberry Pi Alarm System: PIR...
blog raspberry pi alarm system pir buzzer and sms alert build 595102
blog raspberry pi gps tracker build real time fleet monitor 595116
Raspberry Pi GPS Tracker: Buil...

Related posts

Svg%3E
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Svg%3E
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now