Курс Arduino с нуля · Индикаторы и экраны

Урок 26. Экран LCD: выводим текст и цифры

Подключаем экран LCD1602 на две строки по шестнадцать знаков. Разбираемся, зачем ему столько проводов и потенциометр, и учим плату писать слова, показывать числа и рисовать свои значки.

Урок 26 из 31⏱ примерно 60 минутОбновлено: 28 июля 2026

Что понадобится

  • Плата Uno из набора
  • Кабель USB
  • Макетная плата
  • Экран LCD1602
  • Потенциометр 10 кОм
  • Тактовая кнопка
  • Фоторезистор и резистор 10 кОм
  • 16 проводов «папа-папа»

Все детали есть в обучающем наборе, по которому идёт курс.

В прошлом уроке индикатор показывал одну цифру. Сегодня возьмём деталь посерьёзнее — экран LCD1602. На нём помещаются две строки по шестнадцать знаков: уже можно написать слово, показать температуру с подписью или вывести меню.

Урок будет чуть длиннее обычного: проводов к экрану идёт много. Зато потом всё окупится — любое ваше устройство сможет объясняться словами, а не морганием.

Что это за деталь

Privet,Arduino!Urok261VSS2VDD3V04RS5RW6E7D08D19D210D311D412D513D614D715A16KЧто делает каждый контакт1, 5, 16на «минус»2, 15на «плюс»3контраст — к потенциометру4, 6команды: RS и E11, 12, 13, 14данные: D4…D77, 8, 9, 10не используютсяЭкран показывает две строки по 16 знаков: каждая буква складывается из точек в своей клетке.
Экран LCD1602: две строки по 16 знаков и гребёнка из 16 контактов вдоль верхнего края. Цвет подсказывает, куда пойдёт каждый контакт.

Название читается просто: LCD — жидкокристаллический экран, 16 знаков в строке, 02 строки. Сзади у него зелёная подсветка, поэтому надписи видно и в темноте.

Сверху — ряд из шестнадцати контактов с тем же шагом, что у отверстий макетной платы. Это удобно: экран просто вставляется в макетку, как большая микросхема.

Контакты пронумерованы прямо на плате экрана: у крайнего напечатана единица или подпись VSS, у противоположного — 16 или K. С этого края и начинаем счёт.

Как экран рисует буквы

BukvavkletkeA16znakov5 точек в ширину8 точек в высотуДве строки по 16 знаковКаждый знак живёт в своей клетке и собирается из точек.Рисунки букв и цифр экран знает сам — вы просто печатаете слово.
Экран разделён на 32 клетки — знакоместа. В каждой клетке 5 точек в ширину и 8 в высоту, из них и складывается буква.

Экран не умеет рисовать что угодно в любом месте, как монитор компьютера. Он разделён на клетки, и в каждую клетку помещается ровно один знак — буква, цифра или пробел.

Самое приятное: рисунки букв и цифр экран уже знает наизусть. Вам не нужно объяснять ему, как выглядит буква «A» — достаточно отправить слово, а точки он зажжёт сам.

Почему проводов так много

К светодиоду шло два провода, к кнопке — два. К экрану пойдёт двенадцать. Разберёмся, откуда столько, чтобы это не выглядело загадкой.

  • Четыре провода — питание. Контакт 1 на минус, контакт 2 на плюс, и ещё два на подсветку: контакт 15 на плюс, контакт 16 на минус.
  • Один провод — контраст. Контакт 3 идёт не на плату, а на среднюю ножку потенциометра. Им вы настраиваете, насколько тёмными выглядят буквы.
  • Один провод — на минус. Контакт 5 (он подписан RW) выбирает, читаем мы с экрана или пишем на него. Читать нам незачем, поэтому он навсегда прижат к минусу.
  • Шесть проводов — данные и команды. Вот они и идут к плате: контакты 4 и 6 говорят экрану «сейчас будет команда» и «принимай», а контакты 11–14 несут сами буквы.

А контакты 7, 8, 9, 10 остаются пустыми. Экран умеет принимать букву целиком за один раз — по восьми проводам, но тогда пришлось бы занять ещё четыре вывода платы. Поэтому он умеет и по-другому: принимать букву двумя половинками по четырём проводам. Чуть медленнее, зато экономно. Такой способ и называют четырёхпроводным режимом, и им пользуются почти все.

Собираем схему

+abcdefghiPrivet,Arduino!Urok2612345678910111213141516151015202530123451Экран воткнут в самый нижний ряд макетки — он закрывает нижние шины, поэтому питание берём с верхних.2Потенциометр 10 кОм задаёт контраст: крайние ножки на «+» и «−», средняя — на контакт 3 экрана.3С платы на шины идут два провода: гнездо 5V на «+», гнездо GND на «−».4Шесть проводов данных: контакт 4 → вывод 12, контакт 6 → вывод 11, контакты 11, 12, 13, 14 → выводы 5, 4, 3, 2.5Питание экрана: контакты 1, 5 и 16 на «−», контакты 2 и 15 на «+».Оранжевые цифры на макетке — номера контактов экрана. Контакты 7–10 в четырёхпроводном режиме не нужны.Провод соединён только там, где на нём светлая шляпка; шины он пересекает между отверстиями.
Экран садится в самый нижний ряд макетной платы и закрывает нижние шины — питание берём с верхних. Оранжевые цифры показывают, в каком столбике оказался каждый контакт экрана.

Отключите плату от USB и соберите схему по шагам. Первым делом вставьте экран: гребёнкой в самый нижний ряд макетки, корпусом вниз, чтобы он не закрывал остальные отверстия. Запомните столбик, в который попал первый контакт, — дальше считать удобно от него.

  1. Экран вставлен в нижний ряд. Провода к нему подключаются не в те же отверстия, а в любые свободные того же столбика — они соединены внутри макетки.
  2. Потенциометр: крайние ножки на «+» и «−», средняя — проводом на контакт 3 экрана. Это регулятор контраста.
  3. Питание с платы: гнездо 5V на шину «+», гнездо GND на шину «−».
  4. Питание экрана: контакты 1, 5 и 16 на «−», контакты 2 и 15 на «+». Пять коротких проводов.
  5. Шесть проводов данных: контакт 4 на вывод 12, контакт 6 на вывод 11, контакты 11, 12, 13, 14 — на выводы 5, 4, 3, 2.

Проверьте перед включением: контакт 1 экрана уходит на «−», контакт 2 — на «+», контакт 5 — тоже на «−»; средняя ножка потенциометра идёт на контакт 3, а крайние — на разные шины; шесть проводов данных сидят по порядку, без сдвига на столбик; и на макетке есть питание с платы — 5V на «+», GND на «−».

Внимательнее всего пересчитайте именно шесть проводов данных: если сдвинуть их на один столбик, экран включится, но вместо слов покажет бессмыслицу. И только теперь включайте USB.

Шаг 1. Первые слова

Экран — деталь непростая, и разговаривать с ним по проводам вручную было бы мучением. За нас это делает библиотека — готовый набор команд. Нужная библиотека называется LiquidCrystal и уже встроена в Trema IDE: ставить ничего не надо.

// Урок 26. Первые слова на экране.

#include <LiquidCrystal.h>

// В скобках — выводы платы по порядку: RS, E, D4, D5, D6, D7.
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);            // экран на 16 знаков и 2 строки
  lcd.print("Privet!");
}

void loop() {
}

Разберём по строчкам.

  • #include <LiquidCrystal.h> — подключаем библиотеку. Эта строка всегда идёт первой.
  • LiquidCrystal lcd(12, 11, 5, 4, 3, 2); — говорим, к каким выводам подключён экран. Порядок строгий: сначала контакт 4 (RS), потом контакт 6 (E), потом четыре провода данных. Слово lcd — это имя, которым мы дальше зовём экран.
  • lcd.begin(16, 2); — сообщаем размер: 16 знаков, 2 строки. Без этой строки экран останется пустым.
  • lcd.print("Privet!"); — печатаем слово. Текст обязательно в двойных кавычках.

Заметьте: всё написано в setup(), а loop() пустой. Так и надо — надпись достаточно вывести один раз, дальше она держится на экране сама.

Экран включился, но пустой? Не спешите искать ошибку в программе — почти наверняка дело в контрасте. Медленно покрутите потенциометр от края до края: где-то посередине буквы проявятся. В одном крайнем положении экран выглядит чистым, в другом — заполнен рядами тёмных квадратов.

Шаг 2. Курсор: пишем куда нужно

TremaIDEUrok26012345678910111213141501строкастолбецlcd.setCursor(4, 1) — столбец 4, строка 1Счёт и столбцов, и строк идёт с нуля: левый верхний угол — это (0, 0).
У каждой клетки свой адрес: номер столбца и номер строки. Считаются они с нуля.

Команда print пишет с того места, где сейчас стоит курсор, — как мигающая палочка в текстовом редакторе. Сразу после включения курсор в левом верхнем углу. Передвинуть его можно командой setCursor: сначала номер столбца, потом номер строки.

// Урок 26. Две строки: ставим курсор и пишем куда нужно.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);

  lcd.setCursor(0, 0);         // столбец 0, строка 0 — левый верхний угол
  lcd.print("Trema IDE");

  lcd.setCursor(4, 1);         // столбец 4, строка 1 — ниже и правее
  lcd.print("Urok 26");
}

void loop() {
}

Счёт идёт с нуля — как у ячеек массива из урока про бегущий огонёк. Столбцы нумеруются от 0 до 15, строки — 0 и 1. Значит, setCursor(4, 1) — это пятая клетка второй строки.

Шаг 3. Показываем меняющееся число

Пока на экране надпись, всё просто. А теперь пусть плата считает секунды и показывает их. И тут ждёт ловушка, о которой стоит узнать заранее.

// Урок 26. Счётчик секунд: число печатается в одно и то же место.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int seconds = 0;

void setup() {
  lcd.begin(16, 2);
  lcd.print("Sekundy:");       // подпись пишем один раз
}

void loop() {
  lcd.setCursor(0, 1);
  lcd.print(seconds);
  lcd.print("    ");           // пробелы затирают хвост прошлого числа

  seconds++;
  delay(1000);
}

Экран ничего не стирает сам. Он просто зажигает точки там, куда вы напечатали, — а всё остальное остаётся как было. Когда после числа 10 вы печатаете 9, ноль от прошлого числа никуда не денется, и на экране получится 90.

Поэтому после числа мы печатаем несколько пробелов: lcd.print(" "). Пробел — тоже знак, он затирает клетку начисто. Второй способ — команда lcd.clear(), она стирает весь экран разом. Но пользоваться ей на каждом круге не стоит: экран заметно мигает, потому что вместе с числом стирается и подпись.

Правило. Подписи, которые не меняются, печатайте один раз в setup(). В loop() обновляйте только то, что действительно изменилось.

Шаг 4. Экран считает нажатия

Соберём знакомое: кнопка из уроков про кнопки плюс экран. Кнопку ставим одной парой ножек сверху от канавки, другой снизу; сигнальный провод — на вывод 7, второй вывод кнопки — на шину «−».

Почему не вывод 2? Раньше кнопка всегда жила на выводе 2, но теперь он занят экраном — на нём висит контакт 14. Так бывает всегда, когда деталей становится много: свободные выводы приходится распределять заново.

// Урок 26. Экран считает нажатия кнопки.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int BUTTON_PIN = 7;      // вывод 2 занят экраном, кнопка переехала на 7

int count = 0;
bool wasPressed = false;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  lcd.begin(16, 2);
  lcd.print("Nazhatiy:");
  showCount();
}

void loop() {
  bool pressed = (digitalRead(BUTTON_PIN) == LOW);

  if (pressed && !wasPressed) {
    count++;
    showCount();
    delay(50);                 // пережидаем дребезг
  }

  wasPressed = pressed;
}

void showCount() {
  lcd.setCursor(0, 1);
  lcd.print(count);
  lcd.print("    ");
}

Приём тот же, что и раньше: мы ловим момент нажатия, сравнивая нынешнее состояние кнопки с прошлым. Новое здесь только одно — печать вынесена в свою функцию showCount(), и вызывается она лишь тогда, когда число изменилось. Экран не дёргается зря.

Шаг 5. Показываем датчик: число и полоска

Потенциометр в наборе один, и он теперь занят контрастом. Поэтому возьмём датчик света из пятнадцатого урока: фоторезистор идёт от шины «+» в свободный столбик, из того же столбика резистор 10 кОм уходит на «−», а от середины провод на вход A0.

// Урок 26. Датчик света: число и полоска-шкала на экране.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int SENSOR_PIN = A0;

void setup() {
  lcd.begin(16, 2);
}

void loop() {
  int value = analogRead(SENSOR_PIN);
  int blocks = map(value, 0, 1023, 0, 16);   // сколько квадратиков закрасить

  lcd.setCursor(0, 0);
  lcd.print("Svet: ");
  lcd.print(value);
  lcd.print("   ");

  lcd.setCursor(0, 1);
  for (int i = 0; i < 16; i++) {
    if (i < blocks) {
      lcd.write((byte)255);    // знак 255 — сплошной чёрный квадрат
    } else {
      lcd.print(" ");
    }
  }

  delay(100);
}

В первой строке — число, во второй — полоска из чёрных квадратиков: чем светлее в комнате, тем она длиннее. Квадратик — это знак с номером 255, он есть в памяти экрана наравне с буквами. Команда lcd.write печатает знак по его номеру, а map из урока про потенциометр переводит 0…1023 в 0…16 квадратиков.

Получился настоящий индикатор уровня — такие рисуют на регуляторах громкости. Точно так же можно показать заряд, температуру или скорость.

Шаг 6. Свой символ

Букв и цифр экран знает много, но иногда хочется своего: значок градуса, стрелку, батарейку, сердечко. Экран умеет запомнить восемь ваших рисунков.

B00000,B01010,B11111,B11111,B01110,B00100,B00000,B000001 — точка горит, 0 — точка погашена.Восемь строк —восемь чиселБуква B в началеозначает: дальшене обычное число,а рисунок из нулейи единиц.
Рисунок задаётся по точкам: восемь строк, в каждой пять знаков. Единица — точка горит, ноль — погашена.
// Урок 26. Свой символ: рисуем сердечко по точкам.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// Восемь строк по пять точек. 1 — точка горит, 0 — не горит.
byte heart[8] = {
  B00000,
  B01010,
  B11111,
  B11111,
  B01110,
  B00100,
  B00000,
  B00000
};

void setup() {
  lcd.begin(16, 2);
  lcd.createChar(0, heart);    // запоминаем рисунок под номером 0

  lcd.setCursor(0, 0);
  lcd.print("Arduino ");
  lcd.write((byte)0);          // показываем свой символ
}

void loop() {
}

Массив heart — это и есть картинка: смотрите на нули и единицы прищурившись, и увидите сердечко. Команда createChar(0, heart) отправляет рисунок в экран и запоминает его под номером 0, а lcd.write((byte)0) показывает его в том месте, где стоит курсор.

Номера ваших символов — от 0 до 7, всего восемь. Придумывать рисунок удобно на клетчатой бумаге: расчертите поле 5 на 8 и закрасьте нужные клетки.

А русские буквы?

Здесь придётся честно сказать: обычный LCD1602 русского алфавита не знает. В его памяти латинские буквы, цифры, знаки препинания и немного значков. Если напечатать русское слово, экран покажет случайный набор символов.

Поэтому в уроке мы пишем латиницей: Privet, Temperatura. Это обычная практика для таких экранов. А если очень нужны русские буквы — их можно нарисовать самим, теми самыми восемью своими символами. Правда, восьми букв хватит не на всякое слово.

Не работает? Разбираемся

  • Экран светится, но пустой — крутите потенциометр контраста. Это причина девяти неудач из десяти.
  • Видно ряд тёмных квадратов и больше ничего — контраст выкручен в другую сторону, и вдобавок программа не дошла до lcd.begin(). Проверьте, что скетч загрузился.
  • Экран совсем тёмный, подсветки нет — проверьте контакты 15 и 16: один на «+», другой на «−». И заодно контакты 1 и 2 — это питание самого экрана.
  • Вместо слов бессмыслица — перепутаны провода данных. Пересчитайте: контакт 11 на вывод 5, 12 на 4, 13 на 3, 14 на 2. Их легко сдвинуть на один столбик.
  • Экран ведёт себя странно: то пишет, то нет — проверьте контакт 5 (RW). Если он висит в воздухе, экран не понимает, писать ему или читать. Его место — на минусе.
  • Надпись мигает — вы зовёте lcd.clear() в каждом круге loop(). Печатайте только то, что изменилось.
  • Экран не реагирует вообще — выньте и вставьте его в макетку заново. Из-за длинной гребёнки он часто садится не до конца, и половина контактов повисает в воздухе.

Задания для тренировки

  • РазминкаВыведите в первой строке своё имя, а во второй — сегодняшнюю дату. Обе надписи неподвижные, значит, обе печатаются в setup().
  • ПосложнееСделайте «часы, которые идут»: пусть во второй строке каждую секунду обновляется число секунд с момента включения, а в первой стоит подпись Rabotaem:.
  • Со звёздочкой ⭐Секундомер. Кнопка запускает отсчёт, второе нажатие останавливает, третье — запускает снова с того же места. Время показывайте как минуты:секунды, например 01:07. Разбор ниже.
Показать разбор секундомера

Главная мысль: экран должен показывать время, но millis() считает от включения платы и остановить его нельзя. Значит, считать будем сами — двумя переменными. startedAt помнит, когда нажали «старт», а collected — сколько времени накопилось за прошлые запуски.

// Урок 26. Разбор задания: секундомер. Кнопка запускает и останавливает счёт.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int BUTTON_PIN = 7;

bool running = false;          // идёт ли отсчёт прямо сейчас
bool wasPressed = false;
unsigned long startedAt = 0;   // когда нажали «старт»
unsigned long collected = 0;   // сколько накопили до остановки
int lastShown = -1;            // какие секунды уже на экране

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);

  lcd.begin(16, 2);
  lcd.print("Sekundomer");
}

void loop() {
  bool pressed = (digitalRead(BUTTON_PIN) == LOW);

  if (pressed && !wasPressed) {
    if (running) {
      collected = collected + (millis() - startedAt);
      running = false;
    } else {
      startedAt = millis();
      running = true;
    }
    delay(50);
  }

  wasPressed = pressed;

  unsigned long total = collected;
  if (running) {
    total = total + (millis() - startedAt);
  }

  showTime(total);
}

void showTime(unsigned long ms) {
  int allSeconds = ms / 1000;

  if (allSeconds == lastShown) {
    return;                    // ничего не изменилось — экран не трогаем
  }
  lastShown = allSeconds;

  int minutes = allSeconds / 60;
  int seconds = allSeconds % 60;

  lcd.setCursor(0, 1);
  if (minutes < 10) {
    lcd.print("0");
  }
  lcd.print(minutes);
  lcd.print(":");
  if (seconds < 10) {
    lcd.print("0");
  }
  lcd.print(seconds);
}

Пока секундомер идёт, к накопленному прибавляем время с момента старта. Когда его останавливают, это время переезжает в collected насовсем.

Вторая хитрость — в функции showTime. Она сравнивает секунды с теми, что уже на экране, и если ничего не изменилось, сразу выходит по return. Иначе экран обновлялся бы тысячи раз в секунду и заметно дрожал.

И мелочь, которая делает вид аккуратным: если число меньше десяти, перед ним печатается ноль. Иначе вместо 01:07 получилось бы 1:7.

Что мы узнали

  • LCD1602 — экран на две строки по 16 знаков; каждый знак собирается из точек в своей клетке.
  • Экран подключают двенадцатью проводами: питание, подсветка, контраст через потенциометр и шесть проводов данных.
  • Работать с ним помогает встроенная библиотека LiquidCrystal: команды begin, print, setCursor, clear.
  • Столбцы и строки считаются с нуля, а старые знаки нужно затирать пробелами.
  • Восемь своих символов можно нарисовать по точкам командой createChar.

В следующем уроке подключим датчик DHT11 — он умеет измерять температуру и влажность. А показывать его цифры будет как раз наш новый экран.

Частые вопросы

Как подключить экран LCD1602 к Arduino?

Экран вставляют в макетную плату и соединяют двенадцатью проводами: питание и подсветка идут на шины, контакт 3 — на среднюю ножку потенциометра 10 кОм, а шесть проводов данных — на выводы платы 12, 11, 5, 4, 3 и 2.

Почему экран светится, но ничего не показывает?

Чаще всего дело в контрасте: покрутите потенциометр от края до края, буквы проявятся где-то посередине. Если не помогло, проверьте контакт 5 — он должен быть соединён с минусом.

Зачем экрану потенциометр?

Он задаёт контраст. Без него экран показывает либо чистое поле, либо ряды тёмных квадратов. Крайние ножки потенциометра идут на плюс и минус, средняя — на контакт 3 экрана.

Какая библиотека нужна для LCD1602?

LiquidCrystal — она уже встроена в Trema IDE, ставить ничего не нужно. Достаточно строки include в начале программы и одной строки с перечислением выводов.

Можно ли выводить на LCD1602 русские буквы?

Обычный экран знает только латиницу, цифры и знаки препинания, поэтому надписи пишут латинскими буквами. Отдельные русские буквы можно нарисовать самому — экран запоминает восемь своих символов.

← Все уроки курса