Подключение LCD экрана LCM1602 с I2C к Arduino. LCD I2C модуль подключение к Arduino Подключение дисплея 1602 i2c

В этой статье расскажу, как использовать интерфейсный модуль I2C для управления LCD дисплеем (2×16 / 20х4) с помощью Arduino. Данный модуль позволяет уменьшить количество используемых выводов контроллера, вместо 8 или 4-битного соединения, требуется только 2 вывода (SDA и SCL).

Технические параметры

Поддержка дисплеев: LCD 16×02 / 20×04
Дополнительно: регулировка контрастности
Напряжение питания. 5В
Интерфейс: I2C
Габариты: 54мм x 19мм x 15мм

Общие сведения интерфейсного модуля I2C

Поскольку количество контактов на контроллерах Arduino ограничено и часто при использовании различных датчиков и модулей они заканчиваются, появляется необходимость в их экономии, для этих случай разработан этот модуль, с его помощью можно реализовать передачу по двум контактам (SDA и SCL).

Теперь немного о самом модуле, построен он на микросхеме PCF8574T. Резисторы R8 (4.7кОм) и R9 (4.7кОм) необходимы для подтяжки линий SDA и SCL, в идеале при подключении двух и более устройств по шине I2C необходимо использовать подтяжку только на одном устройств, позже напишу почему. На плате предусмотрены три перемычки (по схеме видно что линии A0, A1, A2 подтянуты к питанию через резисторы R4, R5, R6), необходимы они для смены адресации устройства, всего их 8 вариантов. Изменение адресации дает нам возможность подключения до восьми устройств по шине IC2 c микросхемой PCF8574T, варианты адресов показаны на рисунке (по умолчанию адрес устройства 0x27). Так же модуль оснащен потенциометром R11 с его помощью можно изменить контрастность LCD дисплея.

Для соединения на модуле расположено три группы контактов:

Первая группа:
SCL: линия тактирования (Serial CLock)
SDA: линия данных (Serial Dфta)
VCC: «+» питание
GND: «-» питание

Вторая группа:
VSS: «-» питание
VDD: «+» питание
VO: Вывод управления контрастом
RS: Выбор регистра
RW: Чтение/запись (режим записи при соединении с землей)
E: Еnable (строб по спаду)
DB0-DB3: Младшие биты интерфейса
DB4-DB7: Старшие биты интерфейса
A: «+» питания подсветки
K: «-» питания подсветки

Третья группа: (по умолчанию установлена перемычка)
VCC:
A от LCD:

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

Необходимые детали:
Arduino UNO R3 x 1 шт.
LCD-дисплей 1602A (2×16, 5V, Синий) x 1 шт.
Интерфейсный модуль I2C, IIC, TWI для LCD x 1 шт.
Провод DuPont, 2,54 мм, 20 см, F-M (Female — Male) x 1 шт.
Кабель USB 2.0 A-B x 1 шт.

Подключение :
Первым делом, припаиваем модуль I2C к LCD дисплею, затем необходимо подключить дисплей к Arduino UNO. Для этого воспользуемся проводками DuPont, подключение осуществляем по таблице ниже.

Для наглядности, приведу еще одну схему.

Для этого эксперимента необходимо скачать и установить библиотеку «LiquidCrystal_I2C». Затем скопируйте и вставьте этот пример кода в окно программы IDE Arduino и загрузите в контроллер.

/* Тестировалось на Arduino IDE 1.6.11 Дата тестирования 15.09.2016г. */ #include #include LiquidCrystal_I2C lcd(0x27,16,2); // Задаем адрес и размер дисплея void setup() { lcd.init(); // Инициализация lcd lcd.backlight(); // Включаем подсветку lcd.setCursor(0,0); // Устанавливаем курсор в начало 1 строки lcd.print("Hello, world"); // Выводим текст lcd.setCursor(0,1); // Устанавливаем курсор в начало 2 строки lcd.print("www.robotchip.ru"); // Выводим текст } void loop() { }

Скачать программу

Если Вы правильно все сделали, но никаких символов на дисплее нет, попробуйте увеличить контрастность потенциометром.


Ссылки
Скачать библиотеку LiquidCrystal_I2C
Документация на микросхему PCF8574T
Документация к LCD1602A

Купить на Aliexpress

Заполучил я тут от хорошего магазина Чип Резистор очередной девайс для изучения и применения в полезных устройствах. Сей девайс оказался заточен для управления ЖК дисплеем под управлением контроллера HD44780, в 4-х битном режиме. Для этой цели на плате установлена микросхема , которая является преобразователем шины I2C в параллельный 8 битный порт.

Плата разведена таким образом, чтобы ее можно было сразу скрестить с ЖК дисплеем. На вход подается питание и линии I2C. На плате сразу установлены подтягивающие резисторы на линиях SCL и SDA, потенциометр для регулировки контрастности и питание самого дисплея.

Джампер справа включает/отключает подсветку. Далее вооружившись тестером была составлена следующая табличка. После изучения модуля было выявлено что P3 управляет подсветкой. Если джампер установлен, то 1 включает подсветку, а 0 выключает. При снятом джампере подсветка всегда выключена. Далее было принято решение дополнить библиотеку axlib функциями для работы с шиной I2C(программная реализация) и функциями для управления микросхемой PCF8574. В двух словах как работает модуль. Для того чтобы вывести параллельно байт, для этого нужно послать в шину I2C адрес микросхемы (по умолчанию он равен 0x4E. Так же можно менять адрес методом впаивания перемычек на плате и меняя значение трех младших разрядов адреса), затем после получения ACK посылается байт данных. После того как микросхема отвечает ACK, байт появляется на параллельном порту микросхемы. Для управления ЖК дисплеем я взял функции из библиотеки axlib и немного переделал их для работы с шиной I2C. #include #include #include #include #define ADD 0x4E // Адрес микросхемы /* LCD Микросхема RS P0 RW P1 EN P2 D4 P4 D5 P5 D6 P6 D7 P7 На ножке P3 подключени подсветка. 1 вкл, 0 выкл. */ // Вывод данных com |= 0x04; // Е в единицу pcf8574_byte_out(com, ADD); // Вывод данных com &= 0xFB; // Е в ноль pcf8574_byte_out(com, ADD); // Вывод данных } void init(void) { _delay_ms(30); com(0x30); _delay_us(40); com(0x30); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x30); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x20); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x20); // Установка параметров com(0x80); // Установка параметров com(0x00); // Выключаем дисплей com(0x80); // Выключаем дисплей com(0x00); // Очищаем дисплей com(0x10); // Очищаем дисплей com(0x00); com(0x60); // Устанавливаем режим ввода данных com(0x00); com(0xC0); // Включаем дисплей с выбранным курсором } void char_out(BYTE data) { BYTE data_h = ((data & 0xF0) + 0x09); BYTE data_l = ((data // Передача старших 4 бит data_h |= 0x04; pcf8574_byte_out(data_h, ADD); // Передача старших 4 бит // Передача старших 4 бит // Передача младших 4 бит // Передача младших 4 бит // Передача младших 4 бит } void str_out(BYTE *str) { while((*str) != "\0") { char_out(*str); str++; } } int main(void) { init(); str_out("ЁPҐBET MҐP!"); while(1) { } } Собственно что здесь происходит. Сначала подключаем библиотеки для I2C и для PCF8574. Про I2C я писал уже , поэтому распинаться еще раз на буду, а вот что в PCF8574.h я расскажу. В состав библиотеки вошли всего три функции.
BYTE pcf8574_test(BYTE add) { BYTE ask = ACK; add &= 0xFE; i2c_start(); ask = i2c_send_byte(add); i2c_stop(); return ask; } Первая функция была написана для проверки наличия устройства на шине. В принципе ее можно применять для поиска любого устройства находящегося на шине. Функция принимает адрес искомого устройства и если оно отвечает, то возвращает ноль. Если устройство с таким адресом нет на шине, то вернет единицу.
BYTE pcf8574_byte_out(BYTE data, BYTE add) { BYTE ask = ACK; add &= 0xFE; i2c_start(); ask = i2c_send_byte(add); if(!ask) ask = i2c_send_byte(data); i2c_stop(); return ask; } Эта функция уже заточена чисто под данную микросхему. В качестве аргументов ей передаются байт для передачи в шину и адрес микросхемы. Функция сначала запросит микросхему по адресу, а затем пошлет байт. Если микросхема получила байт и ответила ACK, то функция закончит работу с микросхемой и вернет ноль как удачная посылка байта. А микросхема в это время выведет этот байт в свой параллельный порт. Иначе получим NACK и вернем единицу, передача провалилась.
BYTE pcf8574_str_out(BYTE *data, BYTE col, BYTE add) { BYTE ask = ACK; add &= 0xFE; i2c_start(); ask = i2c_send_byte(add); for(BYTE i=0; i Эта функция создана для эксперимента. Принимает указатель на массив однобайтовых данных, количество этих байт и адрес микросхемы. Собственно попытка передать все данные одной сессией, а не одним байтом за сессию. Функция работает, но так для ЖК дисплея и не подошла. А теперь давайте вернемся к основной программе. После подключения библиотек, прописываем адрес микросхемы. Далее создаем три функции по аналогии с lcd.h. Отличие лишь в принципе передачи данных.
void com(BYTE com) { com |= 0x08; // Р3 в единицу, дабы горела подсветка pcf8574_byte_out(com, ADD); // Вывод данных com |= 0x04; // Е в единицу pcf8574_byte_out(com, ADD); // Вывод данных com &= 0xFB; // Е в ноль pcf8574_byte_out(com, ADD); // Вывод данных } Эта функция передает только команды дисплею. Отсюда появилась первая строка с логическим сложением команды с 0х08. Эта бяка нужна из-за того что мы передаем байт не прямо в порт ЖК дисплея, а через наш ретранслятор. То есть если мы подали байт, а потом нам нужно вывести только один бит, то соизвольте к предыдущему байту присвоит нужный бит и уже его снова отправить в порт. Вот такая заморочка. Сложение с 0х08 необходимо для постоянного удержания единицы на третьем разряде. Помните про подсветку? Вот именно это сложение и включает подсветку. После вызываем функцию передачи байта в шину. О ней написано выше. Затем передаем байт по шине в микросхему. Далее следует выставить в единицу Е, чем собственно занимается логическое сложение байта с 0х04. После обнуление Е. Таким образом можно послать любую команду дисплею лишь передав в качестве аргумента саму команду. void init(void) { _delay_ms(30); // Пауза после подачи питания com(0x30); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x30); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x30); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x20); // Переход в 4-х битный режим _delay_us(40); // Задержка для выполнения команды com(0x20); // Установка параметров com(0x80); // Установка параметров com(0x00); // Выключаем дисплей com(0x80); // Выключаем дисплей com(0x00); // Очищаем дисплей com(0x10); // Очищаем дисплей com(0x00); // Устанавливаем режим ввода данных com(0x60); // Устанавливаем режим ввода данных com(0x00); // Включаем дисплей с выбранным курсором com(0xC0); // Включаем дисплей с выбранным курсором } Эта функция занимается лишь инициализацией дисплея. Последовательность команд взята из даташита на ЖК дисплей. void char_out(BYTE data) { BYTE data_h = ((data & 0xF0) + 0x09); BYTE data_l = ((data // Передача старших 4 бит data_h |= 0x04; pcf8574_byte_out(data_h, ADD); // Передача старших 4 бит data_h &= 0xF9; pcf8574_byte_out(data_h, ADD); // Передача старших 4 бит pcf8574_byte_out(data_l, ADD); // Передача младших 4 бит data_l |= 0x04; pcf8574_byte_out(data_l, ADD); // Передача младших 4 бит data_l &= 0xF9; pcf8574_byte_out(data_l, ADD); // Передача младших 4 бит } Эта функция передает данные ЖК дисплею. Выполняется так же как и команды за исключением того, что передача байта идет сначала старшим полубайтом, а затем младшим. А остальное тоже самое. void str_out(BYTE *str) { while((*str) != "\0") { char_out(*str); str++; } } Ну, а эта функция чисто для передачи строки дисплею. Собственно к нашей теме она никакого отношения не имеет.

Проект для AtmelStudio 6.2 

Грамотный 01.08.15 17:11

Запятая пропущена. Правильно: "ПРИВЕТ, МИР!" И сей девайс заточен не только для HD44780. Подтягивающие резисторы ставятся со стороны мастера. Согласно спецификации, запись данных в контроллер LCD идет по спаду Е. Отсюда первая же функция упрощается: void com(BYTE com) { com |= 0x08; // подсветка pcf8574_byte_out(com | 0x04, ADD);// Вывод данных pcf8574_byte_out(com, ADD); // Е в ноль } Да и остальные тоже существенно меньше могут быть. Например, void char_out(BYTE data) будет всего из двух вызовов, и уж тем более без дополнительных переменных. Инициализация LCD выполнена с нарушениями спецификации таймингов.

Алексей 02.08.15 19:11

Из-за отсутствия запятой, дисплей не пострадает. Сей девайc как раз заточен именно под дисплеи с таким, либо аналогичным контроллером. А вот именно микросхема действительно простой расширитель порта. По поводу Е я согласен. Дополнительные переменные нужны. Если передать функции аргумент с выполнением неких действий с логикой, могут возникнуть глюки. Уже с таким сталкивался. Инициализация выполняется без нарушений тайменгов. В документации сказано, что между командами ставиться пауза 40 мкс. Из-за того что передача идет по шине i2c, а та в свою очередь программная и медленная, то периоды выполняются с лихвой. Если все же Вам не лень, то напишите свой вариант и пришлите мне. Я его опубликую. В конце концов данный сайт предназначен на любительскую аудиторию и каждый кто хочет может высказать свое мнение и видение на жизнь МК.

Алексей 06.08.15 09:14

Добавлены тайменги при инициализации дисплея по замечанию уважаемого "Грамотного"

Дмитрий 14.06.16 21:57

Здравствуйте Алексей.Можно в генератор кода добавить библиотеку для работы с PCF8574.

Алексей 14.06.16 22:32

Я подумаю.))

ruslan 21.12.16 19:54
Алексей 21.12.16 21:53

О да. Особенно код на асме. Ардуинщики оценят по полной)))

Пы.сы.
Даже если не взирать на асм, то там прога написана под PIC контроллер. Для AVRщиков это "очень" полезная информация? особенно начинающим))) Я ничего не имею против PIC, но даже асм у PIC и AVR разный. А по поводу подробностей работы ЖК дисплея, то можно глянуть ))) Правда я ее еще писал под CVAVR но все команды разобраны и разложены по полочкам. Но в любом случае решайте сами где понятнее написано))) Автор пишет, читатель выбирает.

GeK 04.01.17 12:52

"I2C адрес микросхемы (по умолчанию он равен 0x4E"

Старшие 4 бита адреса фиксированы,
префикс У PCF8574 равен 0100, а у PCF8574A - 0111
Младшие 3 бита зависят от состояния входов микросхемы A2-A0. По умолчанию все 3 перемычки разомкнуты, соответственно адрес микросхемы принимает значение 0111111.
// A2 A1 A0 PCF8574 PCF8574A
// 1 1 1 0x20 0x38
// 1 1 0 0x21 0x39
// 1 0 1 0x22 0x3A
// 1 0 0 0x23 0x3B
// 0 1 1 0x24 0x3C
// 0 1 0 0x25 0x3D
// 0 0 1 0x26 0x3E
// 0 0 0 0x27 0x3F

Алексей 04.01.17 14:27

Что-то вы перепутали.
Выписка из документации на микросхему

0b01001110 это 0x4E
Так что тут все верно. А если нужно сменить адрес, то всего лишь нужно его поменять в дефайне.

Юрий 14.12.17 21:26

Доброго времени суток! А можно еще код функции lcdgotoxy и lcdclear для работы с переходником на PCF8574.

Александр 20.05.18 18:14

Доброго времени суток! как вы выводите русский текст.

Алексей 20.05.18 23:04

Это отечественный дисплей от фирмы МЭЛТ. У него в памяти зашита кириллица.

Александр 21.05.18 04:55

Доброго времени суток! Я пиши как у вас в Проект для AtmelStudio 6.2 " ЁPҐBET MҐP!" то выводит нормально
а если пиши "ПРИВЕТ МИР!" выводит ерунду всякую. у меня два
варианта дисплеев у одного зашита кириллица. второй китайский.

Алексей 21.05.18 09:22

Я бы для начала написал бы тестовою программу. Перебор всей памяти с выводом на дисплей символов и их адресов. А потом уже выеснять в чем проблема. Скорее всего таблица символов не совпадает с таблицей ascii.

Андрей 03.09.18 08:32

День Добрый!

А схемку под Proteus не можете подкинуть?

Андрей 03.09.18 10:22

Или в Proteuse никто не проверял?

Андрей 03.09.18 10:56

Разобрался main_init

Павел 30.05.19 23:35

Любопытная вещь, адрес дисплея 0х4Е, а если тот же дисплей подключить к ардуинке то адрес 0х27

Павел 31.05.19 11:04

Спасибо огромное за Вашу работу! Перерыл весь интернет, ни один из приведенных примеров кроме Вашего не заработал. Единственное, в архиве проекта в функции инициализации дисплея не прописаны задержки _delay_, и он соответственно не работает

Алексей 01.06.19 09:52

Ну это больше демонстрационный проект. По хорошему нужно библиотеку axlib переписывать, но с учетом того что STM32 и STM8 двигается семимильными шагами, смысла в AVR уже нет вообще.

Павел 05.06.19 12:57

У STM нет DIP корпусов, сложнее делать печатные платы. Для моих проектов возможностей AVR хватает с запасом, на одной Atmega 8 очень много можно уместить

Алексей 05.06.19 15:20

Да, но сколько стоит Atmega8 и stm8s003)))

Дмитрий 07.06.19 00:41

Здравствуй, Алексей.
Подскажи, пожалуйста, как нужно читать из pcf8574 состояние порта?
Хочу сделать внешний блок, 8 GPIO по шине i2c - саме оно.

Дмитрий 07.06.19 17:56

Сам себе отвечу
Функция возвращает байт - состояние портов микросхемы
uint8_t pcf8574_byte_rcv(uint8_t addr)
{
uint8_t ask = ACK;
addr |= 0b01; //READ
uint8_t data=0;
i2c_start();
ask = i2c_send_byte(addr);
if(!ask) data = i2c_read_byte(NACK);
i2c_stop();

Return data;
}

Павел 07.06.19 20:37

Сколько стоит, 150 рублей, по цене релюшки в общем), а как вы разводите платы под STM? ЛУТ ненадежен, ЧПУ фрезер не уверен что возьмет (не пробовал)

LCD I2C модуль позволить подключить символьный дисплей к плате Arduino всего по двум сигнальным проводам.

Используемые компоненты (купить в Китае):

. Управляющая плата

. Соединительные провода

Основные технические характеристики:

Дисплей: Символьный 16х02 либо 20x04
. Подсветка: Синяя c белыми символами
. Контраст: Настраивается потенциометром
. Напряжение питания: 5В
. Интерфейс: I2C
. I2C адрес: 0x27
. Размеры: 82мм x 35мм x 18мм

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

Модуль оборудован четырех-пиновым разъемом стандарта 2.54мм

SCL : последовательная линия тактирования (Serial CLock)

SDA : последовательная линия данных (Serial DAta)

VCC : "+" питания

GND : "-" питания

Выводы отвечающие за интерфейс I2C на платах Arduino на базе различных контроллеров разнятся

Для работы с данным модулем необходимо установить библиотеку LiquidCrystal_I2C1602V1

Скачиваем, распаковываем и закидываем в папку libraries в папке Arduino. В случае, если на момент добавления библиотеки, Arduino IDE была открытой, перезагружаем среду.

Переходим непосредственно к скетчу. В данном примере выведем стандартный "Hello, world!" и для адрес нашего сообщества.

пример программного кода:

#include #include LiquidCrystal_I2C lcd(0x27,16,2); /* Задаем адрес и размерность дисплея. При использовании LCD I2C модуля с дисплеем 20х04 ничего в коде изменять не требуется, cледует только задать правильную размерность */ void setup () { lcd.init(); // Инициализация lcd lcd.backlight(); // Включаем подсветку // Курсор находится в начале 1 строки lcd.print ("Hello, world!" ); // Выводим текст lcd.setCursor (0, 1); // Устанавливаем курсор в начало 2 строки lcd.print ("сайт" ); // Выводим текст } void loop () { }

Создание собственных символов

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

Не беда, требуемый символ можно сделать вручную. Данный способ частично, ограничение в 7 символов, поможет решить проблему вывода.

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

В ниже приведенном примере нарисуем смайлик.

пример программного кода:

//Тестировалось на Arduino IDE 1.0.5 // Добавляем необходимые библиотеки #include #include // Битовая маска символа улыбки byte smile = { B00010, B00001, B11001, B00001, B11001, B00001, B00010, }; LiquidCrystal_I2C lcd(0x27,20,4); // Задаем адрес и размерность дисплея. void setup () { lcd.init(); // Инициализация lcd lcd.backlight(); // Включаем подсветку // Создаем символ под номером 0 lcd.createChar (1, smile); lcd.setCursor (0, 0); // Устанавливаем курсор в начало 1 строки lcd.print ("\1" ); // Выводим смайлик (символ под номером 1) - "\1" } void loop () { }

Программка для легкого создания символов

В комментариях участник сообщества скинул ссылку на генератор символов