A 16×2 LCD with an I2C backpack needs just four wires from a Nano: 5V, GND, A4 (SDA) and A5 (SCL). It’s readable in sunlight, which an OLED isn’t, and costs about ₹180.
To make the second line useful, the sketch measures the Nano’s own supply voltage without any extra parts. That’s a quick way to find a bad USB cable or a power bank that sags — a common cause of “random resets” on battery builds.
Wiring
| Arduino Nano | 16×2 LCD + I2C backpack | Wire | Notes |
|---|---|---|---|
| GND | GND | black | |
| 5V | VCC | red | Backlight draws 20–30 mA — fine from the Nano’s 5V pin. |
| A4 | SDA | blue | |
| A5 | SCL | yellow |
5 V (3.3 V versions exist) part, 5 V board. Most of these LCDs need 5 V for good contrast, and the backpack pulls SDA/SCL up to its own VCC. On ESP32 or Pico, put a BSS138 level shifter between the board and the backpack instead of wiring SDA/SCL directly.
Board quirks
- The LCD and the Nano are both 5 V, so SDA/SCL connect directly — no level shifter, unlike on an ESP32.
- The line-two voltage is measured by the ATmega328P against its internal 1.1 V reference. On USB it often reads 4.6–4.9 V because of the protection diode on the Nano; below about 4.5 V the LCD contrast fades.
- Address is 0x27 on PCF8574T backpacks and 0x3F on PCF8574AT. If unsure, run an I2C scanner first.
- Mount the LCD off the breadboard: the backpack’s pins hang below the display and won’t sit flat beside a Nano.
Code
// 16x2 LCD with a PCF8574 I2C backpack on an Arduino Nano.
// GND → GND, VCC → 5V, SDA → A4, SCL → A5. Address 0x27 (some backpacks: 0x3F).
// Line 2 shows the 5 V rail the Nano measures on itself (against its internal 1.1 V bandgap),
// handy for spotting a weak USB cable or a sagging power bank.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
long readVccMillivolts() {
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // AVcc reference, measure 1.1 V bandgap
delay(2);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC)) {}
long raw = ADC;
return 1125300L / raw; // 1.1 V * 1023 * 1000
}
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(F("Hello from Nano"));
Serial.println(F("LCD ready - blank? turn the blue contrast trimmer"));
}
void loop() {
long mv = readVccMillivolts();
lcd.setCursor(0, 1);
lcd.print(F("5V rail: "));
lcd.print(mv / 1000.0, 2);
lcd.print(F(" V "));
Serial.print(F("5V rail: "));
Serial.print(mv);
Serial.println(F(" mV"));
delay(1000);
}// 16x2 LCD with a PCF8574 I2C backpack on an Arduino Nano.
// GND → GND, VCC → 5V, SDA → A4, SCL → A5. Address 0x27 (some backpacks: 0x3F).
// Line 2 shows the 5 V rail the Nano measures on itself (against its internal 1.1 V bandgap),
// handy for spotting a weak USB cable or a sagging power bank.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
long readVccMillivolts() {
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // AVcc reference, measure 1.1 V bandgap
delay(2);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC)) {}
long raw = ADC;
return 1125300L / raw; // 1.1 V * 1023 * 1000
}
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print(F("Hello from Nano"));
Serial.println(F("LCD ready - blank? turn the blue contrast trimmer"));
}
void loop() {
long mv = readVccMillivolts();
lcd.setCursor(0, 1);
lcd.print(F("5V rail: "));
lcd.print(mv / 1000.0, 2);
lcd.print(F(" V "));
Serial.print(F("5V rail: "));
Serial.print(mv);
Serial.println(F(" mV"));
delay(1000);
}Library: LiquidCrystal I2C (Frank de Brabander) — compiled with LiquidCrystal I2C 1.1.2.
Expected serial output
LCD ready - blank? turn the blue contrast trimmer
5V rail: 4742 mV
5V rail: 4738 mVLCD ready - blank? turn the blue contrast trimmer 5V rail: 4742 mV 5V rail: 4738 mV