Скетч из моего же урока у читателя не собрался: компилятор жаловался, что у класса LiquidCrystal_I2C нет метода init. У меня тот же код собирался без проблем. Диагноз оказался банальным: под одним и тем же именем в интернете живут минимум три библиотеки с разными API, и у него стояла другая ветка. Я потратил десять минут на переписку, а потом посмотрел на свой Library Manager и понял: сама библиотека — тема отдельного урока. Где её брать, чем отличаются версии, что у них общего и как не гадать на кофейной гуще.
Разберём установку через менеджер библиотек, конструктор с адресом из сканера, пройдёмся по методам, которые реально пригодятся, и отдельно остановимся на паре init против begin — главной, после электрики из урока про контраст, причине «тёмного экрана при горящей подсветке». Быстрый старт уже был в уроке про первый текст, там же — схема на четыре провода; здесь — полный тур по инструменту.
Оговорка про версии, чтобы потом не возвращаться: рассказываю по самой расхожей ветке — автор Frank de Brabander, в менеджере она значится как LiquidCrystal I2C. У клонов имена методов могут отличаться, но идеи совпадают: всё, что ниже, переносится заменой двух-трёх строк.
Установка, конструктор, адрес
Ставится библиотека стандартно: Tools, затем Library Manager, поиск по «LiquidCrystal I2C» — вся процедура описана в уроке про менеджер библиотек. Ставьте одну ветку и не держите в проекте две: конфликт заголовков лечится только удалением лишней. Если скетч из интернета отказывается собираться, первым делом сверяйте автора библиотеки — по моей статистике это вторая причина сбоев после банальных опечаток. Практический ориентир — число загрузок в менеджере: ветка с сотнями тысяч установок и есть та, что подразумевается в девяти туториалах из десяти. Если менеджер предлагает обновиться — обновляйтесь только вместе со своими скетчами: API между версиями иногда менялся, и рабочая программа после апдейта переставала собираться.
Конструктор выглядит так: LiquidCrystal_I2C lcd(адрес, колонки, строки). Адрес берём из сканера шины — 0x27 или 0x3F, размер — 16 и 2 либо 20 и 4. Пины не указываются вовсе: SDA и SCL на Uno сидят на A4 и A5 жёстко, их не перепрограммируешь. Если адрес в конструкторе не совпал с реальным, шина просто молчит: никакой диагностики — тишина и есть симптом несовпадения. Тот же порядок работает и на крупных панелях — только помните про раскладку строк из урока про 20x4, где текст умеет перетекать через строку.
| Метод | Что делает | Замечание из практики |
|---|---|---|
| init() | Запуск дисплея в расхожей версии | В части клонов отсутствует — тогда begin(16, 2) |
| backlight() / noBacklight() | Вкл и выкл подсветки через бит расширителя | Подсветка — не контраст, V0 не трогает |
| clear() | Стереть экран, курсор в (0, 0) | Не для каждого кадра — даёт вспышку |
| home() | Курсор в (0, 0) без стирания | Редко нужна, но приятно держать в голове |
| setCursor(col, row) | Позиция курсора, нумерация с нуля | setCursor(15, 1) — правый нижний угол 16x2 |
| print(x) | Печать строк и чисел | Имя то же, что у Serial — класс другой |
| print(x, base) | Печать в системе счисления | BIN, OCT, DEC, HEX — как у Serial |
| write(byte(n)) | Печать одного кода или слота | Глифы CGRAM и коды ROM, например 255 |
| cursor() / noCursor() | Курсор-подчёркивание | Наглядно в полях настройки меню |
| blink() / noBlink() | Мигающий курсор | На некоторых клонах игнорируется |
| scrollDisplayLeft()/Right() | Сдвиг всей картинки | Для бегущей строки; курсор не двигается |
| createChar(n, arr) | Заливка слота CGRAM | Подробно — в уроке про свои символы |
#include <Wire.h>#include <LiquidCrystal_I2C.h> // 20x4 и адрес 0x3F: вся разница с 16x2 - в двух аргументах конструктораLiquidCrystal_I2C lcd(0x3F, 20, 4); void setup() { lcd.init(); // в части версий: lcd.begin(20, 4); lcd.backlight(); lcd.setCursor(0, 0); lcd.print("LiquidCrystal_I2C"); lcd.setCursor(1, 1); lcd.print("20x4, adres 0x3F"); lcd.cursor(); // курсор-подчёркивание виден lcd.blink(); // и мигает} void loop() {}Теперь развилка init против begin, о которой я обещал. В ветке Frank de Brabander стартовым методом служит lcd.init(): внутри он делает и begin, и первичную настройку. Часть клонов метода init не знает — там положено звать lcd.begin(16, 2). Симптом один и тот же: подсветка горит, компиляция проходит, а текста нет, потому что стартовую последовательность никто не отправил. Я держу правило: подключил чужой скетч — сверь его стартовые строки с шапкой установленной библиотеки, прежде чем трогать провода. Проверка занимает минуту: замените init на begin(16, 2) — если экран ожил, дело было в версии, и провода ни при чём.
Из таблицы выделю тройку, которая экономит место на экране и ваше время. cursor() рисует подчёркивание в позиции курсора — в меню с курсором это нагляднее угадывания. scrollDisplayLeft() сдвигает всю картинку — на ней собирают бегущие строки, только помните про 10–15 мс на перерисовку по шине из прошлого урока. А createChar и write остаются единственным способом добавить к латинице значки — градус, стрелку, клетки бара из предыдущего урока.
Отдельно про печать чисел. lcd.print работает с теми же перегрузками, что и Serial.print: число печатается как есть, а второй аргумент задаёт систему счисления — lcd.print(counter, HEX) выведет шестнадцатеричный вид. Плавающую точку библиотека по умолчанию рисует с двумя знаками, а lcd.print(temp, 1) — с одним; те же правила у второй строки в Serial, так что навык переносится без переучивания. Эти мелочи избавляют от ручного перевода чисел в строку. И помните про ширину: «T: 5 C» после «T: 25 C» оставит висящую единицу — хвост из пробелов после значения обязателен; экранные странности в девяти случаях из десяти оказываются забытым затирателем.
- Подключите четыре провода: VCC к 5V, GND к GND, SDA к A4, SCL к A5.
- Прогоните сканер шины и запишите адрес — не берите 0x27 «на удачу».
- Поставьте одну библиотеку LiquidCrystal I2C через Library Manager и не добавляйте вторую.
- В скетче: конструктор с найденным адресом, затем init() и backlight(); при пустом экране замените init() на begin(16, 2).
- Текста всё ещё нет — крутите ручку контраста, потом проверяйте SDA и SCL местами.
Практика в симуляторе
Движок понимает LiquidCrystal_I2C из коробки: конструктор создаёт экран, init зажигает подсветку, clear и setCursor работают как на железе. Соберём визитку библиотеки: верхняя строка — имя и адрес, нижняя — счётчик нажатий кнопки на D2; каждое нажатие моргает подсветкой и светит светодиодом на D12. Кнопка здесь обрабатывается по фронту, а не по уровню — удержание считается одним нажатием. Смотрите на затирание хвостов после чисел — это та же гигиена печати, что и в баре из первого урока тройки.
Если моргание подсветки в тренажёре выглядит как полное выключение — так и задумано: бит расширителя гасит транзисторный ключ, и панель темнеет целиком, контраст при этом живёт. На реальном железе то же самое делает lcd.noBacklight() — этим удобно усыплять экран по таймауту, не отключая питание проекта. Рецепт прост: держите millis() последнего нажатия, и когда тишина перевалит за десять секунд, зовите lcd.noBacklight(); по новому нажатию — backlight() и перерисовка экрана. Пара строк кода, а подсветка ночует погашенной и не жжётся впустую. О чипе, который принимает этот бит, — в уроке про PCF8574, а о том, куда расти, когда знакомест станет мало, — в уроке про OLED: та же шина, те же адреса, пиксели вместо клеток.
Тройка про I2C-дисплеи замыкается: бар научился считать столбцы, переходник — экономить пины, библиотека перестала быть чёрным ящиком. Дальше логичные шаги: меню с курсором на том же экране, крупные панели 20x4 или графический OLED. Код у всех этих веток общий — конструктор, setCursor, print — так что время, вложенное в библиотеку, окупится на каждом следующем дисплее. И старое напутствие из урока про createChar остаётся в силе: если на реальном дисплее символы выглядят не так, как ждали, — напечатайте дамп кодов 128–255 и посмотрите свою партию знакогенератора.
- Под именем LiquidCrystal_I2C живут разные ветки; ставьте одну — LiquidCrystal I2C от Frank de Brabander — и не смешивайте
- Конструктор: адрес из сканера плюс размер; пины не задаются — SDA и SCL на Uno это A4 и A5
- Нет lcd.init() — зовите lcd.begin(16, 2); тёмный экран при горящей подсветке часто лечится именно этим
- clear() — для смены экрана, не для каждого кадра; печать поверх с затиранием хвостов пробелами
- cursor(), blink() и scrollDisplayLeft() — дешёвые способы оживить интерфейс без новых пинов
- noBacklight() и backlight() переключают бит расширителя — готовый будильник экрана по таймауту
- 1. Скетч из туториала не собирается: у LiquidCrystal_I2C нет метода init(). Что это чаще всего значит?
- 2. Какой метод заменяет lcd.init() в версиях библиотеки без него?
- 3. Куда встанет курсор после lcd.setCursor(7, 1) на экране 16x2?
- 4. Чем lcd.home() отличается от lcd.clear()?
- 5. Где в коде место адресу, который нашёл сканер шины?
Частые вопросы по теме урока
- Скетч из туториала не собирается: у LiquidCrystal_I2C нет метода init(). Что это чаще всего значит?
- Под одним именем распространяются несколько веток библиотеки с разными API. Сверьте автора установленной библиотеки с шапкой туториала. У вас другая ветка библиотеки с иным API
- Какой метод заменяет lcd.init() в версиях библиотеки без него?
- begin(колонки, строки) отправляет стартовую последовательность в версиях, где метода init нет. backlight и clear работают и без begin, но экран не инициализируют. lcd.begin(16, 2)
- Куда встанет курсор после lcd.setCursor(7, 1) на экране 16x2?
- Аргументы — столбец, затем строка, нумерация с нуля. Столбец 7 — восьмой по счёту, строка 1 — вторая. В восьмой столбец второй строки
- Чем lcd.home() отличается от lcd.clear()?
- clear() затирает всю экранную память и возвращает курсор, home() только перемещает курсор в начало. Текст после home() остаётся на месте. home() возвращает курсор в (0, 0), не стирая текст
- Где в коде место адресу, который нашёл сканер шины?
- Конструктор принимает адрес, колонки и строки: LiquidCrystal_I2C lcd(0x27, 16, 2). Найденный сканером адрес подставляется первым числом. Первый аргумент конструктора LiquidCrystal_I2C