The 16×2 character LCD is arguably the most widely used display in the maker community — and for good reason. It is affordable, easy to programme, and displays text clearly. Adding an I2C backpack reduces the wiring from 12+ pins to just 4 wires. In this guide, we go beyond the basics to cover custom character creation and building a proper menu navigation system.
Understanding the 16×2 LCD with I2C Backpack
The 16×2 LCD based on the HD44780 controller displays 2 lines of 16 characters each. The I2C backpack (PCF8574 or PCF8574T) sits on the back and converts the parallel interface to I2C:
- Only 4 wires needed: VCC, GND, SDA, SCL
- Default I2C address: 0x27 (some modules use 0x3F)
- Backlight control: Managed via I2C — no extra pin needed
- Contrast adjustment: Small potentiometer on the I2C board
This combination of simplicity and capability makes it the default choice for projects that need text output — from temperature displays to 3D printer controllers.
Wiring and Initial Setup
| LCD I2C Pin | Arduino Uno |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
Install the LiquidCrystal_I2C library and run this test:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Hello, Zbotic!");
lcd.setCursor(0, 1);
lcd.print("Made in India");
}
If you see a blank screen with backlight on, adjust the contrast potentiometer with a small screwdriver.
Creating Custom Characters
The HD44780 controller supports up to 8 custom characters (5×8 pixels each), stored in CGRAM. Here is how to create them:
// Heart symbol
byte heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000
};
void setup() {
lcd.init();
lcd.backlight();
lcd.createChar(0, heart);
lcd.setCursor(0, 0);
lcd.write(byte(0)); // Display the heart
}
Useful custom characters for Indian projects:
- Rupee symbol (₹) — essential for billing/pricing displays
- Temperature icon — thermometer shape for weather stations
- Battery level indicators — empty, quarter, half, three-quarter, full
- Arrow symbols — for menu navigation indicators
- Lock/unlock icons — for security systems
Use online tools like LCD Character Creator to design your custom characters visually.
Building a Multi-Page Menu System
A menu system transforms a simple LCD into an interactive user interface. Here is the architecture:
const char* menuItems[] = {
"1. Temperature",
"2. Humidity",
"3. Set Alarm",
"4. WiFi Config",
"5. About"
};
int menuIndex = 0;
int totalItems = 5;
void displayMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(">");
lcd.print(menuItems[menuIndex]);
lcd.setCursor(0, 1);
if (menuIndex + 1 < totalItems) {
lcd.print(" ");
lcd.print(menuItems[menuIndex + 1]);
}
}
Use two buttons (Up/Down) or a rotary encoder to navigate. The “>” cursor indicates the currently selected item. Press a “Select” button to enter a sub-menu or execute an action.
Using Rotary Encoder for Navigation
A rotary encoder with a built-in push button is the most elegant navigation solution:
- Rotate clockwise — move down the menu
- Rotate anti-clockwise — move up the menu
- Press the knob — select/enter the current item
- Long press — go back to the previous menu level
This gives you a professional-feeling interface with just a single knob — similar to car infotainment systems or 3D printer controllers. Use the Encoder library with interrupt-driven reading for smooth, debounce-free rotation detection.
Displaying Sensor Data with Custom Icons
Combine custom characters with sensor readings for a polished dashboard:
- Line 1:
[thermometer icon] 28.5°C [droplet] 65% - Line 2:
[clock icon] 14:30 [bell] Alarm ON
This approach packs maximum information into 32 characters while remaining highly readable. Update the display every 2 seconds to keep readings current without causing LCD flicker.
Common Troubleshooting Tips
- Blank screen with backlight: Adjust the contrast potentiometer; try I2C address 0x3F
- Garbled characters: Check wiring, especially SDA and SCL; run an I2C scanner to verify address
- Flickering display: Add a 100 µF capacitor across VCC and GND near the LCD
- I2C address conflicts: If using multiple I2C devices, ensure no address overlap; some PCF8574 boards have solder jumpers to change address
- Custom characters disappearing: You must call
createChar()in setup, and characters are lost afterlcd.clear()on some libraries — recreate them after clearing
Recommended LCD Modules from Zbotic
These are our best-selling LCD modules for your next project:
Frequently Asked Questions
Can I use a 16×2 LCD without the I2C backpack?
Yes, but it requires 6-10 data pins on your Arduino. The I2C backpack reduces this to just 2 pins (SDA and SCL), freeing up GPIO for sensors and other peripherals.
How many custom characters can the 16×2 LCD store?
The HD44780 controller supports up to 8 custom characters (numbered 0-7). Each character is 5 pixels wide by 8 pixels tall.
What is the difference between 0x27 and 0x3F I2C addresses?
It depends on the PCF8574 variant. PCF8574 uses 0x27 by default, while PCF8574T uses 0x3F. Run an I2C scanner sketch to determine your module’s address.
Can I display Devanagari or other Indian scripts on a 16×2 LCD?
You can create up to 8 custom characters, which limits you to 8 unique symbols at a time. For full Devanagari support, consider a graphical OLED or TFT display instead.
Shop Display Modules at Zbotic.in
India’s trusted source for OLED, LCD, TFT, LED matrices, and more. Fast shipping across India.
Add comment