Подключение I2C LCD к Arduino

Подключение I2C LCD к Arduino

Если вы когда-либо пробовали подключить LCD-дисплей к Arduino, вы, вероятно, заметили, что это требует довольно много выводов Arduino. Даже при использовании 4-битного режима нужно семь подключений — что занимает около половины доступных цифровых выводов I/O Arduino.

Лучшее решение — использовать I2C LCD-дисплей. Для него нужны всего два вывода, которые даже не входят в набор обычных цифровых выводов I/O. Более того, эти выводы могут совместно использоваться с другими I2C-устройствами. Это значительно упрощает подключение и сохраняет ценные выводы для подключения других датчиков или компонентов в ваших проектах.

Обзор оборудования

Типичный I2C LCD-дисплей состоит из двух основных частей: символьного LCD-дисплея на базе HD44780 и I2C LCD-адаптера. Давайте рассмотрим оба компонента подробнее.

Символьный LCD-дисплей

Символьные LCD-дисплеи специально разработаны для отображения букв, цифр и символов. Например, символьный LCD 16×2 может показывать 16 символов в каждой строке, всего две строки.

Подключение I2C LCD к Arduino

Если вы внимательно посмотрите на экран, то заметите маленькие прямоугольные блоки для каждой позиции символа. Внутри каждого из этих прямоугольников находится сетка 5×8 крошечных точек или пикселей. Эти пиксели светятся в различных паттернах, формируя различные буквы, цифры или символы.

Для более подробной информации о символьных LCD-дисплеях ознакомьтесь с нашим подробным руководством.

I2C LCD-адаптер

Ключевой компонент этого адаптера — 8-битная микросхема расширения ввода-вывода PCF8574. Эта микросхема преобразует данные I2C от Arduino в параллельные данные, необходимые для работы LCD-дисплея.

Подключение I2C LCD к Arduino

Плата адаптера также включает небольшой подстроечный потенциометр, позволяющий точно регулировать контрастность дисплея.

Подключение I2C LCD к Arduino

Вы заметите перемычку на плате, которая подаёт питание на подсветку. Если вы хотите управлять яркостью подсветки, просто снимите эту перемычку и подключите внешний источник напряжения к выводу с маркировкой „LED“.

I2C-адрес LCD

Если у вас несколько устройств на одной шине I2C, может потребоваться установить другой I2C-адрес для LCD-адаптера, чтобы избежать конфликтов с другими I2C-устройствами.

Для этого адаптер оснащён тремя паяными перемычками/площадками (обозначенными A0, A1 и A2). Для одного LCD их можно оставить без изменений; однако при подключении нескольких I2C-устройств или LCD необходимо убедиться, что каждое имеет уникальный адрес, изменяя эти перемычки. Адрес можно изменить, замкнув перемычку небольшой каплей припоя.

Подключение I2C LCD к Arduino

Важно знать, что разные компании, такие как Texas Instruments и NXP Semiconductors, производят одну и ту же микросхему PCF8574. I2C-адрес вашего LCD зависит от того, какая компания произвела микросхему.

Если ваш LCD имеет микросхему PCF8574 от Texas Instruments:

Согласно техническому описанию Texas Instruments, три бита выбора адреса (A0, A1 и A2) расположены в конце 7-битного регистра I2C-адреса.

Подключение I2C LCD к Arduino

Поскольку есть три входа адреса, которые могут быть HIGH или LOW, существует восемь возможных комбинаций (2^3 = 8) адресов.

Все три входа адреса подтянуты к HIGH по умолчанию с помощью встроенных подтягивающих резисторов. Это даёт PCF8574 I2C-адрес по умолчанию 0x27.

Когда вы замыкаете паяную перемычку, вы подтягиваете этот вход адреса к LOW. Если замкнуть все три перемычки, адрес изменится на 0x20. Таким образом, диапазон возможных адресов — от 0x20 до 0x27.

Вы можете установить различные I2C-адреса согласно этой таблице:

Подключение I2C LCD к Arduino

Если ваш LCD имеет микросхему PCF8574 от NXP:

Согласно техническому описанию NXP Semiconductors, три бита выбора адреса (A0, A1 и A2) также расположены в конце 7-битного регистра I2C-адреса. Однако остальные биты в регистре адреса отличаются от микросхемы Texas Instruments.

Подключение I2C LCD к Arduino

Как и в случае с микросхемой Texas Instruments, существует восемь возможных комбинаций адресов, поскольку три входа могут быть HIGH или LOW.

Все три входа адреса подтянуты к HIGH по умолчанию с помощью встроенных подтягивающих резисторов. Это даёт PCF8574 I2C-адрес по умолчанию 0x3F.

Когда вы замыкаете паяную перемычку, вы подтягиваете этот вход к LOW. Если замкнуть все три перемычки, адрес изменится на 0x38. Таким образом, диапазон возможных адресов — от 0x38 до 0x3F.

Вы можете установить различные I2C-адреса согласно этой таблице:

Подключение I2C LCD к Arduino

Итак, I2C-адрес вашего LCD, скорее всего, 0x27 или 0x3F. Если вы не уверены, какой адрес у вашего LCD, не волнуйтесь! Есть простой способ узнать это, о котором вы прочитаете далее в этом руководстве.

Распиновка I2C LCD-дисплея

I2C LCD-дисплей имеет всего четыре вывода. Вот распиновка:

Подключение I2C LCD к Arduino

GND — это вывод заземления.

VCC — это вывод питания. Подключите его к выходу 5V Arduino или внешнему источнику питания 5V.

SDA — это вывод данных I2C.

SCL — это вывод тактирования I2C.

Схема подключения I2C LCD-дисплея к Arduino

Подключение I2C LCD значительно проще, чем подключение стандартного LCD. Нужно подключить всего четыре вывода вместо множества.

Сначала подключите вывод VCC к выходу 5V Arduino, а вывод GND — к земле Arduino.

Далее нужно подключить выводы I2C. Важно знать, что разные платы Arduino имеют разные выводы I2C, и они должны быть подключены правильно. На платах Arduino с разводкой R3 выводы SDA (линия данных) и SCL (линия тактирования) также расположены на штыревых разъёмах рядом с выводом AREF. Однако внутренне они аналогичны выводам A4 (SDA) и A5 (SCL).

В таблице ниже показаны все необходимые подключения:

I2C LCDArduino
VCC5V
GNDGND
SCLSCL or A5
SDASDA or A4

Эта схема показывает, как именно подключить всё:

Подключение I2C LCD к Arduino

Регулировка контрастности LCD

После подключения LCD к Arduino необходимо отрегулировать контрастность LCD-дисплея. Найдите маленький синий подстроечный потенциометр на плате I2C-адаптера — он контролирует контрастность LCD.

Теперь подайте питание на Arduino. Вы должны увидеть, как сразу загорится подсветка. Возьмите маленькую отвёртку и аккуратно поверните ручку потенциометра. По мере регулировки вы увидите, как появляется первый ряд прямоугольников на экране. Эти прямоугольники — места, где будут отображаться символы. Если вы чётко видите эти прямоугольники — поздравляем: ваш LCD работает идеально и готов к отображению текста!

Подключение I2C LCD к Arduino

Определение I2C-адреса

Прежде чем перейти к примеру кода, вам нужно знать I2C-адрес вашего LCD, чтобы правильно обмениваться с ним данными. Как упоминалось ранее, I2C-адрес вашего LCD, вероятно, 0x27 или 0x3F. Вы можете найти этот адрес на наклейке, прилагаемой к LCD, или в информации о продукте. Но не волнуйтесь, если нигде не можете найти эту информацию! Есть простое решение — вы можете запустить простой скетч I2C-сканера, который автоматически определит правильный адрес. Вот как:

Вы можете найти этот скетч, нажав File > Examples > Wire > i2c_scanner в меню Arduino IDE.

Подключение I2C LCD к Arduino

Загрузите скетч i2c_scanner в Arduino IDE.

#include <Wire.h>

void setup() {
  Wire.begin();

  Serial.begin(9600);
  while (!Serial); // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  int nDevices = 0;

  Serial.println("Scanning...");

  for (byte address = 1; address < 127; ++address) {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    byte error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.print(address, HEX);
      Serial.println("  !");

      ++nDevices;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println("done\n");
  }
  delay(5000); // Wait 5 seconds for next scan
}

После загрузки скетча в Arduino откройте монитор последовательного порта и установите скорость 9600 бод. Через несколько мгновений вы должны увидеть I2C-адрес вашего LCD-дисплея на экране.

Подключение I2C LCD к Arduino

Обязательно запишите этот адрес. Он понадобится при работе с LCD в последующих примерах.

Установка библиотеки

Для управления I2C LCD мы будем использовать библиотеку Arduino LiquidCrystal_I2C. Эта библиотека значительно упрощает работу с LCD, поскольку обрабатывает всю сложную I2C-коммуникацию в фоновом режиме. Существует несколько версий этой библиотеки, но одна из самых надёжных — версия, созданная Frank de Brabander.

Для установки библиотеки:

  1. Сначала откройте Arduino IDE. Затем нажмите на значок Менеджер библиотек на левой боковой панели.

  2. Введите «liquidcrystal» в поле поиска для фильтрации результатов.

  3. Найдите библиотеку «LiquidCrystal I2C library» от Frank de Brabander.

  4. Нажмите кнопку Install для добавления её в Arduino IDE.

Подключение I2C LCD к Arduino

Базовый скетч Arduino — Hello World

С подключённым оборудованием и установленной библиотекой мы можем написать простой скетч Arduino для вывода текста на LCD. В этом примере мы выведем „Hello World!“ на первую строку LCD и „LCD Tutorial“ на вторую строку.

Перед загрузкой скетча нужно внести два важных изменения. Вы должны ввести правильный 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() {
}

После загрузки кода в Arduino вы должны увидеть на экране следующее:

Подключение I2C LCD к Arduino

Объяснение кода:

Скетч начинается с подключения библиотеки 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() в цикле для перемещения текста по экрану.

Пример кода Arduino

Скетч ниже показывает, как непрерывно прокручивать сообщение влево:

#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
}

Когда вы загрузите этот код в Arduino, LCD отобразит что-то подобное:

Подключение I2C LCD к Arduino

Объяснение кода:

В этом примере мы выводим сообщение длиной 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 в двоичной системе) для указания, какие пиксели должны быть включены (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 позволяет использовать только восемь пользовательских символов одновременно. Но не волнуйтесь — восемь различных символов — это достаточно, чтобы сделать ваш проект уникальным и интересным!

Пример кода Arduino

Скетч ниже показывает, как именно отображать пользовательские символы на 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);
}

Когда вы загрузите этот код в Arduino, LCD отобразит что-то подобное:

Подключение I2C LCD к Arduino

Попробуйте и поэкспериментируйте с созданием собственных уникальных символов!

Объяснение кода:

После подключения библиотеки 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 (указывающее, какой из восьми доступных слотов памяти использовать) и имя массива с дизайном символа.

Код ниже сохраняет дизайн сердца в слоте 0 памяти CGRAM LCD.

// create a new character
lcd.createChar(0, Heart);

Наконец, в секции loop мы отображаем наш пользовательский символ с помощью функции write(). Мы указываем, какой символ отобразить, передавая номер слота памяти:

// byte(0) represents Heart character.
lcd.write(byte(0));