Files
2026-10-17 21:18:53 +03:00

6.2 KiB

ESP32 ESP-IDF component for LCD 1602A/1604A via I2C (PCF8574)

Features

  1. Support for HD44780-compatible 16x2 and 16x4 LCD displays via I2C.
  2. 4-bit interface mode for efficient data transfer through PCF8574 expander.
  3. Print strings, integers, and floating-point numbers to the display.
  4. Progress bar display with custom characters on any row.
  5. Cursor visibility and blink control.
  6. Row-specific clear operations in addition to full screen clear.

Attention

  1. The PCF8574 expander handle must remain valid until the LCD handle is deinitialized.
  2. DDRAM location 0xFF must be configured as a custom character in CGRAM for progress bar to display correctly.

Using

In an existing project, run the following command to install the component:

cd ../your_project/components
git clone https://github.com/aZholtikov/zh_160x_i2c

In the application, add the component:

#include "zh_160x_i2c.h"

Examples

Basic Text Output Example

#include "zh_160x_i2c.h"

#define I2C_PORT (I2C_NUM_MAX - 1)

zh_pcf8574_handle_t *pcf8574_handle = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;

void app_main(void)
{
    esp_log_level_set("zh_160x_i2c", ESP_LOG_ERROR);
    esp_log_level_set("zh_pcf8574", ESP_LOG_ERROR);
    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = I2C_PORT,
        .scl_io_num = GPIO_NUM_22,
        .sda_io_num = GPIO_NUM_21,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = true,
    };
    i2c_master_bus_handle_t i2c_bus_handle = NULL;
    esp_err_t ret = i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
    if (ret != ESP_OK)
    {
        printf("I2C bus initialization error\n");
        return;
    }
    zh_pcf8574_init_config_t pcf_config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
    pcf_config.i2c_handle = i2c_bus_handle;
    pcf_config.i2c_address = 0x27;
    ret = zh_pcf8574_init(&pcf_config, &pcf8574_handle);
    if (ret != ESP_OK)
    {
        printf("PCF8574 initialization error\n");
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    ret = zh_160x_init(&pcf8574_handle, &lcd_handle, ZH_LCD_16X2);
    if (ret != ESP_OK)
    {
        printf("LCD initialization error\n");
        zh_pcf8574_deinit(&pcf8574_handle);
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    zh_160x_set_cursor(&lcd_handle, 0, 0);
    zh_160x_print_char(&lcd_handle, "LCD 160X");
    zh_160x_set_cursor(&lcd_handle, 1, 0);
    zh_160x_print_int(&lcd_handle, 42);
    zh_160x_off_cursor(&lcd_handle);
    zh_160x_deinit(&lcd_handle);
    zh_pcf8574_deinit(&pcf8574_handle);
    i2c_del_master_bus(i2c_bus_handle);
}

Float and Cursor Control Example

#include "zh_160x_i2c.h"

#define I2C_PORT (I2C_NUM_MAX - 1)

zh_pcf8574_handle_t *pcf8574_handle = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;

void app_main(void)
{
    esp_log_level_set("zh_160x_i2c", ESP_LOG_ERROR);
    esp_log_level_set("zh_pcf8574", ESP_LOG_ERROR);
    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = I2C_PORT,
        .scl_io_num = GPIO_NUM_22,
        .sda_io_num = GPIO_NUM_21,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = true,
    };
    i2c_master_bus_handle_t i2c_bus_handle = NULL;
    esp_err_t ret = i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
    if (ret != ESP_OK)
    {
        printf("I2C bus initialization error\n");
        return;
    }
    zh_pcf8574_init_config_t pcf_config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
    pcf_config.i2c_handle = i2c_bus_handle;
    pcf_config.i2c_address = 0x27;
    ret = zh_pcf8574_init(&pcf_config, &pcf8574_handle);
    if (ret != ESP_OK)
    {
        printf("PCF8574 initialization error\n");
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    ret = zh_160x_init(&pcf8574_handle, &lcd_handle, ZH_LCD_16X2);
    if (ret != ESP_OK)
    {
        printf("LCD initialization error\n");
        zh_pcf8574_deinit(&pcf8574_handle);
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    zh_160x_on_cursor(&lcd_handle, true);
    zh_160x_set_cursor(&lcd_handle, 0, 0);
    zh_160x_print_char(&lcd_handle, "Temp: ");
    zh_160x_print_float(&lcd_handle, 23.67f, 2);
    zh_160x_clear_row(&lcd_handle, 1);
    zh_160x_set_cursor(&lcd_handle, 1, 0);
    zh_160x_print_char(&lcd_handle, "Row cleared");
    zh_160x_off_cursor(&lcd_handle);
    zh_160x_deinit(&lcd_handle);
    zh_pcf8574_deinit(&pcf8574_handle);
    i2c_del_master_bus(i2c_bus_handle);
}

Progress Bar Example

#include "zh_160x_i2c.h"

#define I2C_PORT (I2C_NUM_MAX - 1)

zh_pcf8574_handle_t *pcf8574_handle = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;

void app_main(void)
{
    esp_log_level_set("zh_160x_i2c", ESP_LOG_ERROR);
    esp_log_level_set("zh_pcf8574", ESP_LOG_ERROR);
    i2c_master_bus_config_t i2c_bus_config = {
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .i2c_port = I2C_PORT,
        .scl_io_num = GPIO_NUM_22,
        .sda_io_num = GPIO_NUM_21,
        .glitch_ignore_cnt = 7,
        .flags.enable_internal_pullup = true,
    };
    i2c_master_bus_handle_t i2c_bus_handle = NULL;
    esp_err_t ret = i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
    if (ret != ESP_OK)
    {
        printf("I2C bus initialization error\n");
        return;
    }
    zh_pcf8574_init_config_t pcf_config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
    pcf_config.i2c_handle = i2c_bus_handle;
    pcf_config.i2c_address = 0x27;
    ret = zh_pcf8574_init(&pcf_config, &pcf8574_handle);
    if (ret != ESP_OK)
    {
        printf("PCF8574 initialization error\n");
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    ret = zh_160x_init(&pcf8574_handle, &lcd_handle, ZH_LCD_16X2);
    if (ret != ESP_OK)
    {
        printf("LCD initialization error\n");
        zh_pcf8574_deinit(&pcf8574_handle);
        i2c_del_master_bus(i2c_bus_handle);
        return;
    }
    zh_160x_set_cursor(&lcd_handle, 0, 0);
    zh_160x_print_char(&lcd_handle, "Progress: ");
    zh_160x_print_progress_bar(&lcd_handle, 1, 75);
    zh_160x_lcd_clear(&lcd_handle);
    zh_160x_deinit(&lcd_handle);
    zh_pcf8574_deinit(&pcf8574_handle);
    i2c_del_master_bus(i2c_bus_handle);
}