14 KiB
Описание компонента zh_160x_i2c
Общие сведения
zh_160x_i2c — это драйвер для ESP-IDF, реализующий управление 16x2 и 16x4 LCD-дисплеями (HD44780-совместимыми) через I2C-расширитель PCF8574.
Компонент предоставляет высокоуровневый API для вывода текста, управления курсором, отображения индикатора прогресса и работы с числовыми данными на жидкокристаллических дисплеях.
Основные возможности
- Поддержка дисплеев 16x2 и 16x4 — автоматическое определение конфигурации экрана.
- 4-битный режим интерфейса — эффективная передача данных через линии D4–D7 (пин P4–P7 PCF8574).
- Вывод строк, целых и вещественных чисел — функции для форматированного вывода числовых данных.
- Отображение индикатора прогресса — 16-блочный прогресс-бар с настраиваемым процентом.
- Управление курсором — включение/выключение курсора и режима мерцания (blink).
- Построчная очистка — очистка произвольной строки дисплея.
Внутреннее устройство
Структура zh_160x_i2c_handle_t
| Поле | Тип | Описание |
|---|---|---|
zh_pcf8574_handle |
zh_pcf8574_handle_t * |
Указатель на управляющую структуру расширителя PCF8574 |
zh_160x_i2c_lcd_size |
zh_160x_i2c_lcd_size_t |
Конфигурация размера LCD (16x2 или 16x4) |
Управляющая структура содержит ссылку на расширитель PCF8574 (который принадлежит вызывающей стороне) и текущую конфигурацию размера дисплея для расчёта адресов строк.
Управление памятью
Память под структуру zh_160x_i2c_handle_t выделяется функцией heap_caps_calloc() с флагом MALLOC_CAP_8BIT при вызове zh_160x_init(). Освобождение происходит через heap_caps_free() в функции zh_160x_deinit(), после чего указатель устанавливается в NULL для предотвращения use-after-free.
Адресация строк HD44780
HD44780-совместимые контроллеры используют нестандартную адресную карту строк:
| Физическая строка | Адрес DDRAM |
|---|---|
| 0 | 0x00 |
| 1 | 0x40 |
| 2 | 0x10 |
| 3 | 0x50 |
Массив _lcd_row_addresses содержит эти адреса и используется функцией zh_160x_set_cursor() для корректного позиционирования курсора.
Протокол инициализации LCD
Инициализация follows HD44780 initialization protocol:
- Задержка 20 мс для стабилизации питания.
- Три команды
0x30с импульсами Enable — перевод в 4-битный режим (последовательность «warm-up»). - Команда
0x20— установка 4-битного режима. - Команда
0x28— функция set: 4-бит, 2 строки, 5x8 точки. - Команда
0x0C— display on, cursor off, blink off. - Команда
0x01— clear display. - Команда
0x06— entry mode: cursor increment, no shift.
API (интерфейс)
Инициализация и освобождение
| Функция | Описание |
|---|---|
zh_160x_init() |
Инициализирует LCD-дисплей, выделяет и настраивает управляющую структуру, отправляет последовательность инициализации контроллеру LCD через расширитель PCF8574. |
zh_160x_deinit() |
Освобождает выделенную память управляющей структуры и устанавливает указатель в NULL. |
Позиционирование и очистка
| Функция | Описание |
|---|---|
zh_160x_lcd_clear() |
Очищает весь экран LCD и перемещает курсор в домашнюю позицию (строка 0, столбец 0). |
zh_160x_set_cursor() |
Устанавливает курсор в указанную позицию (строка и столбец). Для 16x2: строки 0–1, столбцы 0–15. Для 16x4: строки 0–3, столбцы 0–15. |
zh_160x_clear_row() |
Очищает указанную строку (заполняет 16 пробелами) и возвращает курсор в начало строки. |
Вывод данных
| Функция | Описание |
|---|---|
zh_160x_print_char() |
Выводит строку символов в текущую позицию курсора. Курсор автоматически перемещается после каждого символа. |
zh_160x_print_int() |
Преобразует целое число (signed 32-bit) в десятичную строку и выводит на дисплей. |
zh_160x_print_float() |
Преобразует число с плавающей точкой в строку с указанным количеством знаков после запятой и выводит на дисплей. |
Прогресс-бар и курсор
| Функция | Описание |
|---|---|
zh_160x_print_progress_bar() |
Отображает 16-блочный прогресс-бар на указанной строке. Заполненные блоки отображаются как символ с кодом 0xFF (требует настройки CGRAM). |
zh_160x_on_cursor() |
Включает курсор с опциональным режимом мерцания (blink). |
zh_160x_off_cursor() |
Выключает курсор и режим мерцания. |
Потокобезопасность
Компонент не является потокобезопасным. Все операции с LCD-дисплеем требуют внешних механизмов синхронизации (мьютексов, критических секций) при доступе из нескольких задач FreeRTOS. Управляющая структура zh_160x_i2c_handle_t не содержит внутренних примитивов синхронизации.
Алгоритмы
Отправка данных в 4-битном режиме
Команды и данные передаются в два этапа (старший и младший нибблы) через линии D4–D7:
- Отправка команды (
_zh_160x_send_command) — старший ниббл команды записывается на шины с маской0x08(RS=0, P3=1), затем генерируется импульс Enable. Затем младший ниббл (сдвинутый на 4 бита) записывается с той же маской и снова импульс Enable. - Отправка данных (
_zh_160x_send_data) — аналогично, но с маской0x09(RS=1 для режима данных, P3=1). - Импульс Enable (
_zh_160x_pulse) — установка пина P2 в HIGH, задержка 1 мс, установка в LOW, задержка 1 мс. Этот импульс Latch-ит данные в LCD-контроллер.
Прогресс-бар
Процент прогресса конвертируется в количество заполненных блоков по формуле:
blocks = (progress * 16) / 100
Где progress — значение от 0 до 100. Заполненные блоки выводятся как 0xFF (сплошной блок), пустые — как пробелы.
Примеры использования
Базовый вывод текста
#include "zh_160x_i2c.h"
zh_pcf8574_handle_t *pcf8574_handle = NULL;
zh_160x_i2c_handle_t *lcd_160x_handle = NULL;
void app_main(void)
{
// Настройка I2C-шины и инициализация PCF8574...
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, &pcf8574_handle);
// Инициализация LCD 16x2
zh_160x_init(&pcf8574_handle, &lcd_160x_handle, ZH_LCD_16X2);
// Вывод текста на дисплей
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "Hello, LCD!");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "ESP32 Ready");
// Очистка и освобождение ресурсов
vTaskDelay(5000 / portTICK_PERIOD_MS);
zh_160x_lcd_clear(&lcd_160x_handle);
zh_160x_deinit(&lcd_160x_handle);
}
Вывод числовых данных
// Вывод целого числа
int temperature = 25;
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "Temp: ");
zh_160x_print_int(&lcd_160x_handle, temperature);
zh_160x_print_char(&lcd_160x_handle, " C");
// Вывод числа с плавающей точкой (2 знака после запятой)
float voltage = 3.315f;
zh_160x_set_cursor(&lcd_160x_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "VCC: ");
zh_160x_print_float(&lcd_160x_handle, voltage, 2);
zh_160x_print_char(&lcd_160x_handle, " V");
Отображение прогресс-бара
// Прогресс-бар требует настройки CGRAM:
// DDRAM адрес 0xFF должен быть сопоставлен с пользовательским символом (CGRAM pattern 7)
for (uint8_t i = 0; i <= 100; i += 10)
{
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "Progress: ");
zh_160x_print_int(&lcd_160x_handle, i);
zh_160x_print_char(&lcd_160x_handle, "%");
zh_160x_print_progress_bar(&lcd_160x_handle, 1, i);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
zh_160x_lcd_clear(&lcd_160x_handle);
zh_160x_deinit(&lcd_160x_handle);
Логирование
Компонент использует ESP-IDF логирование с тегом "zh_160x_i2c".
esp_log_level_set("zh_160x_i2c", ESP_LOG_ERROR);
Для включения подробного логирования установите уровень ESP_LOG_DEBUG.
Ошибки
| Код | Описание |
|---|---|
ESP_OK |
Успешное выполнение |
ESP_ERR_INVALID_ARG |
Неверный аргумент (NULL-указатель, недопустимый размер дисплея, координаты вне диапазона) |
ESP_ERR_INVALID_STATE |
LCD уже инициализирован (повторная инициализация без деинициализации) |
ESP_ERR_NO_MEM |
Не удалось выделить память под управляющую структуру |
ESP_FAIL |
Ошибка записи/чтения через PCF8574 или сбой последовательности инициализации |
Ограничения
- Зависимость от компонента
zh_pcf8574— требуется установка и инициализация драйвера PCF8574 перед использованием LCD. - Буфер 16 символов — функция
zh_160x_print_float()использует внутренний буфер фиксированной длины; длинные числа могут быть усечены. - Отсутствие потокобезопасности — все операции с LCD требуют внешней синхронизации при работе из нескольких задач FreeRTOS.
- Прогресс-бар требует CGRAM — для отображения заполненных блоков символ с кодом
0xFFдолжен быть настроен как пользовательский символ в CGRAM (паттерн 7 HD44780). - Один I2C-адрес — компонент рассчитан на один LCD-модуль на шину; множественные дисплеи требуют дополнительных расширителей или мультиплексирования.
Требования для сборки
- ESP-IDF v5.0 или новее
- Компонент
zh_pcf8574(зависимость, устанавливается автоматически через idf_component_manager) - FreeRTOS (входит в состав ESP-IDF)
- Настройка
CONFIG_FREERTOS_HZ=1000в menuconfig
Установка
cd ваш_проект/components
git clone https://github.com/aZholtikov/zh_160x_i2c
#include "zh_160x_i2c.h"