← Back to guides

How to Display Custom Icons on LCD 1602

The HD44780 controller stores up to 8 custom characters in CGRAM (Character Generator RAM). Each character is an 8×8 pixel grid encoded as 8 bytes — exactly what our pixel generator produces.

Step 1 — Generate the Byte Array

Draw your icon in the generator, then click Copy code. You will get something like:

byte heart[8] = {
  0x00, 0x0A, 0x1F, 0x1F,
  0x0E, 0x04, 0x00, 0x00
};

Step 2 — Load into CGRAM

Call lcd.createChar(slot, dataArray) in setup(). Slots are numbered 0–7. Each slot maps to display code 0–7 when you call lcd.write().

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte heart[8] = {
  0x00, 0x0A, 0x1F, 0x1F,
  0x0E, 0x04, 0x00, 0x00
};

void setup() {
  lcd.begin(16, 2);
  lcd.createChar(0, heart);
  lcd.setCursor(0, 0);
  lcd.write(byte(0));
  lcd.print(" Hello");
}

Step 3 — Multiple Icons

You can load up to 8 different icons at once — one per CGRAM slot:

lcd.createChar(0, heart);
lcd.createChar(1, wifi);
lcd.createChar(2, battery);

lcd.setCursor(0, 1);
lcd.write(byte(1));
lcd.print(" Connected");

Pixel Layout Tips

  • Only 5 columns are visible on most LCDs — leave column 0 and 6–7 empty for clean margins
  • Rows map top-to-bottom: byte 0 = top row, byte 7 = bottom row
  • Each bit in a byte represents one pixel: LSB (bit 0) = left, MSB (bit 7) = right
  • Use the LCD preview panel in the generator to see how your icon looks on a green display

I2C Modules

The process is identical with LiquidCrystal_I2C — only the constructor and lcd.init() call differ. Custom character API is the same.

Compile errors? See our guide on fixing Arduino LiquidCrystal errors.