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 ## Wiki
@@ -10,41 +10,20 @@
## SAST Tools ## 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 ## Features
1. Support of 16 LCD 160X on one bus. 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.
## Attention 3. Print strings, integers, and floating-point numbers.
4. Progress bar display with custom characters.
For correct operation, please enable the following settings in the menuconfig: 5. Cursor visibility and blink control.
6. Row-specific clear operations.
```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)
## Using ## 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 ```text
cd ../your_project/components cd ../your_project/components
@@ -59,57 +38,4 @@ In the application, add the component:
## Examples ## Examples
One LCD on bus: See Wiki [EN](WIKI_EN.md#usage-examples) | [RU](WIKI_RU.md#примеры-использования)
```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);
}
}
```
+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 ## Table of Contents
@@ -25,39 +25,39 @@ The component is designed specifically for ESP32 microcontrollers and uses ESP-I
## Features ## Features
1. **Simple API**: Easy-to-use functions for common LCD operations 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 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 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) 4. **[Multiple LCD Support]**: Up to 16 LCD modules on one I2C bus
5. **Text Display**: Print strings, integers, and floating-point numbers 5. **[Text Display]**: Print strings, integers, and floating-point numbers
6. **Cursor Control**: Enable/disable cursor with optional blink 6. **[Cursor Control]**: Enable/disable cursor with optional blink
7. **Progress Bar**: Display progress bars on LCD 7. **[Progress Bar]**: Display progress bars on LCD
8. **Row Operations**: Clear specific rows 8. **[Row Operations]**: Clear specific rows
9. **ESP-IDF Optimized**: Uses ESP-IDF's I2C master driver and FreeRTOS 9. **[ESP-IDF Optimized]**: Uses ESP-IDF's I2C master driver and FreeRTOS
--- ---
## Installation ## Installation
1. Navigate to your project's components directory: Navigate to your project's components directory:
```bash ```bash
cd ../your_project/components cd ../your_project/components
``` ```
2. Clone the repository: Clone the repository:
```bash ```bash
git clone https://github.com/aZholtikov/zh_160x_i2c git clone https://github.com/aZholtikov/zh_160x_i2c
``` ```
3. In your application, include the header: In your application, include the header:
```c ```c
#include "zh_160x_i2c.h" #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 ### Required menuconfig Settings
@@ -73,55 +73,97 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
## API Reference ## API Reference
### Configuration Constants ### Data Types
#### zh_160x_i2c_handle_t
```c ```c
#define ZH_LCD_16X2 1 // LCD size 16x2 typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
#define ZH_LCD_16X4 0 // LCD size 16x4
``` ```
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() ### 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:** **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) - `size` - LCD size (ZH_LCD_16X2 or ZH_LCD_16X4)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or handle not initialized) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL pointer or invalid size)
- `ESP_FAIL` - Initialization failed - `ESP_ERR_INVALID_STATE` - Handle already initialized
- `ESP_ERR_NO_MEM` - Memory allocation failure
- `ESP_FAIL` - LCD initialization sequence failure
**Example:** **Example:**
```c ```c
zh_pcf8574_handle_t lcd_handle = {0}; zh_pcf8574_handle_t *lcd_expander = NULL;
// Initialize PCF8574 first zh_160x_i2c_handle_t *lcd_handle = NULL;
zh_pcf8574_init(&config, &lcd_handle); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
// Then initialize LCD config.i2c_handle = i2c_bus_handle;
zh_160x_init(&lcd_handle, ZH_LCD_16X2); 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() ### 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle) - `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. 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4) - `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
- `col` - Column number (0-15) - `col` - Column number (0–15)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row/col) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or coordinates out of range)
- `ESP_FAIL` - Operation failed - `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() ### 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `str` - Pointer to the null-terminated string to display - `str` - Pointer to the null-terminated string to display. Must not be NULL
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or str) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or str)
- `ESP_FAIL` - Operation failed - `ESP_FAIL` - Character transmission failure
--- ---
### zh_160x_print_int() ### 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `num` - Integer value to display - `num` - Integer value to display
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed - `ESP_FAIL` - String conversion or print failure
--- ---
### zh_160x_print_float() ### 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `num` - Floating-point value to display - `num` - Floating-point value to display
- `precision` - Number of decimal places (0-9) - `precision` - Number of decimal places (0–6 recommended)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle) - `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. 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4) - `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
- `progress` - Progress percentage (0-100) - `progress` - Progress percentage (0–100)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row or progress) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, row out of range, or progress > 100)
- `ESP_FAIL` - Operation failed - `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. 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `row` - Row number (0-1 for 16x2, 0-3 for 16x4) - `row` - Row number (0–1 for 16x2, 0–3 for 16x4)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle, invalid row) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle or row out of range)
- `ESP_FAIL` - Operation failed - `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. 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle. Must not be NULL
- `blink` - If true, cursor blinks; if false, cursor is steady - `blink` - If true, enables blinking cursor; if false, solid cursor
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle) - `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle)
- `ESP_FAIL` - Operation failed - `ESP_FAIL` - Command send failure
--- ---
### zh_160x_off_cursor() ### 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:** **Parameters:**
- `handle` - Pointer to unique PCF8574 handle - `handle` - Pointer to the LCD handle (not NULL)
**Returns:** **Returns:**
- `ESP_OK` - Success - `ESP_OK` - Success
- `ESP_ERR_INVALID_ARG` - Invalid argument (NULL handle) - `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) #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) void app_main(void)
{ {
@@ -287,19 +356,26 @@ void app_main(void)
.glitch_ignore_cnt = 7, .glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true, .flags.enable_internal_pullup = true,
}; };
i2c_master_bus_handle_t i2c_bus_handle = NULL; i2c_master_bus_handle_t i2c_bus_handle = NULL;
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle); i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle; config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27; config.i2c_address = 0x27;
zh_pcf8574_init(&config, &lcd_160x_handle); esp_err_t err = zh_pcf8574_init(&config, &lcd_expander);
zh_160x_init(&lcd_160x_handle, ZH_LCD_16X2); if (err != ESP_OK) {
return;
}
err = zh_160x_init(&lcd_expander, &lcd_handle, ZH_LCD_16X2);
if (err != ESP_OK) {
return;
}
// Display text // Display text
zh_160x_set_cursor(&lcd_160x_handle, 0, 0); zh_160x_set_cursor(&lcd_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "LCD 160X"); zh_160x_print_char(&lcd_handle, "LCD 160X");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0); zh_160x_set_cursor(&lcd_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "Hello World!"); zh_160x_print_char(&lcd_handle, "Hello World!");
// Cleanup
zh_160x_deinit(&lcd_handle);
} }
``` ```
@@ -308,9 +384,13 @@ void app_main(void)
```c ```c
#include "zh_160x_i2c.h" #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) void app_main(void)
{ {
zh_pcf8574_handle_t lcd_handle = {0};
// ... initialization code ... // ... initialization code ...
for (uint8_t i = 0; i <= 100; ++i) 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); zh_160x_print_progress_bar(&lcd_handle, 1, i);
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);
} }
// Cleanup
zh_160x_deinit(&lcd_handle);
} }
``` ```
@@ -328,9 +410,13 @@ void app_main(void)
```c ```c
#include "zh_160x_i2c.h" #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) void app_main(void)
{ {
zh_pcf8574_handle_t lcd_handle = {0};
// ... initialization code ... // ... initialization code ...
// Display string // Display string
zh_160x_set_cursor(&lcd_handle, 0, 0); zh_160x_set_cursor(&lcd_handle, 0, 0);
@@ -347,6 +433,8 @@ void app_main(void)
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
// Disable cursor // Disable cursor
zh_160x_off_cursor(&lcd_handle); 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) #define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd1_handle = {0}; zh_pcf8574_handle_t *lcd1_expander = NULL;
zh_pcf8574_handle_t lcd2_handle = {0}; 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) void app_main(void)
{ {
@@ -379,18 +469,21 @@ void app_main(void)
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle; config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27; config.i2c_address = 0x27;
zh_pcf8574_init(&config, &lcd1_handle); zh_pcf8574_init(&config, &lcd1_expander);
zh_160x_init(&lcd1_handle, ZH_LCD_16X2); zh_160x_init(&lcd1_expander, &lcd1_handle, ZH_LCD_16X2);
// Initialize second LCD at address 0x26 // Initialize second LCD at address 0x26
config.i2c_address = 0x26; config.i2c_address = 0x26;
zh_pcf8574_init(&config, &lcd2_handle); zh_pcf8574_init(&config, &lcd2_expander);
zh_160x_init(&lcd2_handle, ZH_LCD_16X2); zh_160x_init(&lcd2_expander, &lcd2_handle, ZH_LCD_16X2);
// Display on first LCD // Display on first LCD
zh_160x_set_cursor(&lcd1_handle, 0, 0); zh_160x_set_cursor(&lcd1_handle, 0, 0);
zh_160x_print_char(&lcd1_handle, "LCD 1"); zh_160x_print_char(&lcd1_handle, "LCD 1");
// Display on second LCD // Display on second LCD
zh_160x_set_cursor(&lcd2_handle, 0, 0); zh_160x_set_cursor(&lcd2_handle, 0, 0);
zh_160x_print_char(&lcd2_handle, "LCD 2"); 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 ## Technical Specifications
| Parameter | Value | | Parameter | Value |
|-----------|-------| | ----------- | ------- |
| **LCD Types** | 1602A (16x2), 1604A (16x4) | | **LCD Types** | 1602A (16x2), 1604A (16x4) |
| **Interface** | I2C via PCF8574(A) | | **Interface** | I2C via PCF8574(A) |
| **I2C Address Range** | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) | | **I2C Address Range** | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) |
| **Max LCDs per Bus** | 16 | | **Max LCDs per Bus** | 16 |
| **GPIO Usage** | 2 (SCL, SDA) | | **GPIO Usage** | 2 (SCL, SDA) |
| **ESP-IDF Version** | >= 5.0| | **ESP-IDF Version** | >= 5.0 |
| **Platform** | ESP32 family | | **Platform** | ESP32 series |
| **Language** | C (C99) | | **Language** | C (C99) |
--- ---
@@ -414,7 +507,7 @@ void app_main(void)
## Error Codes ## Error Codes
| Error Code | Description | | Error Code | Description |
|------------|-------------| | ------------ | ------------- |
| `ESP_OK` | Operation completed successfully | | `ESP_OK` | Operation completed successfully |
| `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid value) | | `ESP_ERR_INVALID_ARG` | Invalid argument (NULL pointer or invalid value) |
| `ESP_ERR_INVALID_STATE` | Handle not initialized | | `ESP_ERR_INVALID_STATE` | Handle not initialized |
@@ -498,3 +591,7 @@ limitations under the License.
- Always initialize PCF8574 before initializing LCD - Always initialize PCF8574 before initializing LCD
- Check I2C address using a scanner if LCD does not respond - Check I2C address using a scanner if LCD does not respond
- Consider I2C bus speed limitations when using multiple devices - 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 1. **[Простой API]**: Удобные функции для распространенных операций с LCD
2. **Интерфейс I2C**: Использует только 2 GPIO-пина (SCL и SDA) через расширитель PCF8574 2. **[Интерфейс I2C]**: Использует только 2 GPIO-пина (SCL и SDA) через расширитель PCF8574
3. **Поддержка 1602A и 1604A**: Поддерживает LCD-модули 16x2 и 16x4 3. **[Поддержка 1602A и 1604A]**: Поддерживает LCD-модули 16x2 и 16x4
4. **Множественные LCD**: До 16 LCD-модулей на одной шине I2C 4. **[Множественные LCD]**: До 16 LCD-модулей на одной шине I2C
5. **Отображение текста**: Вывод строк, целых чисел и чисел с плавающей точкой 5. **[Отображение текста]**: Вывод строк, целых чисел и чисел с плавающей точкой
6. **Управление курсором**: Включение/выключение курсора с опциональным миганием 6. **[Управление курсором]**: Включение/выключение курсора с опциональным миганием
7. **Индикатор прогресса**: Отображение индикаторов прогресса на LCD 7. **[Индикатор прогресса]**: Отображение индикаторов прогресса на LCD
8. **Операции со строками**: Очистка конкретных строк 8. **[Операции со строками]**: Очистка конкретных строк
9. **Оптимизировано под ESP-IDF**: Использует драйвер I2C-мастера ESP-IDF и FreeRTOS 9. **[Оптимизировано под ESP-IDF]**: Использует драйвер I2C-мастера ESP-IDF и FreeRTOS
--- ---
## Установка ## Установка
1. Перейдите в каталог компонентов вашего проекта: Перейдите в каталог компонентов вашего проекта:
```bash ```bash
cd ../ваш_проект/components cd ../ваш_проект/components
``` ```
2. Клонируйте репозиторий: Клонируйте репозиторий:
```bash ```bash
git clone https://github.com/aZholtikov/zh_160x_i2c git clone https://github.com/aZholtikov/zh_160x_i2c
``` ```
3. В вашем приложении подключите заголовочный файл: В вашем приложении подключите заголовочный файл:
```c ```c
#include "zh_160x_i2c.h" #include "zh_160x_i2c.h"
``` ```
4. Компонент будет автоматически собран вместе с вашим проектом. Компонент будет автоматически собран вместе с вашим проектом.
### Обязательные настройки в menuconfig ### Обязательные настройки в menuconfig
@@ -73,160 +73,223 @@ CONFIG_I2C_MASTER_ISR_HANDLER_IN_IRAM
## Справочник API ## Справочник API
### Константы конфигурации ### Типы данных
#### zh_160x_i2c_handle_t
```c ```c
#define ZH_LCD_16X2 1 // Размер LCD 16x2 typedef struct _zh_160x_i2c_handle_t zh_160x_i2c_handle_t;
#define ZH_LCD_16X4 0 // Размер LCD 16x4
``` ```
Непрозрачный дескриптор 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() ### 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) - `size` - Размер LCD (ZH_LCD_16X2 или ZH_LCD_16X4)
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или handle не инициализирован) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL указатель или неверный размер)
- `ESP_FAIL` - Ошибка инициализации - `ESP_ERR_INVALID_STATE` - Дескриптор уже инициализирован
- `ESP_ERR_NO_MEM` - Ошибка выделения памяти
- `ESP_FAIL` - Сбой последовательности инициализации LCD
**Пример:** **Пример:**
```c ```c
zh_pcf8574_handle_t lcd_handle = {0}; zh_pcf8574_handle_t *lcd_expander = NULL;
// Сначала инициализируйте PCF8574 zh_160x_i2c_handle_t *lcd_handle = NULL;
zh_pcf8574_init(&config, &lcd_handle); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
// Затем инициализируйте LCD config.i2c_handle = i2c_bus_handle;
zh_160x_init(&lcd_handle, ZH_LCD_16X2); 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() ### zh_160x_lcd_clear()
Очищает весь экран LCD. Очищает экран LCD и перемещает курсор в домашнюю позицию.
Отправляет команду очистки LCD (0x01) для стирания всего отображаемого текста и сброса курсора в верхний левый угол (строка 0, столбец 0).
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка отправки команды
--- ---
### zh_160x_set_cursor() ### zh_160x_set_cursor()
Устанавливает курсор в определенную позицию на LCD. Устанавливает курсор в указанную позицию на LCD.
Перемещает курсор в указанную строку и столбец.
Для дисплеев 16x2: строки 0–1, столбцы 0–15.
Для дисплеев 16x4: строки 0–3, столбцы 0–15.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4) - `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
- `col` - Номер столбца (0-15) - `col` - Номер столбца (0–15)
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row/col) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или координаты вне диапазона)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка отправки команды
**Примечание:**
Адресация строк: строка 0 = 0x00, строка 1 = 0x40, строка 2 = 0x10, строка 3 = 0x50.
--- ---
### zh_160x_print_char() ### zh_160x_print_char()
Выводит строку на LCD. Выводит строку на LCD в текущую позицию курсора.
Передаёт каждый символ строки, завершающейся нулём, на LCD в 4-битном режиме. Курсор автоматически перемещается после каждого символа.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `str` - Указатель на null-terminated строку для отображения - `str` - Указатель на null-terminated строку для отображения. Не должен быть NULL
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или str) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или str)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка передачи символа
--- ---
### zh_160x_print_int() ### zh_160x_print_int()
Выводит целое число на LCD. Выводит целое число на LCD в текущую позицию курсора.
Преобразует целое число в десятичную строку и отображает её.
Поддерживает отрицательные числа (максимум 11 цифр плюс знак).
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `num` - Целочисленное значение для отображения - `num` - Целочисленное значение для отображения
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка преобразования строки или печати
--- ---
### zh_160x_print_float() ### zh_160x_print_float()
Выводит число с плавающей точкой на LCD. Выводит число с плавающей точкой на LCD в текущую позицию курсора.
Преобразует значение с плавающей точкой в строку с указанной точностью десятичных знаков и отображает её.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `num` - Значение с плавающей точкой для отображения - `num` - Значение с плавающей точкой для отображения
- `precision` - Количество знаков после запятой (0-9) - `precision` - Количество знаков после запятой (0–6 рекомендуется)
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка преобразования строки или печати
--- ---
### zh_160x_print_progress_bar() ### zh_160x_print_progress_bar()
Отображает индикатор прогресса в определенной строке LCD. Отображает индикатор прогресса в указанной строке LCD.
Отрисовывает 16-блочный индикатор прогресса с использованием пользовательского символа (0xFF).
Заполненные блоки представляют процент прогресса, пустые блоки показывают остаток.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4) - `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
- `progress` - Процент прогресса (0-100) - `progress` - Процент прогресса (0–100)
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row или progress) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, row вне диапазона или progress > 100)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка установки курсора или печати символов
--- ---
### zh_160x_clear_row() ### zh_160x_clear_row()
Очищает определенную строку на LCD. Очищает указанную строку на LCD.
Перемещает курсор в начало указанной строки и заполняет все 16 позиций пробелами для стирания содержимого.
Курсор остаётся в начале очищенной строки.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `row` - Номер строки (0-1 для 16x2, 0-3 для 16x4) - `row` - Номер строки (0–1 для 16x2, 0–3 для 16x4)
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle, неверный row) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или row вне диапазона)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка установки курсора или печати символов
--- ---
@@ -234,32 +297,37 @@ zh_160x_init(&lcd_handle, ZH_LCD_16X2);
Включает курсор с опциональным режимом мигания. Включает курсор с опциональным режимом мигания.
Включает курсор и при необходимости активирует мигание.
Команда 0x0F включает курсор с миганием, 0x0E включает курсор без мигания.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
- `blink` - Если true, курсор мигает; если false, курсор статичный - `blink` - Если true, включается мигающий курсор; если false — статичный курсор
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle) - `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle)
- `ESP_FAIL` - Операция не удалась - `ESP_FAIL` - Ошибка отправки команды
--- ---
### zh_160x_off_cursor() ### zh_160x_off_cursor()
Отключает курсор. Отключает курсор и отключает мигание.
Отправляет команду 0x0C для отключения курсора и мигания курсора.
**Параметры:** **Параметры:**
- `handle` - Указатель на уникальный дескриптор PCF8574 - `handle` - Указатель на дескриптор LCD. Не должен быть NULL
**Возвращает:** **Возвращает:**
- `ESP_OK` - Успех - `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle) - `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) #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) void app_main(void)
{ {
@@ -287,19 +356,26 @@ void app_main(void)
.glitch_ignore_cnt = 7, .glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true, .flags.enable_internal_pullup = true,
}; };
i2c_master_bus_handle_t i2c_bus_handle = NULL; i2c_master_bus_handle_t i2c_bus_handle = NULL;
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle); i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle; config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27; config.i2c_address = 0x27;
zh_pcf8574_init(&config, &lcd_160x_handle); esp_err_t err = zh_pcf8574_init(&config, &lcd_expander);
zh_160x_init(&lcd_160x_handle, ZH_LCD_16X2); 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_set_cursor(&lcd_handle, 0, 0);
zh_160x_print_char(&lcd_160x_handle, "LCD 160X"); zh_160x_print_char(&lcd_handle, "LCD 160X");
zh_160x_set_cursor(&lcd_160x_handle, 1, 0); zh_160x_set_cursor(&lcd_handle, 1, 0);
zh_160x_print_char(&lcd_160x_handle, "Привет Мир!"); zh_160x_print_char(&lcd_handle, "Привет Мир!");
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
} }
``` ```
@@ -308,9 +384,13 @@ void app_main(void)
```c ```c
#include "zh_160x_i2c.h" #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) void app_main(void)
{ {
zh_pcf8574_handle_t lcd_handle = {0};
// ... код инициализации ... // ... код инициализации ...
for (uint8_t i = 0; i <= 100; ++i) 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); zh_160x_print_progress_bar(&lcd_handle, 1, i);
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);
} }
// Очистка ресурсов
zh_160x_deinit(&lcd_handle);
} }
``` ```
@@ -328,9 +410,13 @@ void app_main(void)
```c ```c
#include "zh_160x_i2c.h" #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) void app_main(void)
{ {
zh_pcf8574_handle_t lcd_handle = {0};
// ... код инициализации ... // ... код инициализации ...
// Отображение строки // Отображение строки
zh_160x_set_cursor(&lcd_handle, 0, 0); zh_160x_set_cursor(&lcd_handle, 0, 0);
@@ -347,6 +433,8 @@ void app_main(void)
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
// Отключение курсора // Отключение курсора
zh_160x_off_cursor(&lcd_handle); 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) #define I2C_PORT (I2C_NUM_MAX - 1)
zh_pcf8574_handle_t lcd1_handle = {0}; zh_pcf8574_handle_t *lcd1_expander = NULL;
zh_pcf8574_handle_t lcd2_handle = {0}; 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) void app_main(void)
{ {
@@ -379,18 +469,21 @@ void app_main(void)
zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle; config.i2c_handle = i2c_bus_handle;
config.i2c_address = 0x27; config.i2c_address = 0x27;
zh_pcf8574_init(&config, &lcd1_handle); zh_pcf8574_init(&config, &lcd1_expander);
zh_160x_init(&lcd1_handle, ZH_LCD_16X2); zh_160x_init(&lcd1_expander, &lcd1_handle, ZH_LCD_16X2);
// Инициализация второго LCD по адресу 0x26 // Инициализация второго LCD по адресу 0x26
config.i2c_address = 0x26; config.i2c_address = 0x26;
zh_pcf8574_init(&config, &lcd2_handle); zh_pcf8574_init(&config, &lcd2_expander);
zh_160x_init(&lcd2_handle, ZH_LCD_16X2); zh_160x_init(&lcd2_expander, &lcd2_handle, ZH_LCD_16X2);
// Отображение на первом LCD // Отображение на первом LCD
zh_160x_set_cursor(&lcd1_handle, 0, 0); zh_160x_set_cursor(&lcd1_handle, 0, 0);
zh_160x_print_char(&lcd1_handle, "LCD 1"); zh_160x_print_char(&lcd1_handle, "LCD 1");
// Отображение на втором LCD // Отображение на втором LCD
zh_160x_set_cursor(&lcd2_handle, 0, 0); zh_160x_set_cursor(&lcd2_handle, 0, 0);
zh_160x_print_char(&lcd2_handle, "LCD 2"); 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) | | **Типы LCD** | 1602A (16x2), 1604A (16x4) |
| **Интерфейс** | I2C через PCF8574(A) | | **Интерфейс** | I2C через PCF8574(A) |
| **Диапазон адресов I2C** | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) | | **Диапазон адресов I2C** | 0x20-0x27 (PCF8574), 0x38-0x3F (PCF8574A) |
| **Макс. LCD на шине** | 16 | | **Макс. LCD на шине** | 16 |
| **Использование GPIO** | 2 (SCL, SDA) | | **Использование GPIO** | 2 (SCL, SDA) |
| **Версия ESP-IDF** | >= 5.0 | | **Версия ESP-IDF** | >= 5.0 |
| **Платформа** | Семейство ESP32 | | **Платформа** | Серия ESP32 |
| **Язык** | C (C99) | | **Язык** | C (C99) |
--- ---
@@ -414,7 +507,7 @@ void app_main(void)
## Коды ошибок ## Коды ошибок
| Код ошибки | Описание | | Код ошибки | Описание |
|------------|----------| | ------------ | ---------- |
| `ESP_OK` | Операция выполнена успешно | | `ESP_OK` | Операция выполнена успешно |
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверное значение) | | `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель или неверное значение) |
| `ESP_ERR_INVALID_STATE` | Дескриптор не инициализирован | | `ESP_ERR_INVALID_STATE` | Дескриптор не инициализирован |
@@ -498,3 +591,7 @@ void app_main(void)
- Всегда инициализируйте PCF8574 перед инициализацией LCD - Всегда инициализируйте PCF8574 перед инициализацией LCD
- Проверьте адрес I2C с помощью сканера, если LCD не отвечает - Проверьте адрес I2C с помощью сканера, если LCD не отвечает
- Учитывайте ограничения скорости шины I2C при использовании нескольких устройств - Учитывайте ограничения скорости шины 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 description: ESP32 ESP-IDF component for LCD 1602A/1604A displays via I2C using PCF8574(A) expanders
url: https://github.com/aZholtikov/zh_160x_i2c url: https://github.com/aZholtikov/zh_160x_i2c
version: "4.1.0" version: "5.0.0"
license: "Apache-2.0" license: "Apache-2.0"
maintainers: maintainers:
- "Alexey Zholtikov <alexey.zholtikov@yandex.ru>" - "Alexey Zholtikov <alexey.zholtikov@yandex.ru>"
+154 -54
View File
@@ -1,119 +1,219 @@
/** /**
* @file zh_160x_i2c.h * @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 #pragma once
#include "zh_pcf8574.h" #include "zh_pcf8574.h"
#define ZH_LCD_16X2 1 /*!< LCD size 16x2. */
#define ZH_LCD_16X4 0 /*!< LCD size 16x4. */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
#endif #endif
/** /**
* @brief Initializes the LCD 160X. * @brief Opaque handle for LCD 160x I2C display.
* *
* @param[in] handle Pointer to unique PCF8574 handle. * Internal structure containing the PCF8574 expander handle and
* @param[in] size LCD size (ZH_LCD_16X2 or ZH_LCD_16X4). * current LCD size configuration.
*
* @return ESP_OK if success or an error code otherwise.
*/ */
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. * @brief Supported LCD display sizes.
*
* @param[in] handle Pointer to unique PCF8574 handle.
*
* @return ESP_OK if success or an error code otherwise.
*/ */
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. * @brief Sets the cursor to a specific position on the LCD.
* *
* @param[in] handle Pointer to unique PCF8574 handle. * Moves the cursor to the specified row and column.
* @param[in] row The row number. * For 16x2 displays: rows 0–1, columns 0–15.
* @param[in] col The column number (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. * Transmits each character of the null-terminated string to the LCD
* @param[in] str Pointer to the string to be displayed. * 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. * Converts the integer to a decimal string and displays it.
* @param[in] num The integer to be displayed. * 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. * Converts the floating-point value to a string with the specified
* @param[in] num The floating-point number to be displayed. * decimal precision and displays it.
* @param[in] precision The number of decimal places to display.
* *
* @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. * @brief Displays a progress bar on a specific row of the LCD.
* *
* @param[in] handle Pointer to unique PCF8574 handle. * Renders a 16-block progress bar using custom character (0xFF).
* @param[in] row The row number. * Filled blocks represent the progress percentage, empty blocks show remaining.
* @param[in] progress The progress percentage (0–100).
* *
* @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. * @brief Clears a specific row on the LCD.
* *
* @param[in] handle Pointer to unique PCF8574 handle. * Moves the cursor to the beginning of the specified row and fills
* @param[in] row The row number. * 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. * Turns on the cursor and optionally enables blinking.
* @param[in] blink Blink mode. * 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 #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; \ 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); * @brief LCD 160x I2C handle structure.
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); * 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_LOGI("160X initialization started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "160X initialization failed. Invalid argument."); 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->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X initialization failed. PCF8574 not initialized."); ZH_ERROR_CHECK(*handle == NULL, ESP_ERR_INVALID_STATE, NULL, "160X initialization failed. 160X is already initialized.");
handle->system = heap_caps_calloc(1, sizeof(uint8_t), MALLOC_CAP_8BIT); *handle = heap_caps_calloc(1, sizeof(zh_160x_i2c_handle_t), MALLOC_CAP_8BIT);
ZH_ERROR_CHECK(handle->system != NULL, ESP_ERR_INVALID_ARG, NULL, "160X initialization failed. Memory allocation fail."); ZH_ERROR_CHECK(*handle != NULL, ESP_ERR_NO_MEM, NULL, "160X initialization failed. Failed to allocate 160X handle.");
*(uint8_t *)handle->system = size; (*handle)->zh_pcf8574_handle = *expander;
ZH_ERROR_CHECK(_zh_160x_lcd_init(handle) == ESP_OK, ESP_FAIL, NULL, "160X initialization failed. PCF8574 error."); (*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."); ZH_LOGI("160X initialization completed successfully.");
return ESP_OK; 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_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 != NULL && *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(_zh_160x_send_command(handle, 0x01) == ESP_OK, ESP_FAIL, NULL, "160X display cleaning failed. PCF8574 error.");
ZH_LOGI("160X display cleaning completed successfully."); ZH_LOGI("160X display cleaning completed successfully.");
return ESP_OK; 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_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 != 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.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X set cursor failed. PCF8574 not initialized."); // clang-format off
ZH_ERROR_CHECK(_zh_160x_send_command(handle, 0x80 | ((row == 0) ? col : (row == 1) ? (0x40 + col) ZH_ERROR_CHECK(_zh_160x_send_command(*handle, 0x80 | ((row == 0) ? col : (row == 1) ? (0x40 + col) : (row == 2) ? (0x10 + col) : (0x50 + col))) == ESP_OK,
: (row == 2) ? (0x10 + col)
: (0x50 + col))) == ESP_OK,
ESP_FAIL, NULL, "160X set cursor failed. PCF8574 error."); ESP_FAIL, NULL, "160X set cursor failed. PCF8574 error.");
// clang-format on
ZH_LOGI("160X set cursor completed successfully."); ZH_LOGI("160X set cursor completed successfully.");
return ESP_OK; 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_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(str != NULL && handle != 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.");
while (*str != 0) 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."); ZH_LOGI("160X print char completed successfully.");
return ESP_OK; 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_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 != NULL && *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.");
char buffer[12]; char buffer[12];
sprintf(buffer, "%d", num); sprintf(buffer, "%d", num);
ZH_ERROR_CHECK(zh_160x_print_char(handle, buffer) == ESP_OK, ESP_FAIL, NULL, "160X print int failed. PCF8574 error."); 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; 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_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 != NULL && *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.");
char buffer[16]; char buffer[16];
sprintf(buffer, "%.*f", precision, num); 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."); 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; 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_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 != 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.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X print progress bar failed. PCF8574 not initialized.");
uint8_t blocks = (progress * 16) / 100; 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."); 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) 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; 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_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 != 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(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "160X clear row failed. PCF8574 not initialized.");
ZH_ERROR_CHECK(zh_160x_set_cursor(handle, row, 0) == ESP_OK, ESP_FAIL, NULL, "160X clear row failed. PCF8574 error."); 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) 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; 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_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 != NULL && *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(_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."); ZH_LOGI("160X enable cursor completed successfully.");
return ESP_OK; 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_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 != NULL && *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(_zh_160x_send_command(handle, 0x0c) == ESP_OK, ESP_FAIL, NULL, "160X disable cursor failed. PCF8574 error.");
ZH_LOGI("160X disable cursor completed successfully."); ZH_LOGI("160X disable cursor completed successfully.");
return ESP_OK; 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); 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_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_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_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_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.");
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; 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_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."); ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
return ESP_OK; 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_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."); ZH_ERROR_CHECK(_zh_160x_pulse(handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 error.");
return ESP_OK; 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); 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); vTaskDelay(1 / portTICK_PERIOD_MS);
return ESP_OK; return ESP_OK;
} }