├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md └── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── app_main.c └── component.mk /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig 3 | sdkconfig.old 4 | 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "components/esp32-smbus"] 2 | path = components/esp32-smbus 3 | url = https://github.com/DavidAntliff/esp32-smbus.git 4 | [submodule "components/esp32-i2c-lcd1602"] 5 | path = components/esp32-i2c-lcd1602 6 | url = https://github.com/DavidAntliff/esp32-i2c-lcd1602.git 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: bionic 3 | language: python 4 | python: "3.8" 5 | 6 | jobs: 7 | include: 8 | - stage: # IDF v3.3 9 | install: 10 | # Install ESP32 toochain following steps as described 11 | # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html 12 | # 13 | # Download binary toolchain for the ESP32 14 | - pushd ~ 15 | - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz 16 | - tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz 17 | # Make xtensa-esp32-elf available for all terminal sessions 18 | - export PATH=$PATH:$(pwd)/xtensa-esp32-elf/bin 19 | # Get ESP-IDF from github 20 | - git clone --recursive --branch v3.3 --single-branch --shallow-submodules https://github.com/espressif/esp-idf.git esp-idf 21 | # Set the path to ESP-IDF directory 22 | - export IDF_PATH=$(pwd)/esp-idf 23 | # Install python dependencies 24 | - pip install --requirement $IDF_PATH/requirements.txt 25 | - popd 26 | script: 27 | - $IDF_PATH/tools/idf.py build 28 | 29 | - stage: # IDF v4.1-beta1 30 | install: 31 | - pushd ~ 32 | - git clone --recursive --branch v4.1-beta1 --single-branch --shallow-submodules https://github.com/espressif/esp-idf.git esp-idf 33 | - esp-idf/install.sh 34 | - popd 35 | script: 36 | - source ~/esp-idf/export.sh && idf.py build 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following five lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(esp32-i2c-lcd1602-example) 7 | 8 | if (NOT IDF_VERSION_MAJOR) 9 | set(IDF_VERSION_MAJOR 3) 10 | endif() 11 | 12 | if (IDF_VERSION_MAJOR GREATER 3) 13 | set(PROJECT_ELF ${project_elf}) 14 | else() 15 | set(PROJECT_ELF ${IDF_PROJECT_EXECUTABLE}) 16 | endif() 17 | 18 | # Ignore false clang warnings about `struct foo = { 0 }` 19 | target_compile_options(${PROJECT_ELF} PRIVATE -Wno-missing-braces -Wmissing-field-initializers) 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Antliff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := esp32-i2c-lcd1602-example 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32-i2c-lcd1602-example 2 | 3 | [![Platform: ESP-IDF](https://img.shields.io/badge/ESP--IDF-v3.0%2B-blue.svg)](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/) 4 | [![Build Status](https://travis-ci.org/DavidAntliff/esp32-i2c-lcd1602-example.svg?branch=master)](https://travis-ci.org/DavidAntliff/esp32-i2c-lcd1602-example) 5 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 6 | 7 | ## Introduction 8 | 9 | This is an example application for the HD4470-compatible LCD1602 device connected via an I2C backpack. 10 | 11 | This application is also usable with an LCD2004 module (20 columns, 4 rows), by uncommenting the `LCD_NUM_ROWS`, `LCD_NUM_COLUMNS`, and `LCD_NUM_VISIBLE_COLUMNS` definitions at the top of `app_main.c`. 12 | 13 | It is written and tested for v3.3 of the [ESP-IDF](https://github.com/espressif/esp-idf) environment, using the xtensa-esp32-elf toolchain (gcc version 5.2.0). 14 | 15 | Ensure that submodules are cloned: 16 | 17 | $ git clone --recursive https://github.com/DavidAntliff/esp32-i2c-lcd1602-example.git 18 | 19 | Build the application with: 20 | 21 | $ cd esp32-i2c-lcd1602-example.git 22 | $ idf.py menuconfig # set your serial configuration and the I2C GPIO - see below 23 | $ idf.py build 24 | $ idf.py -p (PORT) flash monitor 25 | 26 | The program should detect your connected device and display some demonstration text on the LCD. 27 | 28 | ## Dependencies 29 | 30 | This application makes use of the following components (included as submodules): 31 | 32 | * components/[esp32-smbus](https://github.com/DavidAntliff/esp32-smbus) 33 | * components/[esp32-i2c-lcd1602](https://github.com/DavidAntliff/esp32-i2c-lcd1602) 34 | 35 | ## Hardware 36 | 37 | To run this example, connect one LCD1602 device to two GPIOs on the ESP32 (I2C SDA and SCL). If external pull-up resistors are not provided with the sensor, add a 10 KOhm resistor from each GPIO to the 3.3V supply. 38 | 39 | `idf.py menuconfig` can be used to set the I2C GPIOs and LCD1602 device I2C address. 40 | 41 | Note that the 3.3V supply may be insufficient to run the display satisfactorily. In this case I suggest using a 5V supply to the LCD display, and using appropriate level shifter circuitry on the I2C SCL and SDA connections. 42 | 43 | ## Features 44 | 45 | This example steps through the features of the esp32-i2c-lcd1602 component. It demonstrates: 46 | 47 | * Display initialisation, disabling and enabling, clearing. 48 | * Backlight control. 49 | * Underline and blinking cursor control, including arbitrary cursor movement and homing. 50 | * Display scrolling. 51 | * Custom character definition. 52 | * Display of all characters. 53 | 54 | Each step waits for a keypress on stdin before executing. If stdin is not available (no USB/UART available), modify the following code: 55 | 56 | ``` 57 | //#define USE_STDIN 1 58 | #undef USE_STDIN 59 | ``` 60 | 61 | Each step will then wait for one second before proceeding automatically. 62 | 63 | ## Source Code 64 | 65 | The source is available from [GitHub](https://www.github.com/DavidAntliff/esp32-i2c-lcd1602-example). 66 | 67 | ## License 68 | 69 | The code in this project is licensed under the MIT license - see LICENSE for details. 70 | 71 | ## Links 72 | 73 | * [HD44780 Dot Matrix Liquid Crystal Display Controller/Driver datasheet](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) 74 | * [Espressif IoT Development Framework for ESP32](https://github.com/espressif/esp-idf) 75 | 76 | ## Acknowledgements 77 | 78 | * "I2C" is a registered trademark of Phillips Corporation. 79 | * "SMBus" is a trademark of Intel Corporation. 80 | 81 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCDIRS ".") 2 | set(COMPONENT_ADD_INCLUDEDIRS ".") 3 | 4 | register_component() 5 | 6 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "esp32-i2c-lcd1602-example Configuration" 2 | 3 | config I2C_MASTER_SCL 4 | int "I2C Master SCL GPIO number" 5 | range 0 34 6 | default 19 7 | help 8 | GPIO number (IOxx) for I2C SCL. 9 | 10 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used. 11 | 12 | GPIOs 35-39 are input-only so cannot be used to drive the One Wire Bus. 13 | 14 | config I2C_MASTER_SDA 15 | int "I2C Master SDA GPIO number" 16 | range 0 34 17 | default 18 18 | help 19 | GPIO number (IOxx) for I2C SDA. 20 | 21 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used. 22 | 23 | GPIOs 35-39 are input-only so cannot be used to drive the One Wire Bus. 24 | 25 | config LCD1602_I2C_ADDRESS 26 | hex "I2C Address for LCD1602 device" 27 | default 0x27 28 | help 29 | I2C address for HD44780-compatible LCD1602 device. 30 | 31 | endmenu 32 | -------------------------------------------------------------------------------- /main/app_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2018 David Antliff 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file app_main.c 27 | * @brief Example application for the LCD1602 16x2 Character Dot Matrix LCD display via I2C backpack.. 28 | */ 29 | 30 | #include 31 | #include "freertos/FreeRTOS.h" 32 | #include "freertos/task.h" 33 | #include "esp_system.h" 34 | #include "driver/gpio.h" 35 | #include "driver/i2c.h" 36 | #include "esp_log.h" 37 | #include "sdkconfig.h" 38 | #include "rom/uart.h" 39 | 40 | #include "smbus.h" 41 | #include "i2c-lcd1602.h" 42 | 43 | #define TAG "app" 44 | 45 | // LCD1602 46 | #define LCD_NUM_ROWS 2 47 | #define LCD_NUM_COLUMNS 32 48 | #define LCD_NUM_VISIBLE_COLUMNS 16 49 | 50 | // LCD2004 51 | //#define LCD_NUM_ROWS 4 52 | //#define LCD_NUM_COLUMNS 40 53 | //#define LCD_NUM_VISIBLE_COLUMNS 20 54 | 55 | // Undefine USE_STDIN if no stdin is available (e.g. no USB UART) - a fixed delay will occur instead of a wait for a keypress. 56 | #define USE_STDIN 1 57 | //#undef USE_STDIN 58 | 59 | #define I2C_MASTER_NUM I2C_NUM_0 60 | #define I2C_MASTER_TX_BUF_LEN 0 // disabled 61 | #define I2C_MASTER_RX_BUF_LEN 0 // disabled 62 | #define I2C_MASTER_FREQ_HZ 100000 63 | #define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA 64 | #define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL 65 | 66 | static void i2c_master_init(void) 67 | { 68 | int i2c_master_port = I2C_MASTER_NUM; 69 | i2c_config_t conf; 70 | conf.mode = I2C_MODE_MASTER; 71 | conf.sda_io_num = I2C_MASTER_SDA_IO; 72 | conf.sda_pullup_en = GPIO_PULLUP_DISABLE; // GY-2561 provides 10kΩ pullups 73 | conf.scl_io_num = I2C_MASTER_SCL_IO; 74 | conf.scl_pullup_en = GPIO_PULLUP_DISABLE; // GY-2561 provides 10kΩ pullups 75 | conf.master.clk_speed = I2C_MASTER_FREQ_HZ; 76 | i2c_param_config(i2c_master_port, &conf); 77 | i2c_driver_install(i2c_master_port, conf.mode, 78 | I2C_MASTER_RX_BUF_LEN, 79 | I2C_MASTER_TX_BUF_LEN, 0); 80 | } 81 | 82 | // uart_rx_one_char_block() causes a watchdog trigger, so use the non-blocking 83 | // uart_rx_one_char() and delay briefly to reset the watchdog. 84 | static uint8_t _wait_for_user(void) 85 | { 86 | uint8_t c = 0; 87 | 88 | #ifdef USE_STDIN 89 | while (!c) 90 | { 91 | STATUS s = uart_rx_one_char(&c); 92 | if (s == OK) { 93 | printf("%c", c); 94 | } 95 | vTaskDelay(1); 96 | } 97 | #else 98 | vTaskDelay(1000 / portTICK_RATE_MS); 99 | #endif 100 | return c; 101 | } 102 | 103 | void lcd1602_task(void * pvParameter) 104 | { 105 | // Set up I2C 106 | i2c_master_init(); 107 | i2c_port_t i2c_num = I2C_MASTER_NUM; 108 | uint8_t address = CONFIG_LCD1602_I2C_ADDRESS; 109 | 110 | // Set up the SMBus 111 | smbus_info_t * smbus_info = smbus_malloc(); 112 | ESP_ERROR_CHECK(smbus_init(smbus_info, i2c_num, address)); 113 | ESP_ERROR_CHECK(smbus_set_timeout(smbus_info, 1000 / portTICK_RATE_MS)); 114 | 115 | // Set up the LCD1602 device with backlight off 116 | i2c_lcd1602_info_t * lcd_info = i2c_lcd1602_malloc(); 117 | ESP_ERROR_CHECK(i2c_lcd1602_init(lcd_info, smbus_info, true, 118 | LCD_NUM_ROWS, LCD_NUM_COLUMNS, LCD_NUM_VISIBLE_COLUMNS)); 119 | 120 | ESP_ERROR_CHECK(i2c_lcd1602_reset(lcd_info)); 121 | 122 | // turn off backlight 123 | ESP_LOGI(TAG, "backlight off"); 124 | _wait_for_user(); 125 | i2c_lcd1602_set_backlight(lcd_info, false); 126 | 127 | // turn on backlight 128 | ESP_LOGI(TAG, "backlight on"); 129 | _wait_for_user(); 130 | i2c_lcd1602_set_backlight(lcd_info, true); 131 | 132 | ESP_LOGI(TAG, "cursor on"); 133 | _wait_for_user(); 134 | i2c_lcd1602_set_cursor(lcd_info, true); 135 | 136 | ESP_LOGI(TAG, "display A at 0,0"); 137 | _wait_for_user(); 138 | i2c_lcd1602_move_cursor(lcd_info, 0, 0); 139 | i2c_lcd1602_write_char(lcd_info, 'A'); 140 | 141 | ESP_LOGI(TAG, "display B at 8,0"); 142 | _wait_for_user(); 143 | i2c_lcd1602_move_cursor(lcd_info, 8, 0); 144 | i2c_lcd1602_write_char(lcd_info, 'B'); 145 | 146 | ESP_LOGI(TAG, "display C at 15,1"); 147 | _wait_for_user(); 148 | i2c_lcd1602_move_cursor(lcd_info, 15, 1); 149 | i2c_lcd1602_write_char(lcd_info, 'C'); 150 | 151 | ESP_LOGI(TAG, "move to 0,1 and blink"); // cursor should still be on 152 | _wait_for_user(); 153 | i2c_lcd1602_move_cursor(lcd_info, 0, 1); 154 | i2c_lcd1602_set_blink(lcd_info, true); 155 | 156 | ESP_LOGI(TAG, "display DE and move cursor back onto D"); 157 | _wait_for_user(); 158 | i2c_lcd1602_write_char(lcd_info, 'D'); 159 | i2c_lcd1602_set_right_to_left(lcd_info); 160 | i2c_lcd1602_write_char(lcd_info, 'E'); 161 | i2c_lcd1602_set_left_to_right(lcd_info); 162 | 163 | ESP_LOGI(TAG, "disable display"); 164 | _wait_for_user(); 165 | i2c_lcd1602_set_display(lcd_info, false); 166 | 167 | ESP_LOGI(TAG, "display F at 7,1 (display disabled)"); 168 | _wait_for_user(); 169 | i2c_lcd1602_move_cursor(lcd_info, 7, 1); 170 | i2c_lcd1602_write_char(lcd_info, 'F'); 171 | 172 | ESP_LOGI(TAG, "enable display"); 173 | _wait_for_user(); 174 | i2c_lcd1602_set_display(lcd_info, true); 175 | 176 | ESP_LOGI(TAG, "disable blink"); 177 | _wait_for_user(); 178 | i2c_lcd1602_set_blink(lcd_info, false); // cursor should still be on 179 | 180 | ESP_LOGI(TAG, "disable cursor"); 181 | _wait_for_user(); 182 | i2c_lcd1602_set_cursor(lcd_info, false); 183 | 184 | ESP_LOGI(TAG, "display alphabet from 0,0"); // should overflow to second line at "ABC..." 185 | _wait_for_user(); 186 | i2c_lcd1602_home(lcd_info); 187 | i2c_lcd1602_write_string(lcd_info, "abcdefghijklmnopqrstuvwxyz0123456789.,-+ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 188 | 189 | ESP_LOGI(TAG, "scroll display left 8 places slowly"); 190 | _wait_for_user(); 191 | for (int i = 0; i < 8; ++i) 192 | { 193 | i2c_lcd1602_scroll_display_left(lcd_info); 194 | vTaskDelay(200 / portTICK_RATE_MS); 195 | } 196 | 197 | ESP_LOGI(TAG, "scroll display right 8 places quickly"); 198 | _wait_for_user(); 199 | for (int i = 0; i < 8; ++i) 200 | { 201 | i2c_lcd1602_scroll_display_right(lcd_info); 202 | } 203 | 204 | ESP_LOGI(TAG, "move to 8,0 and show cursor"); 205 | _wait_for_user(); 206 | i2c_lcd1602_move_cursor(lcd_info, 8, 0); 207 | i2c_lcd1602_set_cursor(lcd_info, true); 208 | 209 | ESP_LOGI(TAG, "move cursor 5 places to the right"); 210 | _wait_for_user(); 211 | for (int i = 0; i < 5; ++i) 212 | { 213 | i2c_lcd1602_move_cursor_right(lcd_info); 214 | } 215 | 216 | ESP_LOGI(TAG, "move cursor 3 places to the left"); 217 | _wait_for_user(); 218 | for (int i = 0; i < 3; ++i) 219 | { 220 | i2c_lcd1602_move_cursor_left(lcd_info); 221 | } 222 | 223 | ESP_LOGI(TAG, "enable auto-scroll and display >>>>>"); 224 | _wait_for_user(); 225 | i2c_lcd1602_set_auto_scroll(lcd_info, true); 226 | for (int i = 0; i < 5; ++i) 227 | { 228 | i2c_lcd1602_write_char(lcd_info, '>'); 229 | vTaskDelay(200 / portTICK_RATE_MS); 230 | } 231 | 232 | ESP_LOGI(TAG, "change address counter to decrement (right to left) and display <<<<<"); 233 | _wait_for_user(); 234 | i2c_lcd1602_set_right_to_left(lcd_info); 235 | for (int i = 0; i < 5; ++i) 236 | { 237 | i2c_lcd1602_write_char(lcd_info, '<'); 238 | vTaskDelay(200 / portTICK_RATE_MS); 239 | } 240 | 241 | ESP_LOGI(TAG, "disable auto-scroll and display +++++"); 242 | _wait_for_user(); 243 | i2c_lcd1602_set_auto_scroll(lcd_info, false); 244 | for (int i = 0; i < 5; ++i) 245 | { 246 | i2c_lcd1602_write_char(lcd_info, '+'); 247 | vTaskDelay(200 / portTICK_RATE_MS); 248 | } 249 | 250 | ESP_LOGI(TAG, "set left_to_right and display >>>>>"); 251 | _wait_for_user(); 252 | i2c_lcd1602_set_left_to_right(lcd_info); 253 | for (int i = 0; i < 5; ++i) 254 | { 255 | i2c_lcd1602_write_char(lcd_info, '>'); 256 | vTaskDelay(200 / portTICK_RATE_MS); 257 | } 258 | 259 | ESP_LOGI(TAG, "clear display and disable cursor"); 260 | _wait_for_user(); 261 | i2c_lcd1602_clear(lcd_info); 262 | i2c_lcd1602_set_cursor(lcd_info, false); 263 | 264 | ESP_LOGI(TAG, "create and display custom characters"); 265 | _wait_for_user(); 266 | // https://github.com/agnunez/ESP8266-I2C-LCD1602/blob/master/examples/CustomChars/CustomChars.ino 267 | uint8_t bell[8] = {0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4}; 268 | uint8_t note[8] = {0x2, 0x3, 0x2, 0xe, 0x1e, 0xc, 0x0}; 269 | uint8_t clock[8] = {0x0, 0xe, 0x15, 0x17, 0x11, 0xe, 0x0}; 270 | uint8_t heart[8] = {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0}; 271 | uint8_t duck[8] = {0x0, 0xc, 0x1d, 0xf, 0xf, 0x6, 0x0}; 272 | uint8_t check[8] = {0x0, 0x1 ,0x3, 0x16, 0x1c, 0x8, 0x0}; 273 | uint8_t cross[8] = {0x0, 0x1b, 0xe, 0x4, 0xe, 0x1b, 0x0}; 274 | uint8_t retarrow[8] = { 0x1, 0x1, 0x5, 0x9, 0x1f, 0x8, 0x4}; 275 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_0, bell); 276 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_1, note); 277 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_2, clock); 278 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_3, heart); 279 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_4, duck); 280 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_5, check); 281 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_6, cross); 282 | i2c_lcd1602_define_char(lcd_info, I2C_LCD1602_INDEX_CUSTOM_7, retarrow); 283 | 284 | // after defining custom characters, DDRAM address must be set by home() or moving the cursor 285 | i2c_lcd1602_move_cursor(lcd_info, 0, 0); 286 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_0); 287 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_1); 288 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_2); 289 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_3); 290 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_4); 291 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_5); 292 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_6); 293 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_CUSTOM_7); 294 | 295 | ESP_LOGI(TAG, "display special characters"); 296 | _wait_for_user(); 297 | i2c_lcd1602_move_cursor(lcd_info, 0, 1); 298 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_ALPHA); 299 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_BETA); 300 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_THETA); 301 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_PI); 302 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_OMEGA); 303 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_SIGMA); 304 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_INFINITY); 305 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_DEGREE); 306 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_ARROW_LEFT); 307 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_ARROW_RIGHT); 308 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_SQUARE); 309 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_DOT); 310 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_DIVIDE); 311 | i2c_lcd1602_write_char(lcd_info, I2C_LCD1602_CHARACTER_BLOCK); 312 | 313 | ESP_LOGI(TAG, "display all characters (loop)"); 314 | _wait_for_user(); 315 | i2c_lcd1602_clear(lcd_info); 316 | i2c_lcd1602_set_cursor(lcd_info, true); 317 | uint8_t c = 0; 318 | uint8_t col = 0; 319 | uint8_t row = 0; 320 | while (1) 321 | { 322 | i2c_lcd1602_write_char(lcd_info, c); 323 | vTaskDelay(100 / portTICK_RATE_MS); 324 | ESP_LOGD(TAG, "col %d, row %d, char 0x%02x", col, row, c); 325 | ++c; 326 | ++col; 327 | if (col >= LCD_NUM_VISIBLE_COLUMNS) 328 | { 329 | ++row; 330 | if (row >= LCD_NUM_ROWS) 331 | { 332 | row = 0; 333 | } 334 | col = 0; 335 | i2c_lcd1602_move_cursor(lcd_info, col, row); 336 | } 337 | } 338 | 339 | vTaskDelete(NULL); 340 | } 341 | 342 | void app_main() 343 | { 344 | xTaskCreate(&lcd1602_task, "lcd1602_task", 4096, NULL, 5, NULL); 345 | } 346 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | --------------------------------------------------------------------------------