# Описание компонента zh_160x_i2c ## Общие сведения **zh_160x_i2c** — это драйвер для ESP-IDF, реализующий управление 16x2 и 16x4 LCD-дисплеями (HD44780-совместимыми) через I2C-расширитель PCF8574. Компонент предоставляет высокоуровневый API для вывода текста, управления курсором, отображения индикатора прогресса и работы с числовыми данными на жидкокристаллических дисплеях. ## Основные возможности 1. **Поддержка дисплеев 16x2 и 16x4** — автоматическое определение конфигурации экрана. 2. **4-битный режим интерфейса** — эффективная передача данных через линии D4–D7 (пин P4–P7 PCF8574). 3. **Вывод строк, целых и вещественных чисел** — функции для форматированного вывода числовых данных. 4. **Отображение индикатора прогресса** — 16-блочный прогресс-бар с настраиваемым процентом. 5. **Управление курсором** — включение/выключение курсора и режима мерцания (blink). 6. **Построчная очистка** — очистка произвольной строки дисплея. ## Внутреннее устройство ### Структура `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: 1. Задержка 20 мс для стабилизации питания. 2. Три команды `0x30` с импульсами Enable — перевод в 4-битный режим (последовательность «warm-up»). 3. Команда `0x20` — установка 4-битного режима. 4. Команда `0x28` — функция set: 4-бит, 2 строки, 5x8 точки. 5. Команда `0x0C` — display on, cursor off, blink off. 6. Команда `0x01` — clear display. 7. Команда `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: 1. **Отправка команды (`_zh_160x_send_command`)** — старший ниббл команды записывается на шины с маской `0x08` (RS=0, P3=1), затем генерируется импульс Enable. Затем младший ниббл (сдвинутый на 4 бита) записывается с той же маской и снова импульс Enable. 2. **Отправка данных (`_zh_160x_send_data`)** — аналогично, но с маской `0x09` (RS=1 для режима данных, P3=1). 3. **Импульс Enable (`_zh_160x_pulse`)** — установка пина P2 в HIGH, задержка 1 мс, установка в LOW, задержка 1 мс. Этот импульс Latch-ит данные в LCD-контроллер. ### Прогресс-бар Процент прогресса конвертируется в количество заполненных блоков по формуле: ``` blocks = (progress * 16) / 100 ``` Где `progress` — значение от 0 до 100. Заполненные блоки выводятся как `0xFF` (сплошной блок), пустые — как пробелы. ## Примеры использования ### Базовый вывод текста ```c #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); } ``` ### Вывод числовых данных ```c // Вывод целого числа 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"); ``` ### Отображение прогресс-бара ```c // Прогресс-бар требует настройки 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"`. ```c 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 или сбой последовательности инициализации | ## Ограничения 1. **Зависимость от компонента `zh_pcf8574`** — требуется установка и инициализация драйвера PCF8574 перед использованием LCD. 2. **Буфер 16 символов** — функция `zh_160x_print_float()` использует внутренний буфер фиксированной длины; длинные числа могут быть усечены. 3. **Отсутствие потокобезопасности** — все операции с LCD требуют внешней синхронизации при работе из нескольких задач FreeRTOS. 4. **Прогресс-бар требует CGRAM** — для отображения заполненных блоков символ с кодом `0xFF` должен быть настроен как пользовательский символ в CGRAM (паттерн 7 HD44780). 5. **Один I2C-адрес** — компонент рассчитан на один LCD-модуль на шину; множественные дисплеи требуют дополнительных расширителей или мультиплексирования. ## Требования для сборки - ESP-IDF v5.0 или новее - Компонент `zh_pcf8574` (зависимость, устанавливается автоматически через idf_component_manager) - FreeRTOS (входит в состав ESP-IDF) - Настройка `CONFIG_FREERTOS_HZ=1000` в menuconfig ## Установка ```bash cd ваш_проект/components git clone https://github.com/aZholtikov/zh_160x_i2c ``` ```c #include "zh_160x_i2c.h" ```