24 KiB
zh_160x_i2c - Компонент LCD 1602A/1604A через I2C (PCF8574) для ESP-IDF
Содержание
- Обзор
- Возможности
- Установка
- Справочник API
- Примеры использования
- Технические характеристики
- Коды ошибок
- Подключение
- Вклад в проект
- Лицензия
Обзор
zh_160x_i2c — это легковесный компонент ESP-IDF для управления LCD-дисплеями 1602A и 1604A через интерфейс I2C с использованием расширителей ввода-вывода PCF8574(A). Этот компонент упрощает процесс отображения текста, чисел и индикаторов прогресса на символьных LCD-модулях, предоставляя простой и интуитивно понятный API.
Компонент разработан специально для микроконтроллеров ESP32 и использует драйвер I2C-мастера ESP-IDF и FreeRTOS для оптимальной производительности во встраиваемых системах.
Возможности
- [Простой API]: Удобные функции для распространенных операций с LCD
- [Интерфейс I2C]: Использует только 2 GPIO-пина (SCL и SDA) через расширитель PCF8574
- [Поддержка 1602A и 1604A]: Поддерживает LCD-модули 16x2 и 16x4
- [Множественные LCD]: До 16 LCD-модулей на одной шине I2C
- [Отображение текста]: Вывод строк, целых чисел и чисел с плавающей точкой
- [Управление курсором]: Включение/выключение курсора с опциональным миганием
- [Индикатор прогресса]: Отображение индикаторов прогресса на LCD
- [Операции со строками]: Очистка конкретных строк
- [Оптимизировано под ESP-IDF]: Использует драйвер I2C-мастера ESP-IDF и FreeRTOS
Установка
Перейдите в каталог компонентов вашего проекта:
cd ../ваш_проект/components
Клонируйте репозиторий:
git clone https://github.com/aZholtikov/zh_160x_i2c
В вашем приложении подключите заголовочный файл:
#include "zh_160x_i2c.h"
Компонент будет автоматически собран вместе с вашим проектом.
Обязательные настройки в menuconfig
Для корректной работы компонента включите следующие настройки в menuconfig:
CONFIG_FREERTOS_HZ=1000
CONFIG_I2C_ISR_IRAM_SAFE
CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
Справочник API
Типы данных
zh_160x_i2c_handle_t
typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
Непрозрачный дескриптор LCD-дисплея 160x I2C. Внутренняя структура, содержащая дескриптор расширителя PCF8574 и текущую конфигурацию размера LCD.
zh_160x_i2c_lcd_size_t
typedef enum
{
ZH_LCD_16X2 = 0, /*!< Размер LCD 16x2 */
ZH_LCD_16X4, /*!< Размер LCD 16x4 */
ZH_LCD_NUM_MAX
} zh_160x_i2c_lcd_size_t;
Перечисление поддерживаемых размеров LCD-дисплеев.
| Значение | Описание |
|---|---|
ZH_LCD_16X2 |
LCD размером 16x2 (2 строки по 16 символов) |
ZH_LCD_16X4 |
LCD размером 16x4 (4 строки по 16 символов) |
zh_160x_init()
Инициализирует LCD-дисплей 160x.
Выделяет и настраивает дескриптор LCD, затем отправляет последовательность инициализации на контроллер LCD через расширитель I2C PCF8574. Настраивает 4-битный режим и устанавливает параметры дисплея по умолчанию.
Параметры:
expander- Указатель на дескриптор расширителя PCF8574. Не должен быть NULLhandle- Выходной указатель для нового выделенного дескриптора LCD. Должен быть NULLsize- Размер LCD (ZH_LCD_16X2 или ZH_LCD_16X4)
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL указатель или неверный размер)ESP_ERR_INVALID_STATE- Дескриптор уже инициализированESP_ERR_NO_MEM- Ошибка выделения памятиESP_FAIL- Сбой последовательности инициализации LCD
Пример:
zh_pcf8574_handle_t *lcd_expander = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27;
esp_err_t err = zh_pcf8574_init(&config, &lcd_expander);
if (err != ESP_OK) {
// Обработка ошибки
}
err = zh_160x_init(&lcd_expander, &lcd_handle, ZH_LCD_16X2);
if (err != ESP_OK) {
// Обработка ошибки
}
Примечание:
Перед инициализацией LCD необходимо инициализировать расширитель PCF8574.
zh_160x_lcd_clear()
Очищает экран LCD и перемещает курсор в домашнюю позицию.
Отправляет команду очистки LCD (0x01) для стирания всего отображаемого текста и сброса курсора в верхний левый угол (строка 0, столбец 0).
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULL
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle)ESP_FAIL- Ошибка отправки команды
zh_160x_set_cursor()
Устанавливает курсор в указанную позицию на LCD.
Перемещает курсор в указанную строку и столбец. Для дисплеев 16x2: строки 0–1, столбцы 0–15. Для дисплеев 16x4: строки 0–3, столбцы 0–15.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLrow- Номер строки (0–1 для 16x2, 0–3 для 16x4)col- Номер столбца (0–15)
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle или координаты вне диапазона)ESP_FAIL- Ошибка отправки команды
Примечание:
Адресация строк: строка 0 = 0x00, строка 1 = 0x40, строка 2 = 0x10, строка 3 = 0x50.
zh_160x_print_char()
Выводит строку на LCD в текущую позицию курсора.
Передаёт каждый символ строки, завершающейся нулём, на LCD в 4-битном режиме. Курсор автоматически перемещается после каждого символа.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLstr- Указатель на null-terminated строку для отображения. Не должен быть NULL
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle или str)ESP_FAIL- Ошибка передачи символа
zh_160x_print_int()
Выводит целое число на LCD в текущую позицию курсора.
Преобразует целое число в десятичную строку и отображает её. Поддерживает отрицательные числа (максимум 11 цифр плюс знак).
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLnum- Целочисленное значение для отображения
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle)ESP_FAIL- Ошибка преобразования строки или печати
zh_160x_print_float()
Выводит число с плавающей точкой на LCD в текущую позицию курсора.
Преобразует значение с плавающей точкой в строку с указанной точностью десятичных знаков и отображает её.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLnum- Значение с плавающей точкой для отображенияprecision- Количество знаков после запятой (0–6 рекомендуется)
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle)ESP_FAIL- Ошибка преобразования строки или печати
zh_160x_print_progress_bar()
Отображает индикатор прогресса в указанной строке LCD.
Отрисовывает 16-блочный индикатор прогресса с использованием пользовательского символа (0xFF). Заполненные блоки представляют процент прогресса, пустые блоки показывают остаток.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLrow- Номер строки (0–1 для 16x2, 0–3 для 16x4)progress- Процент прогресса (0–100)
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle, row вне диапазона или progress > 100)ESP_FAIL- Ошибка установки курсора или печати символов
zh_160x_clear_row()
Очищает указанную строку на LCD.
Перемещает курсор в начало указанной строки и заполняет все 16 позиций пробелами для стирания содержимого. Курсор остаётся в начале очищенной строки.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLrow- Номер строки (0–1 для 16x2, 0–3 для 16x4)
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle или row вне диапазона)ESP_FAIL- Ошибка установки курсора или печати символов
zh_160x_on_cursor()
Включает курсор с опциональным режимом мигания.
Включает курсор и при необходимости активирует мигание. Команда 0x0F включает курсор с миганием, 0x0E включает курсор без мигания.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULLblink- Если true, включается мигающий курсор; если false — статичный курсор
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle)ESP_FAIL- Ошибка отправки команды
zh_160x_off_cursor()
Отключает курсор и отключает мигание.
Отправляет команду 0x0C для отключения курсора и мигания курсора.
Параметры:
handle- Указатель на дескриптор LCD. Не должен быть NULL
Возвращает:
ESP_OK- УспехESP_ERR_INVALID_ARG- Неверный аргумент (NULL handle)ESP_FAIL- Ошибка отправки команды
Примеры использования
Базовый пример: Одиночный LCD-дисплей
#include "zh_160x_i2c.h"
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t *lcd_expander = 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);
esp_log_level_set("zh_vector", 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;
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27;
esp_err_t err = zh_pcf8574_init(&config, &lcd_expander);
if (err != ESP_OK) {
return;
}
err = zh_160x_init(&lcd_expander, &lcd_handle, ZH_LCD_16X2);
if (err != ESP_OK) {
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_char(&lcd_handle, "Привет Мир!");
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
}
Пример: Индикатор прогресса
#include "zh_160x_i2c.h"
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t *lcd_expander = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;
void app_main(void)
{
// ... код инициализации ...
for (uint8_t i = 0; i <= 100; ++i)
{
zh_160x_set_cursor(&lcd_handle, 0, 10);
zh_160x_print_int(&lcd_handle, i);
zh_160x_print_char(&lcd_handle, "%");
zh_160x_print_progress_bar(&lcd_handle, 1, i);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
}
Пример: Отображение различных типов данных
#include "zh_160x_i2c.h"
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t *lcd_expander = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;
void app_main(void)
{
// ... код инициализации ...
// Отображение строки
zh_160x_set_cursor(&lcd_handle, 0, 0);
zh_160x_print_char(&lcd_handle, "Строка: ");
zh_160x_print_char(&lcd_handle, "Привет");
// Отображение целого числа
zh_160x_set_cursor(&lcd_handle, 1, 0);
zh_160x_print_int(&lcd_handle, 42);
// Отображение числа с плавающей точкой
zh_160x_set_cursor(&lcd_handle, 0, 0);
zh_160x_print_float(&lcd_handle, 3.14159, 2); // 3.14
// Включение курсора
zh_160x_on_cursor(&lcd_handle, true); // Мигающий курсор
vTaskDelay(2000 / portTICK_PERIOD_MS);
// Отключение курсора
zh_160x_off_cursor(&lcd_handle);
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
}
Пример: Несколько LCD на одной шине
#include "zh_160x_i2c.h"
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t *lcd1_expander = NULL;
zh_160x_i2c_handle_t *lcd1_handle = NULL;
zh_pcf8574_handle_t *lcd2_expander = NULL;
zh_160x_i2c_handle_t *lcd2_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);
esp_log_level_set("zh_vector", 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;
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
// Инициализация первого LCD по адресу 0x27
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27;
zh_pcf8574_init(&config, &lcd1_expander);
zh_160x_init(&lcd1_expander, &lcd1_handle, ZH_LCD_16X2);
// Инициализация второго LCD по адресу 0x26
config.i2c_address = 0x26;
zh_pcf8574_init(&config, &lcd2_expander);
zh_160x_init(&lcd2_expander, &lcd2_handle, ZH_LCD_16X2);
// Отображение на первом LCD
zh_160x_set_cursor(&lcd1_handle, 0, 0);
zh_160x_print_char(&lcd1_handle, "LCD 1");
// Отображение на втором LCD
zh_160x_set_cursor(&lcd2_handle, 0, 0);
zh_160x_print_char(&lcd2_handle, "LCD 2");
// Очистка ресурсов
zh_160x_deinit(&lcd1_handle);
zh_160x_deinit(&lcd2_handle);
}
Технические характеристики
| Параметр | Значение |
|---|---|
| Типы LCD | 1602A (16x2), 1604A (16x4) |
| Интерфейс | I2C через PCF8574(A) |
| Диапазон адресов I2C | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) |
| Макс. LCD на шине | 16 |
| Использование GPIO | 2 (SCL, SDA) |
| Версия ESP-IDF | >= 5.0 |
| Платформа | Серия ESP32 |
| Язык | C (C99) |
Коды ошибок
| Код ошибки | Описание |
|---|---|
ESP_OK |
Операция выполнена успешно |
ESP_ERR_INVALID_ARG |
Неверный аргумент (NULL указатель или неверное значение) |
ESP_ERR_INVALID_STATE |
Дескриптор не инициализирован |
ESP_FAIL |
Общий сбой (ошибка связи I2C) |
Подключение
Подключение 1602A/1604A к PCF8574
| Пин LCD | Пин PCF8574 | Описание |
|---|---|---|
| RS | P0 | Выбор регистра |
| E | P2 | Enable |
| D4 | P4 | Бит данных 4 |
| D5 | P5 | Бит данных 5 |
| D6 | P6 | Бит данных 6 |
| D7 | P7 | Бит данных 7 |
Подключение I2C
| LCD-модуль | PCF8574 | ESP32 |
|---|---|---|
| VCC | VCC | 3.3V |
| GND | GND | GND |
| SDA | SDA | GPIO21 |
| SCL | SCL | GPIO22 |
| RW | GND | GND |
Примечание: Пин RW должен быть подключен к GND для операции только записи.
Вклад в проект
Вклад приветствуется! Чтобы внести свой вклад:
- Сделайте форк репозитория
- Создайте ветку функции (
git checkout -b feature/AmazingFeature) - Закоммитьте ваши изменения (
git commit -m 'Add some AmazingFeature') - Отправьте в ветку (
git push origin feature/AmazingFeature) - Откройте Pull Request
Пожалуйста, убедитесь, что ваш код следует существующему стилю и включает соответствующую документацию.
Лицензия
Этот проект лицензирован по лицензии Apache, версия 2.0 - см. файл LICENSE для подробной информации.
Apache License, Version 2.0
Авторское право (c) 2026 Алексей Жолтиков
Лицензировано по лицензии Apache License, Version 2.0 (далее — "Лицензия"); вы не можете использовать этот файл, кроме случаев, предусмотренных Лицензией. Копию Лицензии можно получить по адресу:
http://www.apache.org/licenses/LICENSE-2.0
Если иное не требуется действующим законодательством или не согласовано в письменном виде, программное обеспечение, распространяемое по Лицензии, распространяется на условиях "КАК ЕСТЬ", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, явных или подразумеваемых, включая, но не ограничиваясь, гарантии ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ И НЕНАРУШЕНИЯ ПРАВ. Смотрите Лицензию для получения конкретных прав и ограничений.
Дополнительные заметки
- Подтягивающие резисторы I2C: Используйте резисторы 4.7 кОм на линиях SDA и SCL для надежной связи
- Питание: Обеспечьте стабильное питание 5 В для LCD-модуля (PCF8574 совместим с 5 В)
- Настройка контраста: Используйте встроенный подстроечный резистор для настройки контраста LCD для оптимальной видимости
- Подсветка: Подсветка LCD обычно подключается к VCC через резистор ограничения тока
- Производительность: Операции блокирующие и используют задержки FreeRTOS для правильного тайминга
- I2C_ISR_IRAM_SAFE: Для правильной работы включите
I2C_ISR_IRAM_SAFEиI2C_MASTER_ISR_HANDLER_IN_IRAMв menuconfig - FreeRTOS: Для корректной работы настройте
CONFIG_FREERTOS_HZ=1000в menuconfig - Лучшие практики:
- Всегда инициализируйте PCF8574 перед инициализацией LCD
- Проверьте адрес I2C с помощью сканера, если LCD не отвечает
- Учитывайте ограничения скорости шины I2C при использовании нескольких устройств
Generated for zh_160x_i2c v5.0.0