Arduino Mega - LCD I2C

Welcome to this comprehensive Arduino Mega LCD I2C tutorial! In this detailed Arduino Mega LCD I2C guide, you'll discover how to harness the power of 16x2 character displays with I2C communication for creating informative, user-friendly interfaces in your Arduino Mega projects.

LCD I2C displays revolutionize how we add visual output to microcontroller projects. The "I2C" (Inter-Integrated Circuit) interface is a game-changer that reduces the pin count from 16 pins (in parallel mode) down to just 2 communication wires (SDA and SCL), plus power connections. This makes the LCD I2C perfect for projects with limited available pins. Throughout this Arduino Mega LCD I2C tutorial, we'll explore everything you need to master LCD displays:

This Arduino Mega LCD I2C display project opens up incredible possibilities! Create real-time sensor data displays, user interface menus, status indicators, measurement readouts, scrolling messages, temperature/humidity monitors, countdown timers, and any application where visual feedback enhances user experience. The 16x2 LCD I2C is one of the most popular and versatile display options for embedded projects!

Arduino Mega and 16x2 LCD I2C

Hardware Preparation

1×Arduino Mega
1×USB 2.0 cable type A/B (for USB-A PC)
1×USB 2.0 cable type C/B (for USB-C PC)
1×LCD I2C
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (30 sensors/displays)
1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of LCD I2C 16x2

The 16x2 LCD I2C is a character-based liquid crystal display module that combines a standard 16-column by 2-row LCD screen with an integrated I2C interface adapter (typically a PCF8574 chip). This compact display provides a clear, easy-to-read interface for showing text, numbers, and custom symbols in your embedded projects.

Key Features:

  • Display Capacity: 32 characters total (16 columns × 2 rows)
  • Character Size: Each character is formed by a 5×8 pixel matrix (or 5×10 for larger fonts)
  • I2C Communication: Uses only 2 wires (SDA/SCL) instead of 16+ parallel pins
  • Adjustable Contrast: Built-in potentiometer on the back for contrast adjustment
  • Backlight Control: Blue or green LED backlight (software-controllable via I2C)
  • Low Pin Count: Only requires 4 total pins (VCC, GND, SDA, SCL)

I2C Advantages:

The I2C interface is a massive improvement over traditional parallel connection. It saves 10+ Arduino pins, allows multiple I2C devices on the same bus, simplifies wiring with just 4 connections, and makes the display perfect for projects with limited available pins. The small tradeoff is slightly slower refresh rate compared to parallel mode, but this is imperceptible for most applications.

Pinout

The LCD I2C module features a simple 4-pin interface that uses the I2C communication protocol. Understanding these connections is essential for proper operation:

  • GND pin: The ground reference pin. Connect this to the Arduino Mega's GND (0V) to complete the power circuit and establish a common ground.
  • VCC pin: The power supply pin. Connect this to the Arduino Mega's 5V output to provide operating voltage for both the LCD screen and the I2C adapter chip.
  • SDA pin: The Serial Data line for I2C communication. This bidirectional pin carries data between the Arduino Mega and the LCD module. Connect to the Arduino Mega's SDA pin (Digital Pin 20).
  • SCL pin: The Serial Clock line for I2C communication. This pin carries the clock signal that synchronizes data transmission. Connect to the Arduino Mega's SCL pin (Digital Pin 21).
LCD I2C Pinout

I2C Bus Note: The I2C bus supports multiple devices on the same two wires (SDA/SCL). Each device has a unique I2C address (typically 0x27 or 0x3F for LCD modules). This means you can connect several I2C devices—such as sensors, RTCs, and displays—all sharing the same SDA and SCL lines. The Arduino Mega's dedicated I2C pins (20 and 21) are optimized for reliable communication.

Contrast Adjustment: On the back of the I2C adapter board, you'll find a small blue potentiometer. Use a small screwdriver to turn this pot clockwise or counterclockwise to adjust the LCD contrast for optimal readability. If you can't see any text on your LCD, try adjusting this first!

LCD Coordinate System

Understanding the LCD's coordinate system is crucial for accurate text placement. The 16x2 LCD I2C uses a zero-indexed grid coordinate system where both columns and rows start counting from 0 (not 1).

Coordinate Structure:

  • Columns: Range from 0 to 15 (16 total positions horizontally)
  • Rows: Range from 0 to 1 (2 total lines vertically)
  • Format: lcd.setCursor(column, row) where column comes first

Examples:

  • Top-left corner: (0, 0) - First column, first row
  • Top-right corner: (15, 0) - Last column, first row
  • Bottom-left corner: (0, 1) - First column, second row
  • Bottom-right corner: (15, 1) - Last column, second row
  • Center of top row: (7, 0) or (8, 0) - Middle columns, first row
Arduino Mega LCD I2C Coordinate

Practical Tips:

  • Text automatically wraps: if you print more than 16 characters starting at (0,0), it continues on row 1
  • Cursor position persists: once set, subsequent lcd.print() calls continue from that position
  • Centering text: for a 10-character string on 16-column display, start at column (16-10)/2 = 3

Wiring Diagram

Now let's examine the simple and elegant wiring between your Arduino Mega and the LCD I2C module. Thanks to the I2C interface, we only need 4 wires!

The wiring diagram between Arduino Mega LCD I2C

This image is created using Fritzing. Click to enlarge image

Connection Summary for Arduino Mega:

LCD I2C Arduino Uno, Nano Arduino Mega
Vin 5V 5V
GND GND GND
SDA A4 20
SCL A5 21

Important: The Arduino Mega uses different I2C pins than smaller Arduino boards! While the Arduino Uno and Nano use pins A4 (SDA) and A5 (SCL), the Arduino Mega uses pins 20 (SDA) and 21 (SCL). Always verify you're connecting to the correct pins for your specific board.

Wiring Best Practices:

  • Use short jumper wires (under 30cm) for reliable I2C communication
  • Keep SDA and SCL wires away from noisy power lines
  • If using long wires (>1 meter), consider adding pull-up resistors (4.7kΩ) on SDA and SCL lines
  • The I2C module typically includes built-in pull-ups, but external resistors may improve reliability in noisy environments

How To Program For LCD I2C

Let's explore the essential programming techniques for controlling your LCD I2C display. The LiquidCrystal_I2C library simplifies LCD operations, handling all the complex I2C communication behind the scenes.

Including the Library

First, include the LiquidCrystal_I2C library at the top of your sketch:

#include <LiquidCrystal_I2C.h>

This library provides all the functions needed to communicate with I2C-based LCD displays.

Creating the LCD Object

Create a LiquidCrystal_I2C object by specifying three parameters: the I2C address, number of columns, and number of rows:

LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 columns, 2 rows

I2C Address: Most LCD I2C modules use address 0x27 or 0x3F. If your LCD doesn't work with 0x27, try 0x3F. You can also scan for I2C devices using an I2C scanner sketch to find the correct address.

Initializing the LCD

In your setup() function, initialize the LCD and enable the backlight:

lcd.init(); // Initialize the LCD module lcd.backlight(); // Turn on the LED backlight

The init() function prepares the LCD for operation, while backlight() illuminates the display. You can use lcd.noBacklight() to turn it off later if needed.

Positioning the Cursor

Before displaying text, set the cursor position using column and row coordinates:

lcd.setCursor(column_index, row_index);

Remember: columns range from 0-15, rows range from 0-1. The cursor determines where the next character will be printed.

Displaying Text

Use the print() function to display text or numbers on the LCD:

lcd.print("Hello World!");

The print() function works just like Serial.print(), accepting strings, integers, floats, and other data types.

Additional Capabilities

The library provides many more functions for advanced LCD control. See the "Do More with LCD" section below for custom characters, scrolling text, cursor control, and more!

※ NOTE THAT:

I2C Address Note: The I2C address of LCD modules varies by manufacturer. Our code uses 0x27, which is standard for DIYables LCD modules. If you have a different brand, you may need to use 0x3F or run an I2C scanner to detect the address.

Arduino Mega Code

/* * This Arduino Mega code was developed by newbiely.com * * This Arduino Mega code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-mega/arduino-mega-lcd-i2c */ #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 columns and 2 lines void setup() { lcd.init(); // Initialize the LCD lcd.backlight(); lcd.setCursor(3, 0); // Set cursor to column 3, row 0 lcd.print("DIYables"); // Display title text on the screen lcd.setCursor(0, 1); // Move cursor to the start of the second line lcd.print("www.diyables.io"); // Show the website URL on the second line } void loop() { }

Detailed Instructions

Follow these detailed step-by-step instructions to get your LCD I2C display working with your Arduino Mega:

1. Physical Connections: Wire the LCD I2C display to the Arduino Mega following the wiring diagram shown above. Double-check all four connections: VCC to 5V, GND to GND, SDA to pin 20, and SCL to pin 21.

2. USB Connection: Connect the Arduino Mega board to your computer using a USB cable. Wait for your operating system to recognize the board and install any necessary drivers.

3. Open Arduino IDE: Launch the Arduino IDE software on your computer. If you haven't installed it yet, download it from the official Arduino website.

4. Board Selection: In the Arduino IDE, navigate to Tools → Board and select "Arduino Mega or Mega 2560" from the list of available boards.

5. Port Selection: Go to Tools → Port and choose the COM port (Windows) or /dev/ttyUSB or /dev/ttyACM port (Mac/Linux) that corresponds to your connected Arduino Mega.

6. Library Installation: Click the Libraries icon (book icon) on the left sidebar of the Arduino IDE. In the search box, type "LiquidCrystal I2C" and locate the LiquidCrystal_I2C library by Frank de Brabander.

7. Install Library: Click the Install button to add the LiquidCrystal_I2C library to your Arduino IDE. Wait for the installation to complete.

Arduino Mega LiquidCrystal I2C library

8. Upload Code: Copy the example code provided above and paste it into a new Arduino IDE sketch. Click the Upload button (right arrow icon) in the toolbar to compile and upload the code to your Arduino Mega.

9. Verify Output: Look at the LCD screen. You should see "DIYables" displayed on the first line at column position 3, and "www.diyables.io" displayed on the entire second line.

10. Adjust Contrast (if needed): If you can't see the text clearly or at all, use a small screwdriver to carefully turn the blue potentiometer on the back of the I2C adapter board until the text becomes clearly visible.

Experiment Further: Try modifying the text strings and cursor positions in the code to display your own custom messages and layouts!

Video Tutorial

Do More with LCD

Custom Character Generator

One of the most powerful features of LCD displays is the ability to create and display custom characters—special symbols, icons, and graphics that go beyond standard ASCII text. Want to display a heart symbol, battery indicator, degree symbol, or even a tiny angry bird? The custom character generator makes it possible!

Understanding LCD Pixels:

Each character position on the 16x2 LCD consists of a grid of 40 tiny pixels arranged in 8 rows by 5 columns. By selectively turning these pixels on or off, you can create any symbol or shape you can imagine within that 5×8 space.

Arduino Mega LCD 16x2 Pixel

How It Works:

The LCD controller (HD44780) can store up to 8 custom characters in its CGRAM (Character Generator RAM), numbered 0-7. You define the pixel pattern for each character using a byte array where each byte represents one row, and the lower 5 bits control which pixels are lit.

Using the Character Generator Tool:

The interactive pixel editor below lets you visually design custom characters. Simply follow these steps:

Click on each pixel to select/deselect


Copy below custom character code
Replace the customChar[8] in the below code
#include <LiquidCrystal_I2C.h> // Create LCD object for I2C backpack at address 0x27 with 16 columns and 2 rows LiquidCrystal_I2C lcd(0x27, 16, 2); // Custom 8-byte bitmap to define a LCD character glyph byte customChar[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 }; void setup() { lcd.init(); // Initialize LCD for operation lcd.backlight(); // Enable the backlight lcd.createChar(0, customChar); // Load the glyph into CGRAM as character 0 lcd.setCursor(2, 0); // Move cursor to column 2, row 0 lcd.write((byte)0); // Print the custom character at the cursor } void loop(){ }

Result shown on the screen:

LCD custom character

Multiple Custom Characters

The HD44780 LCD controller provides eight CGRAM slots (addresses 0-7) for storing custom characters. This means you can define up to eight different custom symbols in a single project! This is perfect for creating user interface elements like battery indicators (empty, half, full), directional arrows, degree symbols, musical notes, or any set of icons your project needs.

Example: Three Custom Characters

The example below demonstrates how to create and display three different custom characters: a heart, an up arrow, and a down arrow. Notice how each character is stored in its own byte array and registered with a unique index (0, 1, 2).

#include <LiquidCrystal_I2C.h> // Create an LCD object, using I2C address 0x27 with 16 columns and 2 rows LiquidCrystal_I2C lcd(0x27, 16, 2); // Define custom character 0 (heart shape) byte customChar0[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 }; // Define custom character 1 (arrow pointing upwards) byte customChar1[8] = { 0b00100, 0b01110, 0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100 }; // Define custom character 2 (arrow pointing downwards) byte customChar2[8] = { 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b11111, 0b01110, 0b00100 }; void setup() { lcd.init(); // Initialize the LCD lcd.backlight(); // Turn on the LCD backlight // Register custom char 0 at LCD index 0 lcd.createChar(0, customChar0); // Register custom char 1 at LCD index 1 lcd.createChar(1, customChar1); // Register custom char 2 at LCD index 2 lcd.createChar(2, customChar2); // Move cursor to column 2, row 0 lcd.setCursor(2, 0); // Print customChar0 at current cursor position lcd.write((byte)0); // Move cursor to column 4, row 0 lcd.setCursor(4, 0); // Print customChar1 at current cursor position lcd.write((byte)1); // Move cursor to column 6, row 0 lcd.setCursor(6, 0); // Print customChar2 at the current cursor position lcd.write((byte)2); } void loop() { }

Result shown on the LCD screen:

LCD multiple custom characters

Summary: Creating and Using Custom Characters on LCD

Follow this comprehensive workflow to design and display your own custom characters:

Step 1: Design Your Character

Use the interactive pixel editor tool above to visually design your custom character. Click on individual pixels to turn them on (black) or off (white) until you've created the desired shape or symbol.

Step 2: Copy the Generated Code

The tool automatically generates the byte array code for your character. Copy this binary code from the generator output:

byte customChar[8] = { 0b00000, 0b01010, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000, 0b00000 };

Step 3: Register the Character

In your setup() function, register the custom character to one of the 8 available CGRAM slots (index 0-7) using the createChar() function:

lcd.createChar(index, customChar); // index must be 0-7

Step 4: Display the Character

Anywhere in your code (setup() or loop()), position the cursor and display the custom character using its index:

lcd.setCursor(column, row); // Move to the specified column and row lcd.write((byte)index); // Output the custom character from CGRAM slot 'index'

Important Notes:

  • Custom characters persist in CGRAM until you power off the LCD or overwrite them
  • You can reuse the same custom character multiple times at different screen positions
  • Each character occupies one of the 32 display positions (just like regular ASCII characters)
  • The 8 custom character slots are independent—you can mix custom and regular characters freely

Additional LCD Control Functions

The LiquidCrystal_I2C library provides many powerful functions beyond basic text display. These functions give you complete control over the LCD's appearance and behavior.

Clear the Display:

Removes all text from the LCD and moves the cursor back to position (0,0). Use this when you want to completely refresh the display with new content.

lcd.clear();

Return Cursor to Home:

Moves the cursor to the top-left corner position (0,0) without clearing the display. This is faster than clear() when you want to keep existing content visible.

lcd.home();

Set Cursor Position:

Moves the cursor to a specific column and row coordinate. Essential for positioning text precisely on the display.

lcd.setCursor(column, row); // column: 0-15, row: 0-1

Display Underline Cursor:

Shows an underline cursor at the current position. Useful for indicating where the next character will appear, especially in user input applications.

lcd.cursor();

Hide Cursor:

Turns off the cursor display. This creates a cleaner appearance when not accepting user input.

lcd.noCursor();

Enable Blinking Cursor:

Displays a blinking block cursor at the current position. This provides a more prominent visual indicator for user input fields.

lcd.blink();

Disable Blinking Cursor:

Stops the cursor from blinking, returning it to steady display (if cursor() is enabled) or hidden (if noCursor() is set).

lcd.noBlink();

Backlight Control:

You can dynamically turn the backlight on and off to save power or create attention-grabbing effects:

lcd.backlight(); // Turn on the LED backlight lcd.noBacklight(); // Turn off the LED backlight

Display On/Off:

Control whether content is visible without losing the data in display RAM:

lcd.display(); // Turn on the display (show content) lcd.noDisplay(); // Turn off the display (hide content but retain it in memory)

Advanced Usage Tip: Try testing these functions sequentially in your loop() with delay(5000) between each to observe their effects. For comprehensive documentation, visit the official LiquidCrystal Library Reference: https://arduinogetstarted.com/reference/library/arduino-lcd-library

Troubleshooting LCD I2C Display Issues

Experiencing problems with your LCD I2C display? Follow this comprehensive troubleshooting guide to diagnose and resolve common issues.

Problem: No Text Visible on LCD

Solution 1: Adjust Contrast

The most common issue! On the back of the I2C adapter board, you'll find a small blue potentiometer (trim pot). Use a small flathead screwdriver to carefully rotate this potentiometer clockwise or counterclockwise. You should see the text contrast change—from invisible to faint to clear to black boxes. Adjust until text is clearly readable.

Solution 2: Verify I2C Address

Different LCD I2C modules use different I2C addresses depending on the manufacturer. The two most common addresses are 0x27 and 0x3F. If your LCD doesn't respond with one address, try the other in your code:

LiquidCrystal_I2C lcd(0x3F, 16, 2); // Try 0x3F instead of 0x27

Solution 3: Scan for I2C Address

If neither 0x27 nor 0x3F works, use this I2C scanner sketch to automatically detect the correct address of your LCD module:

// I2C address scanner for discovering devices on the I2C bus #include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); Serial.println("I2C Scanner"); } void loop() { byte error, address; int nDevices; Serial.println("Scanning..."); nDevices = 0; for(address = 1; address < 127; address++ ) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address < 16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println("No I2C devices found"); else Serial.println("done"); delay(5000); // pause 5 seconds before the next scan }

How to Use the Scanner:

  1. Upload the I2C scanner code to your Arduino Mega
  2. Open the Serial Monitor (Tools → Serial Monitor) and set baud rate to 9600
  3. Watch for scanning results every 5 seconds
  4. Note the hexadecimal address displayed (e.g., 0x27 or 0x3F)
  5. Use that address in your LiquidCrystal_I2C lcd() constructor

Example Serial Monitor Output:

COM6
Send
Scanning... I2C device found at address 0x3F ! done Scanning... I2C device found at address 0x3F ! done
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

In this example, the LCD is detected at address 0x3F, so you would use:

LiquidCrystal_I2C lcd(0x3F, 16, 2);

Additional Troubleshooting Tips

Check Wiring Connections:

  • Verify VCC connects to Arduino 5V (not 3.3V)
  • Confirm GND connects to Arduino GND
  • Double-check SDA goes to pin 20 on Arduino Mega (not A4)
  • Ensure SCL goes to pin 21 on Arduino Mega (not A5)
  • Inspect for loose or broken connections

Power Supply Issues:

  • The LCD draws 20-40mA of current with backlight on
  • If using USB power, ensure your computer provides sufficient current
  • Try an external 5V power supply if USB power seems insufficient
  • Measure voltage at LCD VCC pin (should be close to 5.0V)

Library Issues:

  • Confirm you've installed the correct library: LiquidCrystal_I2C by Frank de Brabander
  • Restart Arduino IDE after installing new libraries
  • Check for conflicting libraries with similar names

Hardware Problems:

  • Inspect solder joints on I2C adapter for cold solder or bridges
  • Test with a different LCD module if available
  • Verify the I2C adapter is properly connected to the LCD (some modules have removable adapters)

By systematically working through these troubleshooting steps, you should be able to resolve most LCD I2C display issues!

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!