Добавить в избранное

LCD 1602 с Arduino: подключение по I2C и вывод текста

Чтение ≈ 4 мин

Символьный дисплей LCD1602 на Arduino: I2C-модуль вместо шести проводов, библиотека LiquidCrystal_I2C, вывод текста и чисел, кастомные символы, русские буквы и типичные проблемы адреса и контраста.

LCD1602: два способа подключения

Символьный дисплей 1602 (16 символов × 2 строки) — классика для вывода данных. Изначально у него 16 ног и подключение идёт параллельной шиной: 6-8 проводов данных + управление = почти все пины Arduino заняты.

Решение — I2C-модуль PCF8574 на обратной стороне: вместо десятка проводов всего четыре — VCC, GND, SDA, SCL. Купите дисплей с припаянным модулем — разницы в цене почти нет.

Arduino A4 (SDA) ── SDA
Arduino A5 (SCL) ── SCL
5V ── VCC
GND ── GND

Библиотека и первый текст

Ставим «LiquidCrystal I2C» (автор marcoschwartz или Frank de Brabander — обе работают):

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);   // адрес 0x27 или 0x3F — см. ниже

void setup() {
    lcd.init();
    lcd.backlight();
    lcd.setCursor(0, 0);
    lcd.print("Hello, LCD!");
    lcd.setCursor(0, 1);
    lcd.print("строка 2");
}

Адрес модуля бывает 0x27 или 0x3F — если дисплей не отвечает, попробуйте другой. Для поиска есть скетч I2C-сканера.

Курсор и управление

lcd.setCursor(5, 1);    // колонка 5, строка 1 (нумерация с 0)
lcd.print("x");

lcd.clear();            // очистка всего
lcd.home();             // курсор в 0,0
lcd.cursor();           // показать курсор
lcd.noCursor();         // скрыть
lcd.blink();            // мигающий курсор
lcd.noBlink();
lcd.noBacklight();      // выключить подсветку
lcd.display(); / lcd.noDisplay();  // экран вкл/выкл без очистки

Печать данных: lcd.print принимает строки, числа, float с заданием знаков:

float t = 23.456;
lcd.print(t, 1);       // "23.5" — один знак после точки
lcd.print(42);         // целые
lcd.print("text");

Свои символы и русские буквы

У LCD1602 до 8 кастомных символов в памяти CGRAM (коды 0–7). Каждый — битовая маска 5×8:

byte bell[8] = {
    0b00100,
    0b01110,
    0b01110,
    0b01110,
    0b11111,
    0b00000,
    0b00100,
    0b00000
};

void setup() {
    lcd.createChar(0, bell);   // символ 0
    lcd.write(0);              // напечатать символ 0
}

Русские буквы: знакогенератор дисплея содержит кириллицу (HD44780 A00-прошивки), но кодировка не совпадает с UTF-8 — нужна перекодировка. Готовые библиотеки вроде LiquidCrystal_I2C с поддержкой кириллицы или lcdRus решают это; в простых проектах пишут транслитом или английским.

Проект: вывод данных DHT22

Типичное применение — показания датчика:

#include <DHT.h>
#include <LiquidCrystal_I2C.h>

DHT dht(2, DHT22);
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
    dht.begin();
    lcd.init();
    lcd.backlight();
}

void loop() {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    if (!isnan(t) && !isnan(h)) {
        lcd.setCursor(0, 0);
        lcd.print("Temp: " + String(t, 1) + "C  ");
        lcd.setCursor(0, 1);
        lcd.print("Hum:  " + String(h, 0) + "%  ");
    }
    delay(2000);
}

Пробелы в конце строки затирают старые длинные значения — иначе «25» на «8» оставит «8 ».

Поиск адреса I2C

Не знаете адрес модуля — сканируйте шину:

#include <Wire.h>
void setup() {
    Wire.begin();
    Serial.begin(9600);
    for (byte i = 8; i < 120; i++) {
        Wire.beginTransmission(i);
        if (Wire.endTransmission() == 0) {
            Serial.print("найден: 0x"); Serial.println(i, HEX);
        }
    }
}
void loop() {}

Типичные проблемы

  • Пустые квадраты вместо текста: крутите потенциометр контраста на I2C-модуле (маленький синий винтик).
  • Ничего не горит: проверьте питание, адрес (0x27/0x3F) и не перепутаны ли SDA/SCL.
  • Крякозябры: кириллица требует перекодировки или английский текст.
  • Дисплей работает, но текст не виден: забыт lcd.backlight() или контраст на минимуме.
  • Мусор при перезаписи: строки разной длины — добивайте пробелами или lcd.clear().

Итог

LCD1602 через I2C — это 4 провода и lcd.print. Держите в уме три момента: адрес 0x27 или 0x3F, потенциометр контраста для «чёрных квадратов», перекодировка для кириллицы. Дальше — меню на кнопках, вывод с датчиков, простые анимации кастомными символами.

Полный пример: живое обновление показаний

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);   // адрес 0x27, 16x2

void setup() {
    lcd.init();
    lcd.backlight();
    lcd.setCursor(0, 0);
    lcd.print("Smartep");
}

void loop() {
    float t = dht.readTemperature();

    lcd.setCursor(0, 1);
    lcd.print("T=");
    lcd.print(t, 1);
    lcd.print((char)223);   // символ градуса
    lcd.print("C   ");      // пробелы — стирают хвост старого значения

    delay(2000);
}

Важно: lcd.print не стирает строку — печатайте пробелы хвостом или используйте lcd.clear() (мигает). Лучше — всегда писать значения фиксированной ширины.

Вывод «температура → шкала»

Вторая строка — шкала из блоков:

int bars = map(t * 10, 0, 400, 0, 16);   // 0..16 блоков при 0..40°C
lcd.setCursor(0, 1);
for (int i = 0; i < 16; ++i)
    lcd.write(i < bars ? 0xFF : ' ');

Создание своего символа

LCD1602 поддерживает 8 пользовательских символов — 5×8 пикселей каждый:

byte deg[8] = {0b01100, 0b10010, 0b10010, 0b01100,
               0b00000, 0b00000, 0b00000, 0b00000};

lcd.createChar(0, deg);
lcd.write(0);   // выводит символ градуса

Онлайн-генераторы символов LCD (вроде maxpromer.github.io/LCD-Character-Creator) рисуют символы мышкой и выдают готовый массив.

Бегущая строка

lcd.setCursor(0, 0);
lcd.print("  ");
lcd.scrollDisplayLeft();    // сдвиг на одну позицию
delay(300);

В цикле — классическая «бегущая строка» с текстом больше 16 символов.

Управление подсветкой и контрастом

lcd.backlight() / lcd.noBacklight() — программное управление. Контраст — подстроечный резистор на модуле I2C. При подключении без I2C-расширителя — потенциометр на ногу V0 дисплея.

Частые проблемы и решения

  • Пустые квадраты: дисплей получает питание, но данных нет — неверный I2C-адрес (проверьте сканером), перепутаны SDA/SCL.
  • Иероглифы: написали быстрее чем дисплей успел — добавьте delay после init или обновляйте реже.
  • Мигает/тускло: просадка питания — отдельный 5V для дисплея, конденсатор.
  • Печать поверх старого: print не стирает — печатайте пробелы хвостом.

Полный пример: меню на LCD

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
const char* items[] = {"Настройки", "Яркость", "Таймер", "Выход"};
int pos = 0;

void show() {
    lcd.clear();
    lcd.print(">");
    lcd.print(items[pos]);
    lcd.setCursor(0, 1);
    lcd.print(items[(pos + 1) % 4]);
}

void loop() {
    if (encoderDelta()) {
        pos = (pos + encoderDelta() + 4) % 4;
        show();
    }
    if (buttonPressed()) {
        // выбор пункта
    }
}

Создание своего символа

byte deg[8] = {0b01100, 0b10010, 0b10010, 0b01100,
               0b00000, 0b00000, 0b00000, 0b00000};
lcd.createChar(0, deg);
lcd.write(0);   // выводит символ градуса

Альтернативы

  • OLED SSD1306 — 128×64, графика, I2C, дороже.
  • TFT ILI9341 — цветной, 240×320, SPI, ещё дороже.
  • 7-сегментный — только цифры, ярче, дешевле.
Поделиться
Понравился материал?

Комментарии

Добавить комментарий