Как использовать I2C LCD дисплей с ESP32
Устали полагаться на Serial Monitor, чтобы видеть, что происходит в ваших проектах на ESP32? I2C LCD дисплей может быть именно тем, что вам нужно.
В отличие от традиционных LCD, которым требуется множество выводов данных, I2C LCD используют всего две линии связи. Более того, эти же два вывода могут быть разделены с другими I2C устройствами. Это значительно упрощает монтаж и сохраняет ценные выводы для подключения других датчиков или компонентов в ваших проектах.
В этом руководстве вы узнаете, как подключить I2C LCD к вашему ESP32, найти I2C адрес LCD и написать код для отображения текста, чисел и даже пользовательских символов.
Готовы зажечь свой следующий проект на ESP32? Давайте начнём!
Обзор оборудования
Типичный I2C LCD дисплей состоит из двух основных частей: символьного LCD дисплея на базе HD44780 и I2C LCD адаптера. Давайте рассмотрим оба этих компонента подробнее.
Символьный LCD дисплей
Символьные LCD дисплеи специально предназначены для отображения букв, цифр и символов. Например, символьный LCD 16×2 может отображать 16 символов в каждой строке, всего две строки.
Если вы внимательно посмотрите на экран, то заметите маленькие прямоугольные области для каждой позиции символа. Внутри каждого из этих прямоугольников находится сетка из 5×8 крошечных точек или пикселей. Эти пиксели загораются в различных комбинациях для формирования различных букв, цифр или символов.
I2C LCD адаптер
Ключевым компонентом этого адаптера является 8-битный расширитель ввода-вывода — микросхема PCF8574. Эта умная микросхема преобразует I2C данные от вашего ESP32 в параллельные данные, которые необходимы LCD дисплею для работы.
На плате адаптера также имеется небольшой подстроечный резистор, который позволяет точно регулировать контрастность дисплея.
Вы заметите, что на плате есть перемычка, которая подаёт питание на подсветку. Если вы хотите управлять яркостью подсветки, вы можете просто убрать эту перемычку и подключить внешний источник напряжения к контактному выводу с маркировкой „LED“.
I2C адрес LCD
Если у вас несколько устройств на одной шине I2C, вам может потребоваться установить другой I2C адрес для LCD адаптера, чтобы избежать конфликтов с другими I2C устройствами.
Для этой цели адаптер оснащён тремя паяными перемычками/площадками (с маркировкой A0, A1 и A2). Для одного LCD можно оставить их без изменений; однако, если вы подключаете несколько I2C устройств или LCD, вам нужно убедиться, что у каждого уникальный адрес, изменив эти перемычки. Вы можете изменить адрес, замкнув перемычку небольшой каплей припоя.
Важно знать, что разные компании, такие как Texas Instruments и NXP Semiconductors, производят одну и ту же микросхему PCF8574. I2C адрес вашего LCD зависит от того, какая компания изготовила микросхему.
Если ваш LCD имеет микросхему PCF8574 от Texas Instruments:
Согласно даташиту Texas Instruments, три бита выбора адреса (A0, A1 и A2) расположены в конце 7-битного регистра I2C адреса.
Поскольку есть три адресных входа, которые могут быть либо HIGH, либо LOW, существует восемь возможных комбинаций (2^3 = 8) адресов.
Все три адресных входа по умолчанию подтянуты к HIGH с помощью встроенных подтягивающих резисторов. Это даёт PCF8574 I2C адрес по умолчанию 0x27.
Когда вы замыкаете паяную перемычку, вы притягиваете этот адресный вход к LOW. Если замкнуть все три перемычки, адрес изменится на 0x20. Таким образом, диапазон возможных адресов составляет от 0x20 до 0x27.
Вы можете установить различные I2C адреса в соответствии с этой таблицей:
Если ваш LCD имеет микросхему PCF8574 от NXP:
Согласно даташиту NXP Semiconductors, три бита выбора адреса (A0, A1 и A2) также расположены в конце 7-битного регистра I2C адреса. Однако остальные биты в регистре адреса отличаются от микросхемы Texas Instruments.
Как и в случае с микросхемой Texas Instruments, существует восемь возможных комбинаций адресов, поскольку три входа могут быть либо HIGH, либо LOW.
Все три адресных входа по умолчанию подтянуты к HIGH с помощью встроенных подтягивающих резисторов. Это даёт PCF8574 I2C адрес по умолчанию 0x3F.
Когда вы замыкаете паяную перемычку, вы притягиваете этот адресный вход к LOW. Если замкнуть все три перемычки, адрес изменится на 0x38. Таким образом, диапазон возможных адресов составляет от 0x38 до 0x3F.
Вы можете установить различные I2C адреса в соответствии с этой таблицей:
Примечание
Таким образом, I2C адрес вашего LCD скорее всего 0x27 или 0x3F. Если вы не уверены, какой I2C адрес у вашего LCD, не волнуйтесь! Есть простой способ узнать это, о котором вы узнаете далее в этом руководстве.
Распиновка I2C LCD дисплея
I2C LCD дисплей имеет всего четыре вывода. Ниже приведена распиновка:
GND — это вывод заземления.
VCC — это вывод питания. Подключите его к выходу 5 В Arduino или внешнему источнику питания 5 В.
SDA — это вывод данных I2C.
SCL — это вывод тактового сигнала I2C.
Подключение I2C LCD дисплея к ESP32
Подключить I2C LCD к ESP32 очень просто, потому что нужно соединить всего четыре вывода.
Начните с подключения вывода VCC на LCD к выводу VIN на ESP32, а вывода GND — к одному из выводов GND (заземление) на ESP32.
Далее подключите два вывода, используемых для I2C связи. Подключите вывод SCL на LCD к D22 на ESP32, а вывод SDA — к D21 на ESP32.
В таблице ниже показаны все необходимые соединения:
I2C LCD |
ESP32 |
|---|---|
VCC |
VIN |
GND |
GND |
SCL |
D22 |
SDA |
D21 |
На этой схеме показано, как именно всё подключить:
Настройка контрастности LCD
После того как вы закончите подключение LCD к ESP32, вам нужно будет отрегулировать контрастность LCD дисплея. Найдите маленький синий подстроечный резистор на плате I2C адаптера — он управляет контрастностью LCD.
Теперь подайте питание на ESP32. Вы должны сразу увидеть, как засветится подсветка. Возьмите маленькую отвёртку и аккуратно поверните ручку потенциометра. По мере регулировки вы начнёте видеть первый ряд прямоугольников на экране. Эти прямоугольники — это места, где будут отображаться символы. Если вы можете чётко видеть эти прямоугольники, поздравляем — ваш LCD работает отлично и готов к отображению текста!
Определение I2C адреса
Прежде чем перейти к примеру кода, вам нужно знать I2C адрес вашего LCD, чтобы правильно взаимодействовать с ним. Как мы упоминали ранее, I2C адрес вашего LCD, вероятно, либо 0x27, либо 0x3F. Вы можете найти этот адрес на наклейке, которая шла с вашим LCD, или в информации о продукте. Но не волнуйтесь, если вы не можете найти эту информацию нигде! Есть простое решение — вы можете запустить простой скетч I2C сканера, который поможет вам автоматически определить правильный адрес.
Загрузите приведённый ниже скетч в Arduino IDE.
#include <Wire.h>
void setup() {
Serial.begin(115200);
// Leonardo: wait for serial port to connect
while (!Serial) {
}
Serial.println();
Serial.println("I2C scanner. Scanning ...");
byte count = 0;
Wire.begin();
for (byte i = 8; i < 120; i++) {
Wire.beginTransmission(i);
if (Wire.endTransmission() == 0) {
Serial.print("Found address: ");
Serial.print(i, DEC);
Serial.print(" (0x");
Serial.print(i, HEX);
Serial.println(")");
count++;
delay(1); // maybe unneeded?
} // end of good response
} // end of for loop
Serial.println("Done.");
Serial.print("Found ");
Serial.print(count, DEC);
Serial.println(" device(s).");
} // end of setup
void loop() {
}
После загрузки скетча в ESP32 откройте монитор порта на скорости 115200 бод и нажмите кнопку EN на ESP32. Через несколько мгновений вы должны увидеть I2C адрес вашего LCD дисплея на экране.
Обязательно запишите этот адрес в надёжное место. Он понадобится вам, когда мы будем работать с LCD в последующих примерах.
Установка библиотеки
Для управления I2C LCD мы будем использовать библиотеку LiquidCrystal_I2C. Эта библиотека значительно упрощает запись на LCD, поскольку она обрабатывает всю сложную I2C коммуникацию в фоновом режиме. Существует несколько версий этой библиотеки, но одной из самых надёжных является версия, созданная Frank de Brabander.
Для установки библиотеки:
Сначала откройте программу Arduino IDE. Затем нажмите на значок Library Manager на левой боковой панели.
Введите «liquidcrystal» в поле поиска для фильтрации результатов.
Найдите библиотеку «LiquidCrystal I2C», созданную Frank de Brabander.
Нажмите кнопку Install, чтобы добавить её в Arduino IDE.
Базовый пример кода — Hello World!
С подключённым оборудованием и установленной библиотекой мы можем написать простой скетч Arduino для отображения текста на LCD. В этом примере мы выведем „Hello World!“ на первой строке LCD и „LCD Tutorial“ на второй строке.
Перед загрузкой скетча вам нужно внести два важных изменения, чтобы он работал с вашим конкретным LCD. Вы должны ввести правильный I2C адрес вашего LCD (который мы нашли ранее) и указать размеры дисплея в конструкторе LiquidCrystal_I2C(). Если вы используете символьный LCD 16×2, введите 16 и 2; если используете LCD 20×4, введите 20 и 4.
// enter the I2C address and the dimensions of your LCD here
LiquidCrystal_I2C lcd(0x3F, 16, 2);
После внесения этих изменений вы готовы попробовать полный скетч:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x3F for a 16 chars and 2 line display
void setup() {
lcd.init();
lcd.clear();
lcd.backlight(); // Make sure backlight is on
// Print a message on both lines of the LCD.
lcd.setCursor(2, 0); //Set cursor to character 2 on line 0
lcd.print("Hello world!");
lcd.setCursor(2, 1); //Move cursor to character 2 on line 1
lcd.print("LCD Tutorial");
}
void loop() {
}
После загрузки этого кода в ESP32, вы должны увидеть на экране следующее:
Объяснение кода:
Скетч начинается с подключения библиотеки LiquidCrystal_I2C, которая даёт нам все необходимые функции для управления LCD.
#include <LiquidCrystal_I2C.h>
Далее мы создаём объект класса LiquidCrystal_I2C. Конструктору LiquidCrystal_I2C нужны три параметра: I2C адрес, количество столбцов и количество строк вашего дисплея.
LiquidCrystal_I2C lcd(0x3F,16,2);
В функции setup мы вызываем три важные функции. Во-первых, функция init() инициализирует интерфейс LCD. Во-вторых, функция clear() стирает всё на экране LCD и перемещает курсор в верхний левый угол. В-третьих, функция backlight() включает подсветку LCD, чтобы мы могли видеть текст.
lcd.init();
lcd.clear();
lcd.backlight();
Функция setCursor(2, 0) перемещает курсор в третий столбец первой строки. (Помните, что счёт начинается с 0, поэтому столбец 2 на самом деле является третьим столбцом.) Позиция курсора указывает LCD, куда размещать новый текст на экране. Верхний левый угол считается позицией (0,0).
lcd.setCursor(2,0);
Затем мы используем функцию print() для отображения текста «Hello world!» на LCD.
lcd.print("Hello world!");
Аналогично, следующие две строки кода перемещают курсор в третий столбец второй строки и выводят „LCD Tutorial“ на LCD.
lcd.setCursor(2,1);
lcd.print("LCD Tutorial");
Пример прокрутки текста
Если у вас сообщение длиннее 16 символов, или вы хотите создать эффект бегущей строки, вы можете использовать функции scrollDisplayLeft() или scrollDisplayRight() в цикле для перемещения текста по экрану.
Скетч ниже показывает, как непрерывно прокручивать сообщение влево:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); // set the LCD address to 0x3F for a 16 chars and 2 line display
void setup() {
lcd.init();
lcd.clear();
lcd.backlight(); // Make sure backlight is on
// Print a message
lcd.print("Scrolling Text Demo");
delay(1000); // pause to read the message initially
}
void loop() {
lcd.scrollDisplayLeft(); // scroll everything to the left by one position
delay(300); // small delay for visible scrolling speed
}
Когда вы загрузите этот код в ESP32, ваш LCD отобразит что-то подобное:
Объяснение кода:
В этом примере мы выводим сообщение длиной 19 символов («Scrolling Text Demo») на LCD. Поскольку дисплей может показать только 16 символов одновременно, изначально будут видны только первые 16 символов.
// Print a message to the LCD
lcd.print("Scrolling Text Demo");
В функции loop() мы вызываем lcd.scrollDisplayLeft(), которая сдвигает всё содержимое дисплея на одну позицию влево. Повторяя это с небольшой задержкой между каждым сдвигом, сообщение плавно перемещается по экрану.
void loop() {
lcd.scrollDisplayLeft(); // scroll everything to the left by one position
delay(300); // small delay for visible scrolling speed
}
По мере прокрутки текста символы, выходящие за левый край, исчезают, а на правой стороне экрана появляются пустые места. Если вы хотите, чтобы сообщение непрерывно повторялось, вам нужно добавить код, который периодически заново выводит сообщение.
Для прокрутки в обратном направлении (справа налево) вы можете использовать lcd.scrollDisplayRight() вместо этого.
Другие полезные функции библиотеки LiquidCrystal_I2C
Объект LiquidCrystal_I2C предоставляет множество полезных функций для управления LCD. Вот некоторые из наиболее полезных:
lcd.home()перемещает курсор обратно в верхний левый угол LCD (первая позиция первой строки). В отличие отclear(), она не стирает то, что уже есть на экране — она просто перемещает курсор в начальную позицию.lcd.blink()иlcd.noBlink()включают или выключают мигающий блочный курсор. При включении с помощьюblink()вы увидите сплошной блок, который мигает в текущей позиции курсора. Это отлично подходит для привлечения внимания пользователя или показа того, где появится следующий текст. Если вам не нужен этот мигающий блок, используйтеnoBlink()для его отключения.lcd.cursor()иlcd.noCursor()управляют тем, отображается ли подчёркивание (_) в позиции, где будет написан следующий символ. Функцияcursor()показывает эту линию, аnoCursor()скрывает её. Это отличается от мигающего блока — это просто линия, показывающая, где будет следующий символ.lcd.display()иlcd.noDisplay()позволяют включать или выключать весь дисплей без стирания данных. Когда вы используетеnoDisplay(), экран становится пустым, но весь текст остаётся в памяти LCD. Когда вы снова вызоветеdisplay(), всё появится обратно! Это идеально для создания эффектов мигания или экономии энергии, когда дисплей не нужен.
Попробуйте поэкспериментировать с этими функциями в вашем собственном коде, чтобы увидеть, как они работают. Они помогут вам создавать более интерактивные и динамичные дисплеи для ваших проектов!
Создание и отображение пользовательских символов
Иногда вам может понадобиться отобразить специальные символы, которые не являются частью стандартного алфавита или цифр — например, такие символы, как смайлик, символ градуса (°) для показаний температуры, или забавные иконки, такие как сердечки, музыкальные ноты или стрелки.
Хорошая новость в том, что LCD на базе HD44780 позволяют создать до 8 пользовательских символов собственного дизайна! Как мы узнали ранее в этом руководстве, каждый символ на LCD отображается с помощью маленькой сетки пикселей, расположенных в формате 5×8 (5 пикселей в ширину и 8 пикселей в высоту). Для создания своего собственного символа вам нужно решить, какие из этих крошечных точек должны быть включены, а какие — выключены.
Для создания пользовательского символа сначала нужно создать массив из 8 байт в вашем коде. Каждый байт в этом массиве представляет одну горизонтальную строку вашего символа, начиная с верхней строки и заканчивая нижней. Для каждого байта вы будете использовать биты (единицы и нули в двоичной системе), чтобы указать, какие пиксели должны быть ВКЛЮЧЕНЫ (1), а какие ВЫКЛЮЧЕНЫ (0). Используются только первые 5 бит каждого байта, поскольку символ имеет ширину 5 пикселей.
После того как вы спроектировали символ, настроив этот массив, вы можете использовать функцию createChar() для сохранения пользовательского символа в CGRAM (Character Generator RAM) LCD, которая является специальной областью памяти, предназначенной именно для хранения пользовательских символов.
Теперь давайте создадим несколько крутых пользовательских символов для ваших проектов!
Примечание
CGROM vs. CGRAM
Все LCD на базе контроллера Hitachi HD44780 имеют два типа памяти: CGROM (Character Generator Read-Only Memory — Постоянная память генератора символов) и CGRAM (Character Generator Random Access Memory — Оперативная память генератора символов).
CGROM — это энергонезависимая память, что означает, что она сохраняет данные даже при выключении питания. Она хранит предопределённые точечные шаблоны для стандартных символов ASCII, таких как буквы, цифры и общие символы. Когда вы хотите отобразить «A» на экране, вы отправляете код для «A» (который равен 0x41 в шестнадцатеричной системе), и контроллер LCD ищет точечный шаблон для «A» в своей CGROM и отображает его. Это делает отображение обычных символов очень быстрым и простым!
CGRAM, однако, является энергозависимой памятью, поэтому она теряет свои данные при отключении питания. Эта память гибкая и позволяет хранить пользовательские точечные шаблоны, которых нет во встроенном наборе. Например, вы можете создавать собственные символы, иконки или уникальные знаки для вашего проекта. Однако CGRAM имеет ограниченное пространство — всего 64 байта. На стандартном LCD с пикселями 5×8 это означает, что вы можете хранить только 8 пользовательских символов (поскольку каждый символ требует 8 байт). Если вы используете LCD с пикселями 5×10, вы можете хранить только 4 пользовательских символа, потому что каждый из них требует больше памяти.
Подводя итог: CGROM — это память только для чтения с фиксированными шаблонами символов, которые нельзя изменить, тогда как CGRAM — это записываемая память, позволяющая создавать и сохранять пользовательские символы, когда они вам нужны.
Генератор пользовательских символов
Создание пользовательских символов никогда не было проще! Мы разработали полезный инструмент — генератор пользовательских символов. Видите синюю сетку ниже? Вы можете нажать на любой пиксель, чтобы включить или выключить его, и по мере этого код для вашего символа автоматически создаётся рядом с сеткой. Вы можете скопировать этот код прямо в ваш скетч Arduino.
пиксели
| byte Character[8] = |
| { |
| 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000 |
| }; |
Скопируйте
код в скетч
Возможности для создания практически бесконечны! Вы можете создать стрелки, простых животных, игровых персонажей, символы погоды или любую маленькую иконку, которая помещается в сетку 5×8. Единственное ограничение заключается в том, что библиотека LiquidCrystal_I2C позволяет использовать одновременно только восемь пользовательских символов. Но не волнуйтесь — восьми различных пользовательских символов всё равно достаточно, чтобы сделать ваш проект уникальным и интересным!
Пример кода для ESP32
Скетч ниже показывает, как именно отобразить ваши пользовательские символы на LCD:
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x3F for a 16 chars and 2 line display
// make some custom characters:
byte Heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};
byte Bell[8] = {
0b00100,
0b01110,
0b01110,
0b01110,
0b11111,
0b00000,
0b00100,
0b00000
};
byte Alien[8] = {
0b11111,
0b10101,
0b11111,
0b11111,
0b01110,
0b01010,
0b11011,
0b00000
};
byte Check[8] = {
0b00000,
0b00001,
0b00011,
0b10110,
0b11100,
0b01000,
0b00000,
0b00000
};
byte Speaker[8] = {
0b00001,
0b00011,
0b01111,
0b01111,
0b01111,
0b00011,
0b00001,
0b00000
};
byte Sound[8] = {
0b00001,
0b00011,
0b00101,
0b01001,
0b01001,
0b01011,
0b11011,
0b11000
};
byte Skull[8] = {
0b00000,
0b01110,
0b10101,
0b11011,
0b01110,
0b01110,
0b00000,
0b00000
};
byte Lock[8] = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000
};
void setup() {
lcd.init();
// Make sure backlight is on
lcd.backlight();
// create a new characters
lcd.createChar(0, Heart);
lcd.createChar(1, Bell);
lcd.createChar(2, Alien);
lcd.createChar(3, Check);
lcd.createChar(4, Speaker);
lcd.createChar(5, Sound);
lcd.createChar(6, Skull);
lcd.createChar(7, Lock);
// Clears the LCD screen
lcd.clear();
// Print a message to the lcd.
lcd.print("Custom Character");
}
// Print All the custom characters
void loop() {
lcd.setCursor(0, 1);
lcd.write(0);
lcd.setCursor(2, 1);
lcd.write(1);
lcd.setCursor(4, 1);
lcd.write(2);
lcd.setCursor(6, 1);
lcd.write(3);
lcd.setCursor(8, 1);
lcd.write(4);
lcd.setCursor(10, 1);
lcd.write(5);
lcd.setCursor(12, 1);
lcd.write(6);
lcd.setCursor(14, 1);
lcd.write(7);
}
Когда вы загрузите этот код в ESP32, ваш LCD отобразит что-то подобное:
Попробуйте и поэкспериментируйте с созданием своих собственных уникальных символов!
Объяснение кода:
После подключения библиотеки LiquidCrystal_I2C и настройки объекта LCD код определяет специальные массивы для наших пользовательских символов. Каждый массив содержит ровно 8 байт, и каждый байт управляет одной строкой точек в нашей сетке символа 5×8.
Пример включает восемь различных пользовательских символов. Давайте рассмотрим массив Heart[8] в качестве примера:
byte Heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};
Каждая строка представляет один ряд пикселей, начиная с верха символа. Префикс «0b» в начале просто указывает Arduino, что это двоичное число (состоящее из 0 и 1). Каждый 0 означает «пиксель выключен», а каждая 1 означает «пиксель включён». Если вы внимательно посмотрите на шаблон, вы увидите, как единицы формируют форму сердца!
В секции setup кода мы используем функцию createChar() для сохранения нашего пользовательского символа в памяти LCD. Эта функция требует два параметра: число от 0 до 7 (которое указывает LCD, какой из восьми доступных слотов памяти использовать) и имя массива, содержащего дизайн символа.
Код ниже сохраняет наш дизайн сердца в слот 0 памяти CGRAM LCD.
// create a new character
lcd.createChar(0, Heart);
Наконец, в секции loop мы отображаем наш пользовательский символ с помощью функции write(). Мы указываем, какой символ отобразить, передавая номер слота памяти:
// byte(0) represents Heart character.
lcd.write(byte(0));