feat: initial
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
120
README.md
120
README.md
@@ -1,2 +1,120 @@
|
||||
# zh_avr_160x_i2c
|
||||
# FreeRTOS based AVR library for liquid crystal display module 1602(4)A via I2C connection (PCF8574)
|
||||
|
||||
## Features
|
||||
|
||||
1. Support of 16 LCD 160X on one bus.
|
||||
|
||||
## Connection
|
||||
|
||||
| 1602(4)A | PCF8574 |
|
||||
| -------- | ------- |
|
||||
| RS | P0 |
|
||||
| E | P2 |
|
||||
| D4 | P4 |
|
||||
| D5 | P5 |
|
||||
| D6 | P6 |
|
||||
| D7 | P7 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
1. [zh_avr_free_rtos](http://git.zh.com.ru/avr_libraries/zh_avr_free_rtos)
|
||||
2. [zh_avr_vector](http://git.zh.com.ru/avr_libraries/zh_avr_vector)
|
||||
3. [zh_avr_common](http://git.zh.com.ru/avr_libraries/zh_avr_common)
|
||||
4. [zh_avr_i2c](http://git.zh.com.ru/avr_libraries/zh_avr_i2c)
|
||||
5. [zh_avr_pcf8574](http://git.zh.com.ru/avr_libraries/zh_avr_pcf8574)
|
||||
|
||||
## Using
|
||||
|
||||
In an existing project, run the following command to install the components:
|
||||
|
||||
```text
|
||||
cd ../your_project/lib
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_free_rtos
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_vector
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_i2c
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_common
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_pcf8574
|
||||
git clone http://git.zh.com.ru/avr_libraries/zh_avr_160x_i2c
|
||||
```
|
||||
|
||||
In the application, add the component:
|
||||
|
||||
```c
|
||||
#include "zh_avr_160x_i2c.h"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
One LCD on bus:
|
||||
|
||||
```c
|
||||
#include "avr/io.h"
|
||||
#include "stdio.h"
|
||||
#include "zh_avr_160x_i2c.h"
|
||||
|
||||
#define BAUD_RATE 9600
|
||||
#define BAUD_PRESCALE (F_CPU / 16 / BAUD_RATE - 1)
|
||||
|
||||
int usart(char byte, FILE *stream)
|
||||
{
|
||||
while ((UCSR0A & (1 << UDRE0)) == 0)
|
||||
{
|
||||
}
|
||||
UDR0 = byte;
|
||||
return 0;
|
||||
}
|
||||
FILE uart = FDEV_SETUP_STREAM(usart, NULL, _FDEV_SETUP_WRITE);
|
||||
|
||||
zh_avr_pcf8574_handle_t lcd_160x_handle = {0};
|
||||
|
||||
void lcd_160x_example_task(void *pvParameters)
|
||||
{
|
||||
zh_avr_i2c_master_init(false);
|
||||
zh_avr_pcf8574_init_config_t pcf8574_init_config = ZH_AVR_PCF8574_INIT_CONFIG_DEFAULT();
|
||||
pcf8574_init_config.i2c_address = 0x27;
|
||||
zh_avr_pcf8574_init(&pcf8574_init_config, &lcd_160x_handle);
|
||||
zh_avr_160x_init(&lcd_160x_handle, ZH_LCD_16X2); // For LCD 16X2.
|
||||
// zh_avr_160x_init(&lcd_160x_handle, ZH_LCD_16X4); // For LCD 16X4.
|
||||
for (;;)
|
||||
{
|
||||
zh_avr_160x_set_cursor(&lcd_160x_handle, 0, 0);
|
||||
zh_avr_160x_print_char(&lcd_160x_handle, "LCD 160X");
|
||||
zh_avr_160x_set_cursor(&lcd_160x_handle, 1, 0);
|
||||
zh_avr_160x_print_char(&lcd_160x_handle, "Hello World!");
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
zh_avr_160x_set_cursor(&lcd_160x_handle, 0, 0); // For LCD 16X2.
|
||||
// zh_avr_160x_set_cursor(&lcd_160x_handle, 2, 0); // For LCD 16X4.
|
||||
zh_avr_160x_print_char(&lcd_160x_handle, "Progress: ");
|
||||
for (uint8_t i = 0; i <= 100; ++i)
|
||||
{
|
||||
zh_avr_160x_set_cursor(&lcd_160x_handle, 0, 10); // For LCD 16X2.
|
||||
// zh_avr_160x_set_cursor(&lcd_160x_handle, 2, 10); // For LCD 16X4.
|
||||
zh_avr_160x_print_int(&lcd_160x_handle, i);
|
||||
zh_avr_160x_print_char(&lcd_160x_handle, "%");
|
||||
zh_avr_160x_print_progress_bar(&lcd_160x_handle, 1, i); // For LCD 16X2.
|
||||
// zh_avr_160x_print_progress_bar(&lcd_160x_handle, 3, i); // For LCD 16X4.
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
zh_avr_160x_lcd_clear(&lcd_160x_handle);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
printf("Task Remaining Stack Size %d.\n", uxTaskGetStackHighWaterMark(NULL));
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
UBRR0H = (BAUD_PRESCALE >> 8);
|
||||
UBRR0L = BAUD_PRESCALE;
|
||||
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
|
||||
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
|
||||
stdout = &uart;
|
||||
xTaskCreate(lcd_160x_example_task, "lcd 160x example task", 124, NULL, tskIDLE_PRIORITY, NULL);
|
||||
vTaskStartScheduler();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zh_avr_pcf8574_event_handler(zh_avr_pcf8574_event_on_isr_t *event) // Do not delete! Required for zh_avr_pcf8574 library work.
|
||||
{
|
||||
}
|
||||
```
|
||||
|
99
include/zh_avr_160x_i2c.h
Normal file
99
include/zh_avr_160x_i2c.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
#include "zh_avr_pcf8574.h"
|
||||
#include "util/delay.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#define ZH_LCD_16X2 1
|
||||
#define ZH_LCD_16X4 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes the LCD 160X.
|
||||
*
|
||||
* @param[in] handle Pointer to unique PCF8574 handle.
|
||||
* @param[in] size LCD size (ZH_LCD_16X2 or ZH_LCD_16X4).
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_init(zh_avr_pcf8574_handle_t *handle, bool size);
|
||||
|
||||
/**
|
||||
* @brief Clears the LCD screen.
|
||||
*
|
||||
* @param[in] handle Pointer to unique PCF8574 handle.
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_lcd_clear(zh_avr_pcf8574_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).
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_set_cursor(zh_avr_pcf8574_handle_t *handle, uint8_t row, uint8_t col);
|
||||
|
||||
/**
|
||||
* @brief Prints a string to the LCD.
|
||||
*
|
||||
* @param[in] handle Pointer to unique PCF8574 handle.
|
||||
* @param[in] str Pointer to the string to be displayed.
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_print_char(zh_avr_pcf8574_handle_t *handle, const char *str);
|
||||
|
||||
/**
|
||||
* @brief Prints an integer to the LCD.
|
||||
*
|
||||
* @param[in] handle Pointer to unique PCF8574 handle.
|
||||
* @param[in] num The integer to be displayed.
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise..
|
||||
*/
|
||||
avr_err_t zh_avr_160x_print_int(zh_avr_pcf8574_handle_t *handle, int num);
|
||||
|
||||
/**
|
||||
* @brief Prints a floating-point number to the LCD.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_print_float(zh_avr_pcf8574_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).
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_print_progress_bar(zh_avr_pcf8574_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.
|
||||
*
|
||||
* @return AVR_OK if success or an error code otherwise.
|
||||
*/
|
||||
avr_err_t zh_avr_160x_clear_row(zh_avr_pcf8574_handle_t *handle, uint8_t row);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
1
version.txt
Normal file
1
version.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0
|
139
zh_avr_160x_i2c.c
Normal file
139
zh_avr_160x_i2c.c
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "zh_avr_160x_i2c.h"
|
||||
|
||||
#define LCD_160X_PULSE \
|
||||
zh_avr_pcf8574_write_gpio(handle, 2, true); \
|
||||
_delay_us(300); \
|
||||
zh_avr_pcf8574_write_gpio(handle, 2, false); \
|
||||
_delay_us(400);
|
||||
|
||||
static void _zh_avr_160x_lcd_init(zh_avr_pcf8574_handle_t *handle);
|
||||
static void _zh_avr_160x_send_command(zh_avr_pcf8574_handle_t *handle, uint8_t command);
|
||||
static void _zh_avr_160x_send_data(zh_avr_pcf8574_handle_t *handle, uint8_t data);
|
||||
|
||||
avr_err_t zh_avr_160x_init(zh_avr_pcf8574_handle_t *handle, bool size)
|
||||
{
|
||||
ZH_ERROR_CHECK(handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
handle->system = pvPortCalloc(1, sizeof(uint8_t));
|
||||
ZH_ERROR_CHECK(handle->system != NULL, AVR_ERR_INVALID_ARG);
|
||||
*(uint8_t *)handle->system = size;
|
||||
_zh_avr_160x_lcd_init(handle);
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_lcd_clear(zh_avr_pcf8574_handle_t *handle)
|
||||
{
|
||||
ZH_ERROR_CHECK(handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
_zh_avr_160x_send_command(handle, 0x01);
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_set_cursor(zh_avr_pcf8574_handle_t *handle, uint8_t row, uint8_t col)
|
||||
{
|
||||
ZH_ERROR_CHECK(row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4) && col < 16 && handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
_zh_avr_160x_send_command(handle, 0x80 | ((row == 0) ? col : (row == 1) ? (0x40 + col)
|
||||
: (row == 2) ? (0x10 + col)
|
||||
: (0x50 + col)));
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_print_char(zh_avr_pcf8574_handle_t *handle, const char *str)
|
||||
{
|
||||
ZH_ERROR_CHECK(str != NULL && handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
while (*str != 0)
|
||||
{
|
||||
_zh_avr_160x_send_data(handle, (uint8_t)*str++);
|
||||
}
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_print_int(zh_avr_pcf8574_handle_t *handle, int num)
|
||||
{
|
||||
ZH_ERROR_CHECK(handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
char buffer[12];
|
||||
sprintf(buffer, "%d", num);
|
||||
zh_avr_160x_print_char(handle, buffer);
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_print_float(zh_avr_pcf8574_handle_t *handle, float num, uint8_t precision)
|
||||
{
|
||||
ZH_ERROR_CHECK(handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
char buffer[16];
|
||||
sprintf(buffer, "%.*f", precision, num);
|
||||
zh_avr_160x_print_char(handle, buffer);
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_print_progress_bar(zh_avr_pcf8574_handle_t *handle, uint8_t row, uint8_t progress)
|
||||
{
|
||||
ZH_ERROR_CHECK(row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4) && progress <= 100 && handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
uint8_t blocks = (progress * 16) / 100;
|
||||
zh_avr_160x_set_cursor(handle, row, 0);
|
||||
for (uint8_t i = 0; i < 16; ++i)
|
||||
{
|
||||
if (i < blocks)
|
||||
{
|
||||
zh_avr_160x_print_char(handle, "\xFF");
|
||||
}
|
||||
else
|
||||
{
|
||||
zh_avr_160x_print_char(handle, " ");
|
||||
}
|
||||
}
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
avr_err_t zh_avr_160x_clear_row(zh_avr_pcf8574_handle_t *handle, uint8_t row)
|
||||
{
|
||||
ZH_ERROR_CHECK(row < ((*(uint8_t *)handle->system == ZH_LCD_16X2) ? 2 : 4) && handle != NULL, AVR_ERR_INVALID_ARG);
|
||||
ZH_ERROR_CHECK(handle->is_initialized == true, AVR_ERR_INVALID_STATE);
|
||||
zh_avr_160x_set_cursor(handle, row, 0);
|
||||
for (uint8_t i = 0; i < 16; ++i)
|
||||
{
|
||||
zh_avr_160x_print_char(handle, " ");
|
||||
}
|
||||
zh_avr_160x_set_cursor(handle, row, 0);
|
||||
return AVR_OK;
|
||||
}
|
||||
|
||||
static void _zh_avr_160x_lcd_init(zh_avr_pcf8574_handle_t *handle)
|
||||
{
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
zh_avr_pcf8574_write(handle, 0x30);
|
||||
LCD_160X_PULSE;
|
||||
zh_avr_pcf8574_write(handle, 0x30);
|
||||
LCD_160X_PULSE;
|
||||
zh_avr_pcf8574_write(handle, 0x30);
|
||||
LCD_160X_PULSE;
|
||||
zh_avr_pcf8574_write(handle, 0x20);
|
||||
LCD_160X_PULSE;
|
||||
_zh_avr_160x_send_command(handle, 0x28);
|
||||
_zh_avr_160x_send_command(handle, 0x28);
|
||||
_zh_avr_160x_send_command(handle, 0x28);
|
||||
_zh_avr_160x_send_command(handle, 0x0C);
|
||||
_zh_avr_160x_send_command(handle, 0x01);
|
||||
_zh_avr_160x_send_command(handle, 0x06);
|
||||
}
|
||||
|
||||
static void _zh_avr_160x_send_command(zh_avr_pcf8574_handle_t *handle, uint8_t command)
|
||||
{
|
||||
zh_avr_pcf8574_write(handle, (command & 0xF0) | 0x08);
|
||||
LCD_160X_PULSE;
|
||||
zh_avr_pcf8574_write(handle, (command << 4) | 0x08);
|
||||
LCD_160X_PULSE;
|
||||
}
|
||||
|
||||
static void _zh_avr_160x_send_data(zh_avr_pcf8574_handle_t *handle, uint8_t data)
|
||||
{
|
||||
zh_avr_pcf8574_write(handle, (data & 0xF0) | 0x09);
|
||||
LCD_160X_PULSE;
|
||||
zh_avr_pcf8574_write(handle, (data << 4) | 0x09);
|
||||
LCD_160X_PULSE;
|
||||
}
|
Reference in New Issue
Block a user