Arduino Lcd not posting Image correctly

Howdy!
I've been trying to add an image to the Arduino 16x2 LCD, I've converted my image to monochrome, then a bitmap, then converted it to binary, and then created a Python script to format that code into multiple characters.

This is the image I'm using.
7QeAWe6
Its 80x16 Pixels

Heres the Python script

binary_data = (
    "00000000000000000000000000000000000011011011000000000000000000000000000000000000"
    "00000000000000000000000000000001111001100110000100000000000000000000000000000000"
    "00000000011110000000001110000001001000111100001010000001110000000001111000000000"
    "00000111111111000011110010000001001000000000010101000001001111000011111111100000"
    "00001111111111000100000011000011111110000000001010000011000000100011111111110000"
    "00001111111111000100000001000010010010000000000100000010000000100011111111110000"
    "00001111111111000100000001000010010010000000001110000010000000100011111111110000"
    "00001111111111000100000001000011111111000011111111000010000000100011111111110000"
    "00001111111111000100000001000100000001111100000000100010000000100011111111110000"
    "00001111111111100100001111000100000000000000000000100011110000100111111111110000"
    "00011111111111100011110000000100000000000000000000100000001111000111111111111000"
    "00011111111111100000000000000100000000000000000000100000000000000111111111111000"
    "00011111111111100000000000000100000000000000000000100000000000000111111111111000"
    "00011111111111100000000000000100000000000000000000100000000000000111111111111000"
    "00011111111111100000000000000100111111111111111100100000000000000111111111111000"
    "00011111111111110000000000000100100000000000000100100000000000001111111111111000"
    # ... Continue with the rest of your binary data ...
)

formatted_data = []

# Split the binary data into groups of 8 characters and convert to bytes
for i in range(0, len(binary_data), 5):
    byte_data = binary_data[i:i + 5]
    formatted_byte = "B" + byte_data
    formatted_data.append(formatted_byte)

# Divide the formatted data into chunks of 8 lines
chunks = [formatted_data[i:i + 8] for i in range(0, len(formatted_data), 8)]

# Print each chunk in the required format
for chunk_num, chunk in enumerate(chunks, start=1):
    print(f"byte customChar{chunk_num}[] = {{")
    formatted_data_str = ",\n".join(chunk)
    print(formatted_data_str)
    print("};")
    print("")  # Add an empty line between chunks

for i in range(32):
    print(f"lcd.createChar({i}, customChar{i + 1});")
for i in range(32):
    print(f"lcd.write(byte({i}));")

This correctly formatted the code for creating custom characters.
I added the code to Tinkercad with my electronics looking like this:

When I power on the Arduino I receive these mystery characters,

It looks nothing like the image I wanted. I did some troubleshooting and found that removing large sections of the character's code would put my original image back into position.

Heres the Arduino code:

#include <LiquidCrystal.h>

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

byte customChar1[] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B01101
};

byte customChar2[] = {
  B10110,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};

byte customChar3[] = {
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B01111,
  B00110
};

byte customChar4[] = {
  B01100,
  B00100,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};

byte customChar5[] = {
  B00000,
  B00001,
  B11100,
  B00000,
  B00111,
  B00000,
  B01001,
  B00011
};

byte customChar6[] = {
  B11000,
  B01010,
  B00000,
  B11100,
  B00000,
  B00111,
  B10000,
  B00000
};

byte customChar7[] = {
  B00000,
  B11111,
  B11110,
  B00011,
  B11001,
  B00000,
  B01001,
  B00000
};

byte customChar8[] = {
  B00000,
  B10101,
  B00000,
  B10011,
  B11000,
  B01111,
  B11111,
  B00000
};

byte customChar9[] = {
  B00001,
  B11111,
  B11110,
  B00100,
  B00001,
  B10000,
  B11111,
  B11000
};

byte customChar10[] = {
  B00000,
  B01010,
  B00001,
  B10000,
  B00100,
  B01111,
  B11111,
  B10000
};

byte customChar11[] = {
  B00001,
  B11111,
  B11110,
  B00100,
  B00000,
  B10000,
  B10010,
  B01000
};

byte customChar12[] = {
  B00000,
  B00100,
  B00001,
  B00000,
  B00100,
  B01111,
  B11111,
  B10000
};

byte customChar13[] = {
  B00001,
  B11111,
  B11110,
  B00100,
  B00000,
  B10000,
  B10010,
  B01000
};

byte customChar14[] = {
  B00000,
  B01110,
  B00001,
  B00000,
  B00100,
  B01111,
  B11111,
  B10000
};

byte customChar15[] = {
  B00001,
  B11111,
  B11110,
  B00100,
  B00000,
  B10000,
  B11111,
  B11100
};

byte customChar16[] = {
  B00111,
  B11111,
  B00001,
  B00000,
  B00100,
  B01111,
  B11111,
  B10000
};

byte customChar17[] = {
  B00001,
  B11111,
  B11110,
  B00100,
  B00000,
  B10001,
  B00000,
  B00111
};

byte customChar18[] = {
  B11000,
  B00000,
  B10001,
  B00000,
  B00100,
  B01111,
  B11111,
  B10000
};

byte customChar19[] = {
  B00001,
  B11111,
  B11111,
  B00100,
  B00111,
  B10001,
  B00000,
  B00000
};

byte customChar20[] = {
  B00000,
  B00000,
  B10001,
  B11100,
  B00100,
  B11111,
  B11111,
  B10000
};

byte customChar21[] = {
  B00011,
  B11111,
  B11111,
  B00011,
  B11000,
  B00001,
  B00000,
  B00000
};

byte customChar22[] = {
  B00000,
  B00000,
  B10000,
  B00011,
  B11000,
  B11111,
  B11111,
  B11000
};

byte customChar23[] = {
  B00011,
  B11111,
  B11111,
  B00000,
  B00000,
  B00001,
  B00000,
  B00000
};

byte customChar24[] = {
  B00000,
  B00000,
  B10000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11000
};

byte customChar25[] = {
  B00011,
  B11111,
  B11111,
  B00000,
  B00000,
  B00001,
  B00000,
  B00000
};

byte customChar26[] = {
  B00000,
  B00000,
  B10000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11000
};

byte customChar27[] = {
  B00011,
  B11111,
  B11111,
  B00000,
  B00000,
  B00001,
  B00000,
  B00000
};

byte customChar28[] = {
    B00000,
    B00000,
    B10000,
    B00000,
    B00000,
    B11111,
    B11111,
    B11000
};

byte customChar29[] = {
  B00011,
  B11111,
  B11111,
  B00000,
  B00000,
  B00001,
  B00111,
  B11111
};

byte customChar30[] = {
  B11111,
  B11100,
  B10000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11000
};

byte customChar31[] = {
  B00011,
  B11111,
  B11111,
  B10000,
  B00000,
  B00001,
  B00100,
  B00000
};

byte customChar32[] = {
  B00000,
  B00100,
  B10000,
  B00000,
  B00001,
  B11111,
  B11111,
  B11000
};


void setup() {
  lcd.begin(16, 2);
lcd.createChar(0, customChar1);
lcd.createChar(1, customChar2);
lcd.createChar(2, customChar3);
lcd.createChar(3, customChar4);
lcd.createChar(4, customChar5);
lcd.createChar(5, customChar6);
lcd.createChar(6, customChar7);
lcd.createChar(7, customChar8);
lcd.createChar(8, customChar9);
lcd.createChar(9, customChar10);
lcd.createChar(10, customChar11);
lcd.createChar(11, customChar12);
lcd.createChar(12, customChar13);
lcd.createChar(13, customChar14);
lcd.createChar(14, customChar15);
lcd.createChar(15, customChar16);
lcd.createChar(16, customChar17);
lcd.createChar(17, customChar18);
lcd.createChar(18, customChar19);
lcd.createChar(19, customChar20);
lcd.createChar(20, customChar21);
lcd.createChar(21, customChar22);
lcd.createChar(22, customChar23);
lcd.createChar(23, customChar24);
lcd.createChar(24, customChar25);
lcd.createChar(25, customChar26);
lcd.createChar(26, customChar27);
lcd.createChar(27, customChar28);
lcd.createChar(28, customChar29);
lcd.createChar(29, customChar30);
lcd.createChar(30, customChar31);
lcd.createChar(31, customChar32);
lcd.home();
lcd.write(byte(0));
lcd.write(byte(1));
lcd.write(byte(2));
lcd.write(byte(3));
lcd.write(byte(4));
lcd.write(byte(5));
lcd.write(byte(6));
lcd.write(byte(7));
lcd.write(byte(8));
lcd.write(byte(9));
lcd.write(byte(10));
lcd.write(byte(11));
lcd.write(byte(12));
lcd.write(byte(13));
lcd.write(byte(14));
lcd.write(byte(15));
lcd.write(byte(16));
lcd.write(byte(17));
lcd.write(byte(18));
lcd.write(byte(19));
lcd.write(byte(20));
lcd.write(byte(21));
lcd.write(byte(22));
lcd.write(byte(23));
lcd.write(byte(24));
lcd.write(byte(25));
lcd.write(byte(26));
lcd.write(byte(27));
lcd.write(byte(28));
lcd.write(byte(29));
lcd.write(byte(30));
lcd.write(byte(31));
}


void loop() {
}

Is there any way to fix this? or at least another way to print a full image on the LCD?

I suggest you go over the documentation for your display. It appears the combination you have can only support a few custom characters which you are exceeding. The compiler does not know this, it is the responsibility of the programer. Your frizzy picture does not make appear correct. Post an annotated schematic, hand drawn is ok, just post a clear readable picture of it.

1 Like

Here is the link the the Tinkercad project, Login | Tinkercad

An LCD display like that can only display a total of eight custom characters at once. If you redefine a character currently being displayed, the image on the display will also change, so there is no way around the hardware limitation.

1 Like

Thank you, it's too bad that is limited.

Have you tried image2cpp and an OLED?

// 'image3', 80x16px
const unsigned char epd_bitmap_image3 [] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x0d, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe6, 0x61, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x03, 0x81, 0x23, 0xc2, 0x81, 0xc0, 0x1e, 0x00, 0x07, 0xfc, 
	0x3c, 0x81, 0x20, 0x05, 0x41, 0x3c, 0x3f, 0xe0, 0x0f, 0xfc, 0x40, 0xc3, 0xf8, 0x02, 0x83, 0x02, 
	0x3f, 0xf0, 0x0f, 0xfc, 0x40, 0x42, 0x48, 0x01, 0x02, 0x02, 0x3f, 0xf0, 0x0f, 0xfc, 0x40, 0x42, 
	0x48, 0x03, 0x82, 0x02, 0x3f, 0xf0, 0x0f, 0xfc, 0x40, 0x43, 0xfc, 0x3f, 0xc2, 0x02, 0x3f, 0xf0, 
	0x0f, 0xfc, 0x40, 0x44, 0x07, 0xc0, 0x22, 0x02, 0x3f, 0xf0, 0x0f, 0xfe, 0x43, 0xc4, 0x00, 0x00, 
	0x23, 0xc2, 0x7f, 0xf0, 0x1f, 0xfe, 0x3c, 0x04, 0x00, 0x00, 0x20, 0x3c, 0x7f, 0xf8, 0x1f, 0xfe, 
	0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x7f, 0xf8, 0x1f, 0xfe, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 
	0x7f, 0xf8, 0x1f, 0xfe, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x7f, 0xf8, 0x1f, 0xfe, 0x00, 0x04, 
	0xff, 0xff, 0x20, 0x00, 0x7f, 0xf8, 0x1f, 0xff, 0x00, 0x04, 0x80, 0x01, 0x20, 0x00, 0xff, 0xf8
};

// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 176)
const int epd_bitmap_allArray_LEN = 1;
const unsigned char* epd_bitmap_allArray[1] = {
	epd_bitmap_image3
};
1 Like

That's what I'm working on right now! Its too bad the lcd couldn't work.

I wonder if you can dynamically create custom characters. That is to say,

Define Char1...

Create Char1...

Use it...

Then move the bits around to define a new Char1, create Char1, use Char1...

Or will that be met with compile time errors?

You can redefine a custom character at any time. createChar() sends the character pattern to the memory inside the LCD control chip. If you redefine a custom character that is currently being displayed on the LCD, the image displayed on the LCD changes, so that is not a way to cheat the limitation of eight custom characters.

How does one dig into/past the library files to find how each pixel is being driven? Library files seem very high level. (Reference the datasheet, yes, but looking for the already-written hardware interface... to cheat...)

You would need to look at the data sheet for the HD44780 LCD controller, that or a clone is what drives all of the common LCD displays used with the various LiquidCrystal libraries. As far as I know there is no way to directly control individual pixels of the display, it is a character-based display, with a build-in character set and memory for eight custom character patterns.

This makes sense. Thank you.

The uncompiled library files are downloaded and saved on your pc. Generally near the folder where you store your arduino projects but under\arduino\libraries\

Yes, the authors of the libraries have done all the heavy lifting of interpreting the datasheet and putting it in readable form... As I look at libraries, I am trying to find where the hardware-to-software interaction occurs... the communicating with the device drivers, which provide and receive the bits for the library to function.

The familiar 1602 is a character LCD. You can get graphic LCDs that will allow you to access every pixel.

This document spells out LCD part numbers...

Here is a 160x32 graphic LCD...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.