feat!: main structure of handle changed to double pointer

This commit is contained in:
aZholtikov committed 2026-08-25 19:57:53 +03:00
1 parent a37cab782c
commit 4abc0209b6
7 files changed
+646 -361

No files matched your search

+10 -84
View File
@@ -1,4 +1,4 @@
# ESP32 ESP-IDF component for liquid crystal display module 1602(4)A via I2C connection (PCF8574(A))
# ESP32 ESP-IDF component for LCD 1602A/1604A via I2C (PCF8574)
## Wiki
@@ -10,41 +10,20 @@
## SAST Tools
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) — static analyzer for C, C++, C#, and Java code.
## Features
1. Support of 16 LCD 160X on one bus.
## Attention
For correct operation, please enable the following settings in the menuconfig:
```text
CONFIG_FREERTOS_HZ=1000
CONFIG_GPIO_CTRL_FUNC_IN_IRAM
CONFIG_I2C_ISR_IRAM_SAFE
CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
```
## Connection
| 1602(4)A | PCF8574 |
| -------- | ------- |
| RS | P0 |
| E | P2 |
| D4 | P4 |
| D5 | P5 |
| D6 | P6 |
| D7 | P7 |
## Dependencies
1. [zh_pcf8574](https://github.com/aZholtikov/zh_pcf8574)
1. Support for up to 16 LCD 160X displays on one I2C bus.
2. 4-bit interface mode for efficient data transfer via PCF8574 expander.
3. Print strings, integers, and floating-point numbers.
4. Progress bar display with custom characters.
5. Cursor visibility and blink control.
6. Row-specific clear operations.
## Using
In an existing project, run the following command to install the components:
In an existing project, run the following command to install the component:
```text
cd ../your_project/components
@@ -59,57 +38,4 @@ In the application, add the component:
## Examples
One LCD on bus:
```c
#include "zh_160x_i2c.h"
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd_160x_handle = {0};
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;
zh_pcf8574_init(&config, &lcd_160x_handle);
zh_160x_init(&lcd_160x_handle, ZH_LCD_16X2);
for (;;)
{
zh_160x_on_cursor(&lcd_160x_handle, true);
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "LCD 160X");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "Hello World!");
vTaskDelay(5000 / portTICK_PERIOD_MS);
zh_160x_off_cursor(&lcd_160x_handle);
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "Progress: ");
for (uint8_t i = 0; i <= 100; ++i)
{
zh_160x_set_cursor(&lcd_160x_handle, 0, 10);
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(100 / portTICK_PERIOD_MS);
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
zh_160x_lcd_clear(&lcd_160x_handle);
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}
```
See Wiki [EN](WIKI_EN.md#usage-examples) | [RU](WIKI_RU.md#примеры-использования)
+177 -80
View File
@@ -1,4 +1,4 @@
# zh_160x_i2c - ESP32 ESP-IDF Component for LCD 1602A/1604A via I2C (PCF8574)
# zh_160x_i2c - LCD 1602A/1604A via I2C (PCF8574) Component for ESP-IDF
## Table of Contents
@@ -25,39 +25,39 @@ The component is designed specifically for ESP32 microcontrollers and uses ESP-I
## Features
1. **Simple API**: Easy-to-use functions for common LCD operations
2. **I2C Interface**: Uses only 2 GPIO pins (SCL and SDA) via PCF8574 expander
3. **Support for 1602A and 1604A**: Supports both 16x2 and 16x4 LCD modules
4. **Multiple LCD Support**: Up to 8 LCD modules on one I2C bus (PCF8574) or 4 (PCF8574A)
5. **Text Display**: Print strings, integers, and floating-point numbers
6. **Cursor Control**: Enable/disable cursor with optional blink
7. **Progress Bar**: Display progress bars on LCD
8. **Row Operations**: Clear specific rows
9. **ESP-IDF Optimized**: Uses ESP-IDF's I2C master driver and FreeRTOS
1. **[Simple API]**: Easy-to-use functions for common LCD operations
2. **[I2C Interface]**: Uses only 2 GPIO pins (SCL and SDA) via PCF8574 expander
3. **[Support for 1602A and 1604A]**: Supports both 16x2 and 16x4 LCD modules
4. **[Multiple LCD Support]**: Up to 16 LCD modules on one I2C bus
5. **[Text Display]**: Print strings, integers, and floating-point numbers
6. **[Cursor Control]**: Enable/disable cursor with optional blink
7. **[Progress Bar]**: Display progress bars on LCD
8. **[Row Operations]**: Clear specific rows
9. **[ESP-IDF Optimized]**: Uses ESP-IDF's I2C master driver and FreeRTOS
---
## Installation
1. Navigate to your project's components directory:
Navigate to your project's components directory:
```bash
cd ../your_project/components
```
2. Clone the repository:
Clone the repository:
```bash
git clone https://github.com/aZholtikov/zh_160x_i2c
```
3. In your application, include the header:
In your application, include the header:
```c
#include "zh_160x_i2c.h"
```
4. The component will be automatically built with your project.
The component will be automatically built with your project.
### Required menuconfig Settings
@@ -73,55 +73,97 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
## API Reference
### Configuration Constants
### Data Types
#### zh_160x_i2c_handle_t
```c
#define ZH_LCD_16X2 1 // LCD size 16x2
#define ZH_LCD_16X4 0 // LCD size 16x4
typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
```
Opaque handle for LCD 160x I2C display. Internal structure containing the PCF8574 expander handle and the current LCD size configuration.
---
#### zh_160x_i2c_lcd_size_t
```c
typedef enum
{
ZH_LCD_16X2 = 0, /*!< LCD size 16x2 */
ZH_LCD_16X4, /*!< LCD size 16x4 */
ZH_LCD_NUM_MAX
} zh_160x_i2c_lcd_size_t;
```
Enumeration of supported LCD display sizes.
| Value | Description |
|-------|-------------|
| `ZH_LCD_16X2` | LCD size 16x2 (2 rows of 16 characters) |
| `ZH_LCD_16X4` | LCD size 16x4 (4 rows of 16 characters) |
---
### zh_160x_init()
Initializes the LCD 160X module.
Initializes the LCD 160x display.
Allocates and configures the LCD handle, then sends the initialization sequence to the LCD controller via the PCF8574 I2C expander. Configures 4-bit mode and sets default display parameters.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle (must be already initialized)
- `expander` - Pointer to the PCF8574 expander handle. Must not be NULL
- `handle` - Output pointer for the newly allocated LCD handle. Must be NULL
- `size` - LCD size (ZH_LCD_16X2 or ZH_LCD_16X4)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or handle not initialized)
- `ESP_FAIL` - Initialization failed
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL pointer or invalid size)
- `ESP_ERR_INVALID_STATE` - Handle already initialized
- `ESP_ERR_NO_MEM` - Memory allocation failure
- `ESP_FAIL` - LCD initialization sequence failure
**Example:**
```c
zh_pcf8574_handle_t lcd_handle = {0};
// Initialize PCF8574 first
zh_pcf8574_init(&config, &lcd_handle);
// Then initialize LCD
zh_160x_init(&lcd_handle, ZH_LCD_16X2);
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) {
// Error handling
}
err = zh_160x_init(&lcd_expander, &lcd_handle, ZH_LCD_16X2);
if (err != ESP_OK) {
// Error handling
}
```
**Note:**
The PCF8574 expander must be initialized before initializing the LCD.
---
### zh_160x_lcd_clear()
Clears the entire LCD screen.
Clears the LCD screen and moves the cursor to the home position.
Sends the LCD clear command (0x01) to erase all displayed text and reset the cursor to the upper-left corner (row 0, column 0).
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `handle` - Pointer to the LCD handle. Must not be NULL
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - Command send failure
---
@@ -129,69 +171,84 @@ Clears the entire LCD screen.
Sets the cursor to a specific position on the LCD.
Moves the cursor to the specified row and column.
For 16x2 displays: rows 0–1, columns 0–15.
For 16x4 displays: rows 0–3, columns 0–15.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4)
- `col` - Column number (0-15)
- `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
- `col` - Column number (0–15)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row/col)
- `ESP_FAIL` - Operation failed
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or coordinates out of range)
- `ESP_FAIL` - Command send failure
**Note:**
Row address mapping: row 0 = 0x00, row 1 = 0x40, row 2 = 0x10, row 3 = 0x50.
---
### zh_160x_print_char()
Prints a string to the LCD.
Prints a string to the LCD at the current cursor position.
Transmits each character of the null-terminated string to the LCD in 4-bit mode. The cursor advances automatically after each character.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `str` - Pointer to the null-terminated string to display
- `handle` - Pointer to the LCD handle. Must not be NULL
- `str` - Pointer to the null-terminated string to display. Must not be NULL
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or str)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - Character transmission failure
---
### zh_160x_print_int()
Prints an integer to the LCD.
Prints an integer to the LCD at the current cursor position.
Converts the integer to a decimal string and displays it.
Supports negative numbers (maximum 11 digits plus sign).
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `handle` - Pointer to the LCD handle. Must not be NULL
- `num` - Integer value to display
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - String conversion or print failure
---
### zh_160x_print_float()
Prints a floating-point number to the LCD.
Prints a floating-point number to the LCD at the current cursor position.
Converts the floating-point value to a string with the specified decimal precision and displays it.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `handle` - Pointer to the LCD handle. Must not be NULL
- `num` - Floating-point value to display
- `precision` - Number of decimal places (0-9)
- `precision` - Number of decimal places (0–6 recommended)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - String conversion or print failure
---
@@ -199,17 +256,20 @@ Prints a floating-point number to the LCD.
Displays a progress bar on a specific row of the LCD.
Renders a 16-block progress bar using a custom character (0xFF).
Filled blocks represent the progress percentage, empty blocks show the remainder.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4)
- `progress` - Progress percentage (0-100)
- `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
- `progress` - Progress percentage (0–100)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row or progress)
- `ESP_FAIL` - Operation failed
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, row out of range, or progress > 100)
- `ESP_FAIL` - Cursor positioning or character print failure
---
@@ -217,16 +277,19 @@ Displays a progress bar on a specific row of the LCD.
Clears a specific row on the LCD.
Moves the cursor to the beginning of the specified row and fills all 16 positions with spaces to erase existing content.
The cursor remains at the start of the cleared row.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4)
- `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row)
- `ESP_FAIL` - Operation failed
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or row out of range)
- `ESP_FAIL` - Cursor positioning or character print failure
---
@@ -234,32 +297,37 @@ Clears a specific row on the LCD.
Enables the cursor with optional blink mode.
Turns on the cursor and optionally enables blinking.
Command 0x0F enables cursor with blink, 0x0E enables cursor only.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `blink` - If true, cursor blinks; if false, cursor is steady
- `handle` - Pointer to the LCD handle. Must not be NULL
- `blink` - If true, enables blinking cursor; if false, solid cursor
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - Command send failure
---
### zh_160x_off_cursor()
Disables the cursor.
Hides the cursor and disables blinking.
Sends command 0x0C to turn off both cursor and cursor blink.
**Parameters:**
- `handle` - Pointer to unique PCF8574 handle
- `handle` - Pointer to the LCD handle (not NULL)
**Returns:**
- `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed
- `ESP_FAIL` - Command send failure
---
@@ -272,7 +340,8 @@ Disables the cursor.
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd_160x_handle = {0};
zh_pcf8574_handle_t *lcd_expander = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;
void app_main(void)
{
@@ -287,19 +356,26 @@ void app_main(void)
.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;
zh_pcf8574_init(&config, &lcd_160x_handle);
zh_160x_init(&lcd_160x_handle, ZH_LCD_16X2);
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;
}
// Display text
zh_160x_set_cursor(&lcd_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "LCD 160X");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "Hello World!");
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, "Hello World!");
// Cleanup
zh_160x_deinit(&lcd_handle);
}
```
@@ -308,9 +384,13 @@ void app_main(void)
```c
#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_pcf8574_handle_t lcd_handle = {0};
// ... initialization code ...
for (uint8_t i = 0; i <= 100; ++i)
{
@@ -320,6 +400,8 @@ void app_main(void)
zh_160x_print_progress_bar(&lcd_handle, 1, i);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Cleanup
zh_160x_deinit(&lcd_handle);
}
```
@@ -328,9 +410,13 @@ void app_main(void)
```c
#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_pcf8574_handle_t lcd_handle = {0};
// ... initialization code ...
// Display string
zh_160x_set_cursor(&lcd_handle, 0, 0);
@@ -347,6 +433,8 @@ void app_main(void)
vTaskDelay(2000 / portTICK_PERIOD_MS);
// Disable cursor
zh_160x_off_cursor(&lcd_handle);
// Cleanup
zh_160x_deinit(&lcd_handle);
}
```
@@ -357,8 +445,10 @@ void app_main(void)
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd1_handle = {0};
zh_pcf8574_handle_t lcd2_handle = {0};
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)
{
@@ -379,18 +469,21 @@ void app_main(void)
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_handle);
zh_160x_init(&lcd1_handle, ZH_LCD_16X2);
zh_pcf8574_init(&config, &lcd1_expander);
zh_160x_init(&lcd1_expander, &lcd1_handle, ZH_LCD_16X2);
// Initialize second LCD at address 0x26
config.i2c_address = 0x26;
zh_pcf8574_init(&config, &lcd2_handle);
zh_160x_init(&lcd2_handle, ZH_LCD_16X2);
zh_pcf8574_init(&config, &lcd2_expander);
zh_160x_init(&lcd2_expander, &lcd2_handle, ZH_LCD_16X2);
// Display on first LCD
zh_160x_set_cursor(&lcd1_handle, 0, 0);
zh_160x_print_char(&lcd1_handle, "LCD 1");
// Display on second LCD
zh_160x_set_cursor(&lcd2_handle, 0, 0);
zh_160x_print_char(&lcd2_handle, "LCD 2");
// Cleanup
zh_160x_deinit(&lcd1_handle);
zh_160x_deinit(&lcd2_handle);
}
```
@@ -399,14 +492,14 @@ void app_main(void)
## Technical Specifications
| Parameter | Value |
|-----------|-------|
| ----------- | ------- |
| **LCD Types** | 1602A (16x2), 1604A (16x4) |
| **Interface** | I2C via PCF8574(A) |
| **I2C Address Range** | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) |
| **Max LCDs per Bus** | 16 |
| **GPIO Usage** | 2 (SCL, SDA) |
| **ESP-IDF Version** | >= 5.0|
| **Platform** | ESP32 family |
| **ESP-IDF Version** | >= 5.0 |
| **Platform** | ESP32 series |
| **Language** | C (C99) |
---
@@ -414,7 +507,7 @@ void app_main(void)
## Error Codes
| Error Code | Description |
|------------|-------------|
| ------------ | ------------- |
| `ESP_OK` | Operation completed successfully |
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid value) |
| `ESP_ERR_INVALID_STATE` | Handle not initialized |
@@ -498,3 +591,7 @@ limitations under the License.
- Always initialize PCF8574 before initializing LCD
- Check I2C address using a scanner if LCD does not respond
- Consider I2C bus speed limitations when using multiple devices
---
*Generated for zh_160x_i2c v5.0.0*
+179 -82
View File
@@ -1,4 +1,4 @@
# zh_160x_i2c - Компонент ESP32 ESP-IDF для LCD 1602A/1604A через I2C (PCF8574)
# zh_160x_i2c - Компонент LCD 1602A/1604A через I2C (PCF8574) для ESP-IDF
## Содержание
@@ -25,39 +25,39 @@
## Возможности
1. **Простой API**: Удобные функции для распространенных операций с LCD
2. **Интерфейс I2C**: Использует только 2 GPIO-пина (SCL и SDA) через расширитель PCF8574
3. **Поддержка 1602A и 1604A**: Поддерживает LCD-модули 16x2 и 16x4
4. **Множественные LCD**: До 16 LCD-модулей на одной шине I2C
5. **Отображение текста**: Вывод строк, целых чисел и чисел с плавающей точкой
6. **Управление курсором**: Включение/выключение курсора с опциональным миганием
7. **Индикатор прогресса**: Отображение индикаторов прогресса на LCD
8. **Операции со строками**: Очистка конкретных строк
9. **Оптимизировано под ESP-IDF**: Использует драйвер I2C-мастера ESP-IDF и FreeRTOS
1. **[Простой API]**: Удобные функции для распространенных операций с LCD
2. **[Интерфейс I2C]**: Использует только 2 GPIO-пина (SCL и SDA) через расширитель PCF8574
3. **[Поддержка 1602A и 1604A]**: Поддерживает LCD-модули 16x2 и 16x4
4. **[Множественные LCD]**: До 16 LCD-модулей на одной шине I2C
5. **[Отображение текста]**: Вывод строк, целых чисел и чисел с плавающей точкой
6. **[Управление курсором]**: Включение/выключение курсора с опциональным миганием
7. **[Индикатор прогресса]**: Отображение индикаторов прогресса на LCD
8. **[Операции со строками]**: Очистка конкретных строк
9. **[Оптимизировано под ESP-IDF]**: Использует драйвер I2C-мастера ESP-IDF и FreeRTOS
---
## Установка
1. Перейдите в каталог компонентов вашего проекта:
Перейдите в каталог компонентов вашего проекта:
```bash
cd ../ваш_проект/components
```
2. Клонируйте репозиторий:
Клонируйте репозиторий:
```bash
git clone https://github.com/aZholtikov/zh_160x_i2c
```
3. В вашем приложении подключите заголовочный файл:
В вашем приложении подключите заголовочный файл:
```c
#include "zh_160x_i2c.h"
```
4. Компонент будет автоматически собран вместе с вашим проектом.
Компонент будет автоматически собран вместе с вашим проектом.
### Обязательные настройки в menuconfig
@@ -73,160 +73,223 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
## Справочник API
### Константы конфигурации
### Типы данных
#### zh_160x_i2c_handle_t
```c
#define ZH_LCD_16X2 1 // Размер LCD 16x2
#define ZH_LCD_16X4 0 // Размер LCD 16x4
typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
```
Непрозрачный дескриптор LCD-дисплея 160x I2C. Внутренняя структура, содержащая дескриптор расширителя PCF8574 и текущую конфигурацию размера LCD.
---
#### zh_160x_i2c_lcd_size_t
```c
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-дисплей 160x.
Выделяет и настраивает дескриптор LCD, затем отправляет последовательность инициализации на контроллер LCD через расширитель I2C PCF8574. Настраивает 4-битный режим и устанавливает параметры дисплея по умолчанию.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 (должен быть уже инициализирован)
- `expander` - Указатель на дескриптор расширителя PCF8574. Не должен быть NULL
- `handle` - Выходной указатель для нового выделенного дескриптора LCD. Должен быть NULL
- `size` - Размер LCD (ZH_LCD_16X2 или ZH_LCD_16X4)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или handle не инициализирован)
- `ESP_FAIL` - Ошибка инициализации
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель или неверный размер)
- `ESP_ERR_INVALID_STATE` - Дескриптор уже инициализирован
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти
- `ESP_FAIL` - Сбой последовательности инициализации LCD
**Пример:**
```c
zh_pcf8574_handle_t lcd_handle = {0};
// Сначала инициализируйте PCF8574
zh_pcf8574_init(&config, &lcd_handle);
// Затем инициализируйте LCD
zh_160x_init(&lcd_handle, ZH_LCD_16X2);
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 и перемещает курсор в домашнюю позицию.
Отправляет команду очистки LCD (0x01) для стирания всего отображаемого текста и сброса курсора в верхний левый угол (строка 0, столбец 0).
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка отправки команды
---
### zh_160x_set_cursor()
Устанавливает курсор в определенную позицию на LCD.
Устанавливает курсор в указанную позицию на LCD.
Перемещает курсор в указанную строку и столбец.
Для дисплеев 16x2: строки 0–1, столбцы 0–15.
Для дисплеев 16x4: строки 0–3, столбцы 0–15.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4)
- `col` - Номер столбца (0-15)
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
- `col` - Номер столбца (0–15)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row/col)
- `ESP_FAIL` - Операция не удалась
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или координаты вне диапазона)
- `ESP_FAIL` - Ошибка отправки команды
**Примечание:**
Адресация строк: строка 0 = 0x00, строка 1 = 0x40, строка 2 = 0x10, строка 3 = 0x50.
---
### zh_160x_print_char()
Выводит строку на LCD.
Выводит строку на LCD в текущую позицию курсора.
Передаёт каждый символ строки, завершающейся нулём, на LCD в 4-битном режиме. Курсор автоматически перемещается после каждого символа.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `str` - Указатель на null-terminated строку для отображения
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `str` - Указатель на null-terminated строку для отображения. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или str)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка передачи символа
---
### zh_160x_print_int()
Выводит целое число на LCD.
Выводит целое число на LCD в текущую позицию курсора.
Преобразует целое число в десятичную строку и отображает её.
Поддерживает отрицательные числа (максимум 11 цифр плюс знак).
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `num` - Целочисленное значение для отображения
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка преобразования строки или печати
---
### zh_160x_print_float()
Выводит число с плавающей точкой на LCD.
Выводит число с плавающей точкой на LCD в текущую позицию курсора.
Преобразует значение с плавающей точкой в строку с указанной точностью десятичных знаков и отображает её.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `num` - Значение с плавающей точкой для отображения
- `precision` - Количество знаков после запятой (0-9)
- `precision` - Количество знаков после запятой (0–6 рекомендуется)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка преобразования строки или печати
---
### zh_160x_print_progress_bar()
Отображает индикатор прогресса в определенной строке LCD.
Отображает индикатор прогресса в указанной строке LCD.
Отрисовывает 16-блочный индикатор прогресса с использованием пользовательского символа (0xFF).
Заполненные блоки представляют процент прогресса, пустые блоки показывают остаток.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4)
- `progress` - Процент прогресса (0-100)
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
- `progress` - Процент прогресса (0–100)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row или progress)
- `ESP_FAIL` - Операция не удалась
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, row вне диапазона или progress > 100)
- `ESP_FAIL` - Ошибка установки курсора или печати символов
---
### zh_160x_clear_row()
Очищает определенную строку на LCD.
Очищает указанную строку на LCD.
Перемещает курсор в начало указанной строки и заполняет все 16 позиций пробелами для стирания содержимого.
Курсор остаётся в начале очищенной строки.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4)
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row)
- `ESP_FAIL` - Операция не удалась
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или row вне диапазона)
- `ESP_FAIL` - Ошибка установки курсора или печати символов
---
@@ -234,32 +297,37 @@ zh_160x_init(&lcd_handle, ZH_LCD_16X2);
Включает курсор с опциональным режимом мигания.
Включает курсор и при необходимости активирует мигание.
Команда 0x0F включает курсор с миганием, 0x0E включает курсор без мигания.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `blink` - Если true, курсор мигает; если false, курсор статичный
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `blink` - Если true, включается мигающий курсор; если false — статичный курсор
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка отправки команды
---
### zh_160x_off_cursor()
Отключает курсор.
Отключает курсор и отключает мигание.
Отправляет команду 0x0C для отключения курсора и мигания курсора.
**Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574
- `handle` - Указатель на дескриптор LCD. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась
- `ESP_FAIL` - Ошибка отправки команды
---
@@ -272,7 +340,8 @@ zh_160x_init(&lcd_handle, ZH_LCD_16X2);
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd_160x_handle = {0};
zh_pcf8574_handle_t *lcd_expander = NULL;
zh_160x_i2c_handle_t *lcd_handle = NULL;
void app_main(void)
{
@@ -287,19 +356,26 @@ void app_main(void)
.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;
zh_pcf8574_init(&config, &lcd_160x_handle);
zh_160x_init(&lcd_160x_handle, ZH_LCD_16X2);
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_160x_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "LCD 160X");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "Привет Мир!");
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);
}
```
@@ -308,9 +384,13 @@ void app_main(void)
```c
#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_pcf8574_handle_t lcd_handle = {0};
// ... код инициализации ...
for (uint8_t i = 0; i <= 100; ++i)
{
@@ -320,6 +400,8 @@ void app_main(void)
zh_160x_print_progress_bar(&lcd_handle, 1, i);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
}
```
@@ -328,9 +410,13 @@ void app_main(void)
```c
#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_pcf8574_handle_t lcd_handle = {0};
// ... код инициализации ...
// Отображение строки
zh_160x_set_cursor(&lcd_handle, 0, 0);
@@ -347,6 +433,8 @@ void app_main(void)
vTaskDelay(2000 / portTICK_PERIOD_MS);
// Отключение курсора
zh_160x_off_cursor(&lcd_handle);
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
}
```
@@ -357,8 +445,10 @@ void app_main(void)
#define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd1_handle = {0};
zh_pcf8574_handle_t lcd2_handle = {0};
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)
{
@@ -379,18 +469,21 @@ void app_main(void)
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_handle);
zh_160x_init(&lcd1_handle, ZH_LCD_16X2);
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_handle);
zh_160x_init(&lcd2_handle, ZH_LCD_16X2);
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);
}
```
@@ -399,14 +492,14 @@ void app_main(void)
## Технические характеристики
| Параметр | Значение |
|----------|----------|
| ---------- | ---------- |
| **Типы 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 |
| **Платформа** | Серия ESP32 |
| **Язык** | C (C99) |
---
@@ -414,7 +507,7 @@ void app_main(void)
## Коды ошибок
| Код ошибки | Описание |
|------------|----------|
| ------------ | ---------- |
| `ESP_OK` | Операция выполнена успешно |
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверное значение) |
| `ESP_ERR_INVALID_STATE` | Дескриптор не инициализирован |
@@ -498,3 +591,7 @@ void app_main(void)
- Всегда инициализируйте PCF8574 перед инициализацией LCD
- Проверьте адрес I2C с помощью сканера, если LCD не отвечает
- Учитывайте ограничения скорости шины I2C при использовании нескольких устройств
---
*Generated for zh_160x_i2c v5.0.0*
+1 -1
View File
@@ -1,6 +1,6 @@
description: ESP32 ESP-IDF component for LCD 1602A/1604A displays via I2C using PCF8574(A) expanders
url: https://github.com/aZholtikov/zh_160x_i2c
version: "4.1.0"
version: "5.0.0"
license: "Apache-2.0"
maintainers:
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
+154 -54
View File
@@ -1,119 +1,219 @@
/**
* @file zh_160x_i2c.h
*
* @brief Driver for 16x2 and 16x4 LCD displays via I2C PCF8574 expander.
*
* Provides a high-level API for controlling HD44780-compatible LCD modules
* connected through a PCF8574 I/O expander. Supports text output, cursor
* control, and progress bar display.
*
* Key features:
* - 4-bit interface mode for efficient data transfer
* - Support for 16x2 and 16x4 LCD configurations
* - Text, integer, and floating-point number printing
* - Custom progress bar rendering
* - Cursor visibility and blink control
*/
#pragma once
#include "zh_pcf8574.h"
#define ZH_LCD_16X2 1 /*!< LCD size 16x2. */
#define ZH_LCD_16X4 0 /*!< LCD size 16x4. */
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Initializes the LCD 160X.
* @brief Opaque handle for LCD 160x I2C display.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] size LCD size (ZH_LCD_16X2 or ZH_LCD_16X4).
*
* @return ESP_OK if success or an error code otherwise.
* Internal structure containing the PCF8574 expander handle and
* current LCD size configuration.
*/
esp_err_t zh_160x_init(zh_pcf8574_handle_t *handle, bool size);
typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
/**
* @brief Clears the LCD screen.
*
* @param[in] handle Pointer to unique PCF8574 handle.
*
* @return ESP_OK if success or an error code otherwise.
* @brief Supported LCD display sizes.
*/
esp_err_t zh_160x_lcd_clear(zh_pcf8574_handle_t *handle);
typedef enum
{
ZH_LCD_16X2 = 0, /*!< LCD size 16x2 */
ZH_LCD_16X4, /*!< LCD size 16x4 */
ZH_LCD_NUM_MAX
} zh_160x_i2c_lcd_size_t;
/**
* @brief Initializes the LCD 160x display.
*
* Allocates and configures the LCD handle, then sends the initialization
* sequence to the LCD controller via the PCF8574 I2C expander.
* Configures 4-bit mode and sets default display parameters.
*
* @param[in] expander Pointer to the PCF8574 expander handle (must not be NULL)
* @param[out] handle Output pointer for the newly allocated LCD handle (must be NULL)
* @param[in] size LCD size (ZH_LCD_16X2 or ZH_LCD_16X4)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if any parameter is NULL or size is invalid
* @return ESP_ERR_INVALID_STATE if the handle is already initialized
* @return ESP_ERR_NO_MEM if memory allocation fails
* @return ESP_FAIL if LCD initialization sequence fails
*/
esp_err_t zh_160x_init(zh_pcf8574_handle_t **expander, zh_160x_i2c_handle_t **handle, zh_160x_i2c_lcd_size_t size);
/**
* @brief Deinitializes the LCD 160x display and frees the handle.
*
* Releases the allocated memory for the LCD handle and sets the output
* pointer to NULL to prevent use-after-free.
*
* @param[in,out] handle Pointer to the LCD handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
*/
esp_err_t zh_160x_deinit(zh_160x_i2c_handle_t **handle);
/**
* @brief Clears the LCD screen and moves cursor to home position.
*
* Sends the LCD clear command (0x01) to erase all displayed text
* and reset the cursor to the upper-left corner (row 0, column 0).
*
* @param[in] handle Pointer to the LCD handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
* @return ESP_FAIL if sending the command fails
*/
esp_err_t zh_160x_lcd_clear(zh_160x_i2c_handle_t **handle);
/**
* @brief Sets the cursor to a specific position on the LCD.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] row The row number.
* @param[in] col The column number (0–15).
* Moves the cursor to the specified row and column.
* For 16x2 displays: rows 0–1, columns 0–15.
* For 16x4 displays: rows 0–3, columns 0–15.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] row Row number (0 to 1 for 16x2, 0 to 3 for 16x4)
* @param[in] col Column number (0–15)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL or coordinates are out of range
* @return ESP_FAIL if sending the command fails
*
* @note Row address mapping: row 0 = 0x00, row 1 = 0x40,
* row 2 = 0x10, row 3 = 0x50.
*/
esp_err_t zh_160x_set_cursor(zh_pcf8574_handle_t *handle, uint8_t row, uint8_t col);
esp_err_t zh_160x_set_cursor(zh_160x_i2c_handle_t **handle, uint8_t row, uint8_t col);
/**
* @brief Prints a string to the LCD.
* @brief Prints a string to the LCD at the current cursor position.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] str Pointer to the string to be displayed.
* Transmits each character of the null-terminated string to the LCD
* in 4-bit mode. The cursor advances automatically after each character.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] str Null-terminated string to display (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle or str is NULL
* @return ESP_FAIL if any character transmission fails
*/
esp_err_t zh_160x_print_char(zh_pcf8574_handle_t *handle, const char *str);
esp_err_t zh_160x_print_char(zh_160x_i2c_handle_t **handle, const char *str);
/**
* @brief Prints an integer to the LCD.
* @brief Prints an integer to the LCD at the current cursor position.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] num The integer to be displayed.
* Converts the integer to a decimal string and displays it.
* Supports negative numbers (maximum 11 digits plus sign).
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] num Integer value to display
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
* @return ESP_FAIL if string conversion or printing fails
*/
esp_err_t zh_160x_print_int(zh_pcf8574_handle_t *handle, int num);
esp_err_t zh_160x_print_int(zh_160x_i2c_handle_t **handle, int num);
/**
* @brief Prints a floating-point number to the LCD.
* @brief Prints a floating-point number to the LCD at the current cursor position.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] num The floating-point number to be displayed.
* @param[in] precision The number of decimal places to display.
* Converts the floating-point value to a string with the specified
* decimal precision and displays it.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] num Floating-point value to display
* @param[in] precision Number of decimal places (0–6 recommended)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
* @return ESP_FAIL if string conversion or printing fails
*/
esp_err_t zh_160x_print_float(zh_pcf8574_handle_t *handle, float num, uint8_t precision);
esp_err_t zh_160x_print_float(zh_160x_i2c_handle_t **handle, float num, uint8_t precision);
/**
* @brief Displays a progress bar on a specific row of the LCD.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] row The row number.
* @param[in] progress The progress percentage (0–100).
* Renders a 16-block progress bar using custom character (0xFF).
* Filled blocks represent the progress percentage, empty blocks show remaining.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] row Row number (0 to 1 for 16x2, 0 to 3 for 16x4)
* @param[in] progress Progress percentage (0–100)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL, row is out of range,
* or progress exceeds 100
* @return ESP_FAIL if cursor positioning or character printing fails
*/
esp_err_t zh_160x_print_progress_bar(zh_pcf8574_handle_t *handle, uint8_t row, uint8_t progress);
esp_err_t zh_160x_print_progress_bar(zh_160x_i2c_handle_t **handle, uint8_t row, uint8_t progress);
/**
* @brief Clears a specific row on the LCD.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] row The row number.
* Moves the cursor to the beginning of the specified row and fills
* all 16 positions with spaces to erase existing content.
* Leaves the cursor at the start of the cleared row.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] row Row number (0 to 1 for 16x2, 0 to 3 for 16x4)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL or row is out of range
* @return ESP_FAIL if cursor positioning or character printing fails
*/
esp_err_t zh_160x_clear_row(zh_pcf8574_handle_t *handle, uint8_t row);
esp_err_t zh_160x_clear_row(zh_160x_i2c_handle_t **handle, uint8_t row);
/**
* @brief Enable the cursor.
* @brief Enables the cursor with optional blink mode.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* @param[in] blink Blink mode.
* Turns on the cursor and optionally enables blinking.
* Command 0x0F enables cursor with blink, 0x0E enables cursor only.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
* @param[in] blink If true, enables blinking cursor; if false, solid cursor
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
* @return ESP_FAIL if sending the command fails
*/
esp_err_t zh_160x_on_cursor(zh_pcf8574_handle_t *handle, bool blink);
esp_err_t zh_160x_on_cursor(zh_160x_i2c_handle_t **handle, bool blink);
/**
* @brief Disable the cursor.
* @brief Hides the cursor and disables blinking.
*
* @param[in] handle Pointer to unique PCF8574 handle.
* Sends command 0x0C to turn off both cursor and cursor blink.
*
* @return ESP_OK if success or an error code otherwise.
* @param[in] handle Pointer to the LCD handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle is NULL
* @return ESP_FAIL if sending the command fails
*/
esp_err_t zh_160x_off_cursor(zh_pcf8574_handle_t *handle);
esp_err_t zh_160x_off_cursor(zh_160x_i2c_handle_t **handle);
#ifdef __cplusplus
}
+1 -1
View File
@@ -1 +1 @@
4.1.0
5.0.0
+124 -59
View File
@@ -13,65 +13,135 @@ static const char *TAG = "zh_160x_i2c";
return err; \
}
static esp_err_t _zh_160x_lcd_init(zh_pcf8574_handle_t *handle);
static esp_err_t _zh_160x_send_command(zh_pcf8574_handle_t *handle, uint8_t command);
static esp_err_t _zh_160x_send_data(zh_pcf8574_handle_t *handle, uint8_t data);
static esp_err_t _zh_160x_pulse(zh_pcf8574_handle_t *handle);
/**
* @brief LCD 160x I2C handle structure.
*
* Internal handle containing the PCF8574 expander pointer and
* the configured LCD size for row address calculations.
*/
struct _zh_160x_i2c_handle_t
{
zh_pcf8574_handle_t *zh_pcf8574_handle; /*!< PCF8574 expander handle */
zh_160x_i2c_lcd_size_t zh_160x_i2c_lcd_size; /*!< Configured LCD size (16x2 or 16x4) */
};
esp_err_t zh_160x_init(zh_pcf8574_handle_t *handle, bool size) // -V2008
/**
* @brief Initialize the LCD 160x display.
*
* Sends initialization sequence to the LCD controller via PCF8574 expander.
* Configures 4-bit mode and sets default display parameters.
* Follows HD44780 initialization protocol with function set commands.
*
* @param handle Pointer to the 160x I2C handle
*
* @return ESP_OK on success
* @return ESP_FAIL if error
*/
static esp_err_t _zh_160x_lcd_init(zh_160x_i2c_handle_t *handle);
/**
* @brief Send a command to the LCD.
*
* Transmits a command byte to the LCD in 4-bit mode.
* RS pin is set to low (0x08) to indicate command mode.
*
* @param handle Pointer to the 160x I2C handle
* @param command Command byte to send
*
* @return ESP_OK on success
* @return ESP_FAIL if error
*/
static esp_err_t _zh_160x_send_command(zh_160x_i2c_handle_t *handle, uint8_t command);
/**
* @brief Send data to the LCD.
*
* Transmits a data byte to the LCD in 4-bit mode.
* RS pin is set to high (0x09) to indicate data mode.
*
* @param handle Pointer to the 160x I2C handle
* @param data Data byte to send
*
* @return ESP_OK on success
* @return ESP_FAIL if error
*/
static esp_err_t _zh_160x_send_data(zh_160x_i2c_handle_t *handle, uint8_t data);
/**
* @brief Generate an Enable pulse for the LCD.
*
* Toggles the E pin (GPIO2 on PCF8574) to latch data into the LCD.
* Sets E high, delays 1ms, then sets E low with another 1ms delay.
* This pulse signals the LCD to process the data on the D4-D7 pins.
*
* @param handle Pointer to the 160x I2C handle
*
* @return ESP_OK on success
* @return ESP_FAIL if error
*/
static esp_err_t _zh_160x_pulse(zh_160x_i2c_handle_t *handle);
esp_err_t zh_160x_init(zh_pcf8574_handle_t **expander, zh_160x_i2c_handle_t **handle, zh_160x_i2c_lcd_size_t size) // -V2008
{
ZH_LOGI("160X initialization started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X initialization failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X initialization failed. PCF8574 not initialized.");
handle->system = heap_caps_calloc(1, sizeof(uint8_t), MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(handle->system != NULL, ESP_ERR_INVALID_ARG, NULL, "160X initialization failed. Memory allocation fail.");
*(uint8_t *)handle->system = size;
ZH_ERROR_CHECK(_zh_160x_lcd_init(handle) == ESP_OK, ESP_FAIL, NULL, "160X initialization failed. PCF8574 error.");
ZH_ERROR_CHECK(handle != NULL && expander != NULL && *expander != NULL && size < ZH_LCD_NUM_MAX, ESP_ERR_INVALID_ARG, NULL, "160X initialization failed. Invalid argument.");
ZH_ERROR_CHECK(*handle == NULL, ESP_ERR_INVALID_STATE, NULL, "160X initialization failed. 160X is already initialized.");
*handle = heap_caps_calloc(1, sizeof(zh_160x_i2c_handle_t), MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(*handle != NULL, ESP_ERR_NO_MEM, NULL, "160X initialization failed. Failed to allocate 160X handle.");
(*handle)->zh_pcf8574_handle = *expander;
(*handle)->zh_160x_i2c_lcd_size = size;
ZH_ERROR_CHECK(_zh_160x_lcd_init(*handle) == ESP_OK, ESP_FAIL, NULL, "160X initialization failed. PCF8574 error.");
ZH_LOGI("160X initialization completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_lcd_clear(zh_pcf8574_handle_t *handle)
esp_err_t zh_160x_deinit(zh_160x_i2c_handle_t **handle)
{
ZH_LOGI("160X deinitialization started.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X deinitialization failed. Invalid argument.");
heap_caps_free(*handle);
*handle = NULL;
ZH_LOGI("160X deinitialization completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_lcd_clear(zh_160x_i2c_handle_t **handle)
{
ZH_LOGI("160X display cleaning started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X display cleaning failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X display cleaning failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x01) == ESP_OK, ESP_FAIL, NULL, "160X display cleaning failed. PCF8574 error.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X display cleaning failed. Invalid argument.");
ZH_ERROR_CHECK(_zh_160x_send_command(*handle, 0x01) == ESP_OK, ESP_FAIL, NULL, "160X display cleaning failed. PCF8574 error.");
ZH_LOGI("160X display cleaning completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_set_cursor(zh_pcf8574_handle_t *handle, uint8_t row, uint8_t col) // -V2008
esp_err_t zh_160x_set_cursor(zh_160x_i2c_handle_t **handle, uint8_t row, uint8_t col) // -V2008
{
ZH_LOGI("160X set cursor started.");
ZH_ERROR_CHECK(handle != NULL && row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4) && col < 16, ESP_ERR_INVALID_ARG, NULL, "160X set cursor failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X set cursor failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x80 | ((row == 0) ? col : (row == 1) ? (0x40 + col)
: (row == 2) ? (0x10 + col)
: (0x50 + col))) == ESP_OK,
ZH_ERROR_CHECK(handle != NULL && *handle != NULL && row < (((*handle)->zh_160x_i2c_lcd_size == ZH_LCD_16X2) ? 2 : 4) && col < 16, ESP_ERR_INVALID_ARG, NULL, "160X set cursor failed. Invalid argument.");
// clang-format off
ZH_ERROR_CHECK(_zh_160x_send_command(*handle, 0x80 | ((row == 0) ? col : (row == 1) ? (0x40 + col) : (row == 2) ? (0x10 + col) : (0x50 + col))) == ESP_OK,
ESP_FAIL, NULL, "160X set cursor failed. PCF8574 error.");
// clang-format on
ZH_LOGI("160X set cursor completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_print_char(zh_pcf8574_handle_t *handle, const char *str)
esp_err_t zh_160x_print_char(zh_160x_i2c_handle_t **handle, const char *str)
{
ZH_LOGI("160X print char started.");
ZH_ERROR_CHECK(str != NULL && handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print char failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X print char failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(str != NULL && handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print char failed. Invalid argument.");
while (*str != 0)
{
ZH_ERROR_CHECK(_zh_160x_send_data(handle, (uint8_t)*str++) == ESP_OK, ESP_FAIL, NULL, "160X print char failed. PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_send_data(*handle, (uint8_t)*str++) == ESP_OK, ESP_FAIL, NULL, "160X print char failed. PCF8574 error.");
}
ZH_LOGI("160X print char completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_print_int(zh_pcf8574_handle_t *handle, int num)
esp_err_t zh_160x_print_int(zh_160x_i2c_handle_t **handle, int num)
{
ZH_LOGI("160X print int started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print int failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X print int failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print int failed. Invalid argument.");
char buffer[12];
sprintf(buffer, "%d", num);
ZH_ERROR_CHECK(zh_160x_print_char(handle, buffer) == ESP_OK, ESP_FAIL, NULL, "160X print int failed. PCF8574 error.");
@@ -79,11 +149,10 @@ esp_err_t zh_160x_print_int(zh_pcf8574_handle_t *handle, int num)
return ESP_OK;
}
esp_err_t zh_160x_print_float(zh_pcf8574_handle_t *handle, float num, uint8_t precision)
esp_err_t zh_160x_print_float(zh_160x_i2c_handle_t **handle, float num, uint8_t precision)
{
ZH_LOGI("160X print float started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print float failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X print float failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X print float failed. Invalid argument.");
char buffer[16];
sprintf(buffer, "%.*f", precision, num);
ZH_ERROR_CHECK(zh_160x_print_char(handle, buffer) == ESP_OK, ESP_FAIL, NULL, "160X print float failed. PCF8574 error.");
@@ -91,11 +160,10 @@ esp_err_t zh_160x_print_float(zh_pcf8574_handle_t *handle, float num, uint8_t pr
return ESP_OK;
}
esp_err_t zh_160x_print_progress_bar(zh_pcf8574_handle_t *handle, uint8_t row, uint8_t progress) // -V2008
esp_err_t zh_160x_print_progress_bar(zh_160x_i2c_handle_t **handle, uint8_t row, uint8_t progress) // -V2008
{
ZH_LOGI("160X print progress bar started.");
ZH_ERROR_CHECK(handle != NULL && row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4) && progress <= 100, ESP_ERR_INVALID_ARG, NULL, "160X print progress bar failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X print progress bar failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL && row < (((*handle)->zh_160x_i2c_lcd_size == ZH_LCD_16X2) ? 2 : 4) && progress <= 100, ESP_ERR_INVALID_ARG, NULL, "160X print progress bar failed. Invalid argument.");
uint8_t blocks = (progress * 16) / 100;
ZH_ERROR_CHECK(zh_160x_set_cursor(handle, row, 0) == ESP_OK, ESP_FAIL, NULL, "160X print progress bar failed. PCF8574 error.");
for (uint8_t i = 0; i < 16; ++i)
@@ -113,11 +181,10 @@ esp_err_t zh_160x_print_progress_bar(zh_pcf8574_handle_t *handle, uint8_t row, u
return ESP_OK;
}
esp_err_t zh_160x_clear_row(zh_pcf8574_handle_t *handle, uint8_t row) // -V2008
esp_err_t zh_160x_clear_row(zh_160x_i2c_handle_t **handle, uint8_t row) // -V2008
{
ZH_LOGI("160X clear row started.");
ZH_ERROR_CHECK(handle != NULL && row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4), ESP_ERR_INVALID_ARG, NULL, "160X clear row failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X clear row failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL && row < (((*handle)->zh_160x_i2c_lcd_size == ZH_LCD_16X2) ? 2 : 4), ESP_ERR_INVALID_ARG, NULL, "160X clear row failed. Invalid argument.");
ZH_ERROR_CHECK(zh_160x_set_cursor(handle, row, 0) == ESP_OK, ESP_FAIL, NULL, "160X clear row failed. PCF8574 error.");
for (uint8_t i = 0; i < 16; ++i)
{
@@ -128,36 +195,34 @@ esp_err_t zh_160x_clear_row(zh_pcf8574_handle_t *handle, uint8_t row) // -V2008
return ESP_OK;
}
esp_err_t zh_160x_on_cursor(zh_pcf8574_handle_t *handle, bool blink)
esp_err_t zh_160x_on_cursor(zh_160x_i2c_handle_t **handle, bool blink)
{
ZH_LOGI("160X enable cursor started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X enable cursor failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X enable cursor failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, (blink == true) ? 0x0f : 0x0e) == ESP_OK, ESP_FAIL, NULL, "160X enable cursor failed. PCF8574 error.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X enable cursor failed. Invalid argument.");
ZH_ERROR_CHECK(_zh_160x_send_command(*handle, (blink == true) ? 0x0f : 0x0e) == ESP_OK, ESP_FAIL, NULL, "160X enable cursor failed. PCF8574 error.");
ZH_LOGI("160X enable cursor completed successfully.");
return ESP_OK;
}
esp_err_t zh_160x_off_cursor(zh_pcf8574_handle_t *handle)
esp_err_t zh_160x_off_cursor(zh_160x_i2c_handle_t **handle)
{
ZH_LOGI("160X disable cursor started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X disable cursor failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X disable cursor failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x0c) == ESP_OK, ESP_FAIL, NULL, "160X disable cursor failed. PCF8574 error.");
ZH_ERROR_CHECK(handle != NULL && *handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X disable cursor failed. Invalid argument.");
ZH_ERROR_CHECK(_zh_160x_send_command(*handle, 0x0c) == ESP_OK, ESP_FAIL, NULL, "160X disable cursor failed. PCF8574 error.");
ZH_LOGI("160X disable cursor completed successfully.");
return ESP_OK;
}
static esp_err_t _zh_160x_lcd_init(zh_pcf8574_handle_t *handle) // -V2008
static esp_err_t _zh_160x_lcd_init(zh_160x_i2c_handle_t *handle) // -V2008
{
vTaskDelay(20 / portTICK_PERIOD_MS);
ZH_ERROR_CHECK(zh_pcf8574_write(handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error."); // -V525
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error."); // -V525
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, 0x30) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error."); // -V525
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(handle, 0x20) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, 0x20) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error."); // -V525
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x28) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x28) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
@@ -168,29 +233,29 @@ static esp_err_t _zh_160x_lcd_init(zh_pcf8574_handle_t *handle) // -V2008
return ESP_OK;
}
static esp_err_t _zh_160x_send_command(zh_pcf8574_handle_t *handle, uint8_t command)
static esp_err_t _zh_160x_send_command(zh_160x_i2c_handle_t *handle, uint8_t command)
{
ZH_ERROR_CHECK(zh_pcf8574_write(handle, (command & 0xF0) | 0x08) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, (command & 0xF0) | 0x08) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(handle, (command << 4) | 0x08) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, (command << 4) | 0x08) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
return ESP_OK;
}
static esp_err_t _zh_160x_send_data(zh_pcf8574_handle_t *handle, uint8_t data)
static esp_err_t _zh_160x_send_data(zh_160x_i2c_handle_t *handle, uint8_t data)
{
ZH_ERROR_CHECK(zh_pcf8574_write(handle, (data & 0xF0) | 0x09) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, (data & 0xF0) | 0x09) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(handle, (data << 4) | 0x09) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write(&handle->zh_pcf8574_handle, (data << 4) | 0x09) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
return ESP_OK;
}
static esp_err_t _zh_160x_pulse(zh_pcf8574_handle_t *handle)
static esp_err_t _zh_160x_pulse(zh_160x_i2c_handle_t *handle)
{
ZH_ERROR_CHECK(zh_pcf8574_write_gpio(handle, ZH_PCF8574_GPIO_NUM_P2, ZH_PCF8574_GPIO_HIGH) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write_gpio(&handle->zh_pcf8574_handle, ZH_PCF8574_GPIO_NUM_P2, ZH_PCF8574_GPIO_HIGH) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
vTaskDelay(1 / portTICK_PERIOD_MS);
ZH_ERROR_CHECK(zh_pcf8574_write_gpio(handle, ZH_PCF8574_GPIO_NUM_P2, ZH_PCF8574_GPIO_LOW) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
ZH_ERROR_CHECK(zh_pcf8574_write_gpio(&handle->zh_pcf8574_handle, ZH_PCF8574_GPIO_NUM_P2, ZH_PCF8574_GPIO_LOW) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
vTaskDelay(1 / portTICK_PERIOD_MS);
return ESP_OK;
}