Create Custom Characters using a Common 16x2 Liquid Crystal Display
2022-06-06 | By Maker.io Staff
A previous article discussed the de-facto standard protocol for working with 16x2 character LCDs, as they are commonly found in many DIY projects and commercial products. That article also briefly explained how to write data to the LCD controller’s memory. This article discusses how you can use that technique to send custom character data, such as menu icons, to the HD44780 LCD controller. We’ll explore the data format the controller IC expects before discussing an Arduino code example that generates and displays some custom characters on a standard 16x2 character LCD.
Defining Custom Characters for HD44780-Driven LCDs
The most common size for character LCDs is 16x2. That is, the display contains two rows with 16 columns each. Therefore, such displays can show a total of 32 characters at once. Each of these characters is made up of 40 pixels organized into small 5x8 matrices:
You can make the 5x8 matrices visible by adjusting the contrast of the character LCD. This image also shows how the standard ASCII characters fit within the small pixel matrices.
Each character consists of eight bytes, where each byte represents a single row in the matrix, and the individual bit values of that byte correspond to the columns of the matrix. Note that the byte comprises eight bits. However, each display matrix only contains five columns. Therefore, the HD44780 controller ignores the most significant bits in each byte:
This image illustrates how the five least significant bits of all eight bytes form a custom character.
Therefore, each custom character occupies eight bytes of the HD44780’s character RAM (CG-RAM). CG-RAM has a capacity of 64 bytes, and it can thus store a total of eight custom bitmap characters. That might not seem like much, but it’s plenty for a few custom menu icons or a company logo that you can display while the device boots. In addition, you can also replace custom characters on demand, for example, when the user loads up a new menu that contains different icons. Lastly, note that CG-RAM is a volatile memory block, which means that you need to re-send your custom characters whenever the display powers down.
Displaying Custom Characters Using the LiquidCrystal Arduino Library
You need to store each custom character you want to send from an Arduino to the LCD controller in a byte array. This byte array contains the pixel information as described above. Then, you only have to tell the LiquidCrystal library to send the pixel information to the display. In addition to the pixel array, you also need to supply an index that determines where the library will store the custom character in the HD44780’s CG-RAM. Remember that you can only store up to eight custom characters before you need to replace previously saved data. The following short sketch defines a custom character and sends it to the LCD controller:
#include <LiquidCrystal.h>; LiquidCrystal lcd(12, 11, 5, 4, 3, 2); byte customChar[8] = { 0b00100, 0b01010, 0b00100, 0b11111, 0b00100, 0b00100, 0b01010, 0b10001 }; void setup() { lcd.begin(16, 2); lcd.createChar(0, customChar); lcd.setCursor(0, 0); lcd.write((uint8_t)0); } void loop() { }
This minimal example only contains two variables and three lines of code. First, the customChar byte array holds the pixel information. In this example, I chose to create the same character that I used as an example in the figure above. Then, the setup method initializes the display before writing the custom character data to the first CG-RAM position using the createChar function. Lastly, the setup method displays the custom character on the LCD at the current cursor position:
This image shows the result of running the code example from above.
Summary
Custom characters can spice up the often-boring user experience that simple, standard 16x2 character LCDs have to offer. You can define such custom characters by using an array of eight bytes, where each array entry represents a row of the character, and the five least significant bits of each byte define the pixel states within a row. You can then make a microcontroller, such as the MCU of an Arduino board, transmit that eight-byte sequence to the display controller, for example, when the application starts. Note that the HD44780 can only store eight custom characters at once, and it can’t retain that data once you power it off. Therefore, you have to re-send the custom character data whenever the device reboots; this is a straightforward process that only requires one line of code thanks to the LiquidCrystal Arduino library.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum