Skip to content

5. Custom characters defining and usage

niwciu edited this page Feb 13, 2025 · 10 revisions

How to Define a Special Character

Example of Correspondence between HD44780 EPROM Address Data and Character Pattern (5 × 8 Dots)

If the character shown in the picture above should be defined as a special character, its definition should look like this:

static const uint8_t letter_b[8] = {16, 16, 22, 25, 17, 17, 30, 0};

What Are Character Banks?

The HD44780 LCD controller allows users to define up to 8 custom characters in its CGRAM (Character Generator RAM). In some applications, 8 characters may not be sufficient for all functionalities but can be enough for specific parts of the system. This limitation can be managed effectively by loading a set of 8 custom characters and replacing them dynamically at different points in the code.

A character bank is a predefined collection of up to 8 custom characters. While only one bank can be active at a time, multiple character banks can be created, each containing different combinations of custom characters.

Depending on the application's requirements, a selected bank can be loaded into CGRAM, and when needed, switched to another bank. This ensures that the LCD displays the appropriate special characters for various parts of the application.


What is lcd_special_chars_map

lcd_special_chars_map is a data structure that plays an important role in handling the display of special characters on an LCD screen. A common use case for this structure is enabling the display of specific language letters from a string passed to the lcd_str() function.

The library uses the map contained within this structure to check whether a given character in the string to be displayed is a special character. If it is, the structure provides the corresponding address or code that points to the correct character in the loaded special character bank. This way, instead of displaying a character that is not supported by the standard LCD character set, the display shows the appropriate graphic or bitmap assigned to that special character.

Example of Usage

Below you can find a simple example of two special character bank definitions. This example includes the initialization of 10 special characters, the setup of 2 character bank structures, and an enumeration definition containing labels for each character position in the character bank.

1. Initialization of Special Characters in lcd_hd44780_def_char.h:

static const uint8_t Pol_e[8] = {0, 0, 14, 17, 31, 16, 14, 3};
static const uint8_t Pol_o[8] = {2, 4, 14, 17, 17, 17, 14, 0};
static const uint8_t Pol_s[8] = {2, 4, 14, 16, 14, 1, 30, 0};
static const uint8_t Pol_l[8] = {12, 4, 6, 12, 4, 4, 14, 0};
static const uint8_t Pol_c[8] = {2, 4, 14, 16, 16, 17, 14, 0};
static const uint8_t Pol_a[8] = {0, 0, 14, 1, 15, 17, 15, 3};
static const uint8_t Pol_n[8] = {2, 4, 22, 25, 17, 17, 17, 0};
static const uint8_t Zn_wody[8] = {0, 0, 0, 6, 9, 2, 4, 15};
static const uint8_t Pol_z1[8] = {4, 32, 31, 2, 4, 8, 31, 0};
static const uint8_t Pol_z2[8] = {2, 4, 31, 2, 4, 8, 31, 0};

2. Initialization of lcd_cgram_bank_1 and Definition of Character Bank 1 Labels in lcd_hd44780_def_char.h:

static const struct char_bank_struct lcd_cgram_bank_1 =
{
  Pol_e,
  Pol_o,
  Pol_s,
  Pol_l,
  Pol_c,
  Pol_a,
  Pol_n,
  Zn_wody
};

enum LCD_CGRAM_BANK_1 
{
  pol_e,
  pol_o,
  pol_s,
  pol_l,
  pol_c,
  pol_a,
  pol_n,
  zn_wody,
};

3. Initialization of lcd_cgram_bank_2 and Definition of Character Bank 2 Labels in lcd_hd44780_def_char.h:

static const struct char_bank_struct lcd_cgram_bank_2 =
{
  Pol_e,
  Pol_o,
  Pol_s,
  Pol_l,
  Pol_c,
  Pol_a,
  Pol_z1,
  Pol_z2
};

enum LCD_CGRAM_BANK_2
{
  pol_e,
  pol_o,
  pol_s,
  pol_l,
  pol_c,
  pol_a,
  pol_z1,
  pol_z2,
};

4. Define lcd_special_chars_map

Based on the Polish letters example, to print special characters directly from a string (e.g., lcd_str("ćma") ) or a single character (e.g., lcd_char('ł') ), define lcd_special_chars_map as follows:

static const LCD_char_mapping_struct_t lcd_special_chars_map[] = {
    {'ę', pol_e}, 
    {'ó', pol_o}, 
    {'ś', pol_s}, 
    {'Ś', pol_s}, 
    {'ł', pol_l}, 
    {'Ł', pol_l}, 
    {'ć', pol_c}, 
    {'Ć', pol_c}, 
    {'ą', pol_a}, 
    {'ń', pol_n}, 
    {'\0', 0}     
};

Size off the structure depends on project and developer needs and it's not related to the max size of lcd_char_bank

If additional functionality like the one described above is not needed, but in general special characters will be used in the project its MANDATORY to define this table with null terminator to inform the library algorithm that there is no special characters in string or single char to parse/replace.

static const LCD_char_mapping_struct_t lcd_special_chars_map[] = {
    {'\0', 0}     
};

DO NOT CHANGE THE STRUCT NAME ( lcd_special_chars_map )

5. Use custom characters in app code

  1. Without 'lcd_special_chars_map' defining (only end/null terminator in table)

    • Load the required lcd_char_bank before printing any char from the bank that you want to currently use:

      lcd_load_char_bank(&lcd_cgram_bank_1);
    • Now you can you lcd_str lcd_buf_str lcd_char lcd_buf_char function as shown bellow:

      // ł
      lcd_char(pol_l);
      // ń
      lcd_buf_char(pol_n);
      // ćma
      lcd_char(pol_c);
      lcd_str("ma");
      // łuk
      lcd_buf_char(pol_l);
      lcd_buf_str("uk");
  2. Without 'lcd_special_chars_map' defining

    • Load the required lcd_char_bank before printing any char from the bank that you want to currently use:

      lcd_load_char_bank(&lcd_cgram_bank_1);
    • Now you can you lcd_str lcd_buf_str lcd_char lcd_buf_char function as shown bellow:

      // ł
      lcd_char('ł');
      // ń
      lcd_buf_char('ń');
      // ćma
      lcd_str("ćma");
      // łuk
      lcd_buf_str("łuk");