Files
2026-10-17 21:19:35 +03:00

232 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Описание компонента 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"
```