Arduino lcd 1602 i2c показать все символы. Подключение LCD экрана LCM1602 с I2C к Arduino

В этой статье расскажу, как использовать интерфейсный модуль 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.сайт"); // Выводим текст } void loop() { }

Тестировалось на Arduino IDE 1.6.11

Дата тестирования 15.09.2016г.

#include

#include

LiquidCrystal_I2C lcd (0x27 , 16 , 2 ) ; // Задаем адрес и размер дисплея

void setup ()

lcd . init () ; // Инициализация lcd

lcd . backlight () ; // Включаем подсветку

lcd . print ("Hello, world" ) ; // Выводим текст

lcd . print ("www.сайт" ) ; // Выводим текст

void loop ()

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


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

Заполучил я тут от хорошего магазина Чип Резистор очередной девайс для изучения и применения в полезных устройствах. Сей девайс оказался заточен для управления ЖК дисплеем под управлением контроллера 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? ЛУТ ненадежен, ЧПУ фрезер не уверен что возьмет (не пробовал)

  • Модуль FC-113 сделан на базе микросхемы PCF8574T, которая представляет собой 8-битный сдвиговый регистр - «расширитель» входов-выходов для последовательной шины I2C. На рисунке микросхема обозначена DD1.
  • R1 - подстроечный резистор для регулировки контрастности ЖК дисплея.
  • Джампер J1 используется для включения подсветки дисплея.
  • Выводы 1…16 служат для подключения модуля к выводам LCD дисплея.
  • Контактные площадки А1…А3 нужны для изменения адреса I2C устройства. Запаивая соответствующие перемычки, можно менять адрес устройства. В таблице приведено соответствие адресов и перемычек: "0" соответствует разрыву цепи, "1" - установленной перемычке. По умолчанию все 3 перемычки разомкнуты и адрес устройства 0x27 .

2 Схема подключения ЖК дисплея к Arduino по протоколу I2C

Подключение модуля к Arduino осуществляется стандартно для шины I2C: вывод SDA модуля подключается к аналоговому порту A4, вывод SCL - к аналоговому порту A5 Ардуино. Питание модуля осуществляется напряжением +5 В от Arduino. Сам модуль соединяется выводами 1…16 с соответствующими выводами 1…16 на ЖК дисплее.


3 Библиотека для работы по протоколу I2C

Теперь нужна библиотека для работы с LCD по интерфейсу I2C. Можно воспользоваться, например, вот этой (ссылка в строке "Download Sample code and library").

Скачанный архив LiquidCrystal_I2Cv1-1.rar разархивируем в папку \libraries\ , которая находится в директории Arduino IDE.

Библиотека поддерживает набор стандартных функций для LCD экранов:

Функция Назначение
LiquidCrystal() создаёт переменную типа LiquidCrystal и принимает параметры подключения дисплея (номера выводов);
begin() инициализация LCD дисплея, задание параметров (кол-во строк и символов);
clear() очистка экрана и возврат курсора в начальную позицию;
home() возврат курсора в начальную позицию;
setCursor() установка курсора на заданную позицию;
write() выводит символ на ЖК экран;
print() выводит текст на ЖК экран;
cursor() показывает курсор, т.е. подчёркивание под местом следующего символа;
noCursor() прячет курсор;
blink() мигание курсора;
noBlink() отмена мигания;
noDisplay() выключение дисплея с сохранением всей отображаемой информации;
display() включение дисплея с сохранением всей отображаемой информации;
scrollDisplayLeft() прокрутка содержимого дисплея на 1 позицию влево;
scrollDisplayRight() прокрутка содержимого дисплея на 1 позицию вправо;
autoscroll() включение автопрокрутки;
noAutoscroll() выключение автопрокрутки;
leftToRight() задаёт направление текста слева направо;
rightToLeft() направление текста справа налево;
createChar() создаёт пользовательский символ для LCD-экрана.

4 Скетч для вывода текста на LCD экран по шине I2C

Откроем образец: Файл Образцы LiquidCrystal_I2C CustomChars и немного его переделаем. Выведем сообщение, в конце которого будет находиться мигающий символ. В комментариях к коду прокомментированы все нюансы скетча.

#include // подключаем библиотеку Wire #include // подключаем библиотеку ЖКИ #define printByte(args) write(args); // uint8_t heart = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0}; // битовая маска символа «сердце» LiquidCrystal_I2C lcd(0x27, 16, 2); // Задаём адрес 0x27 для LCD дисплея 16x2 void setup() { lcd.init(); // инициализация ЖК дисплея lcd.backlight(); // включение подсветки дисплея lcd.createChar(3, heart); // создаём символ «сердце» в 3 ячейке памяти lcd.home(); // ставим курсор в левый верхний угол, в позицию (0,0) lcd.!"); // печатаем строку текста lcd.setCursor(0, 1); // перевод курсора на строку 2, символ 1 lcd.print(" i "); // печатаем сообщение на строке 2 lcd.printByte(3); // печатаем символ «сердце», находящийся в 3-ей ячейке lcd.print(" Arduino "); } void loop() { // мигание последнего символа lcd.setCursor(13, 1); // перевод курсора на строку 2, символ 1 lcd.print("\t"); delay(500); lcd.setCursor(13, 1); // перевод курсора на строку 2, символ 1 lcd.print(" "); delay(500); }

Кстати, символы, записанные командой lcd.createChar(); , остаются в памяти дисплея даже после выключения питания, т.к. записываются в ПЗУ дисплея 1602.

5 Создание собственных символов для ЖК дисплея

Немного подробнее рассмотрим вопрос создания собственных символов для ЖК экранов. Каждый символ на экране состоит из 35-ти точек: 5 в ширину и 7 в высоту (+1 резервная строка для подчёркивания). В строке 6 приведённого скетча мы задаём массив из 7-ми чисел: {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0} . Преобразуем 16-ричные числа в бинарные: {00000, 01010, 11111, 11111, 01110, 00100, 00000} . Эти числа - не что иное, как битовые маски для каждой из 7-ми строк символа, где "0" обозначают светлую точку, а "1" - тёмную. Например, символ сердца, заданный в виде битовой маски, будет выглядеть на экране так, как показано на рисунке.

6 Управление ЖК экраном по шине I2C

Загрузим скетч в Arduino. На экране появится заданная нами надпись с мигающим курсором в конце.


7 Что находится «за» шиной I2C

В качестве бонуса рассмотрим временную диаграмму вывода латинских символов "A", "B" и "С" на ЖК дисплей. Эти символы имеются в ПЗУ дисплея и выводятся на экран просто передачей дисплею их адреса. Диаграмма снята с выводов RS, RW, E, D4, D5, D6 и D7 дисплея, т.е. уже после преобразователя FC-113 «I2C параллельная шина». Можно сказать, что мы погружаемся немного «глубже» в «железо».


Временная диаграмма вывода латинских символов "A", "B" и "С" на LCD дисплей 1602

На диаграмме видно, что символы, которые имеются в ПЗУ дисплея (см. стр.11 даташита, ссылка ниже), передаются двумя полубайтами, первый из которых определяет номер столбца таблицы, а второй - номер строки. При этом данные «защёлкиваются» по фронту сигнала на линии E (Enable), а линия RS (Register select, выбор регистра) находится в состоянии логической единицы, что означает передачу данных. Низкое состояние линии RS означает передачу инструкций, что мы и видим перед передачей каждого символа. В данном случае передаётся код инструкции возврата каретки на позицию (0, 0) ЖК дисплея, о чём также можно узнать, изучив техническое описание дисплея.

И ещё один пример. На этой временной диаграмме показан вывод символа «Сердце» на ЖК дисплей.


Опять, первые два импульса Enable соответствуют инструкции Home() (0000 0010 2) - возврат каретки на позицию (0; 0), а вторые два - вывод на ЖК дисплей хранящийся в ячейке памяти 3 10 (0000 0011 2) символ «Сердце» (инструкция lcd.createChar(3, heart); скетча).

С номиналами от 10 Ом до 1 МОм);

  • 2 резистора по 4,7 кОм (из того же набора);
  • соединительные провода (например, вот хороший набор);
  • компьютер с Arduino IDE.
  • 1 Описание интерфейса I2C

    Последовательный протокол обмена данными IIC (также называемый I2C - Inter-Integrated Circuits, межмикросхемное соединение) использует для передачи данных две двунаправленные линии связи, которые называются шина последовательных данных SDA (Serial Data) и шина тактирования SCL (Serial Clock) . Также имеются две линии для питания. Шины SDA и SCL подтягиваются к шине питания через резисторы.

    В сети есть хотя бы одно ведущее устройство (Master) , которое инициализирует передачу данных и генерирует сигналы синхронизации. В сети также есть ведомые устройства (Slave) , которые передают данные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес, по которому ведущий и обращается к нему. Адрес устройства указывается в паспорте (datasheet). К одной шине I2C может быть подключено до 127 устройств, в том числе несколько ведущих. К шине можно подключать устройства в процессе работы, т.е. она поддерживает «горячее подключение».

    Давайте рассмотрим временную диаграмму обмена по протоколу I2C. Есть несколько различающихся вариантов, рассмотрим один из распространённых. Воспользуемся логическим анализатором, подключённым к шинам SCL и SDA.

    Мастер инициирует обмен. Для этого он начинает генерировать тактовые импульсы и посылает их по линии SCL пачкой из 9-ти штук. Одновременно на линии данных SDA он выставляет адрес устройства , с которым необходимо установить связь, которые тактируются первыми 7-ми тактовыми импульсами (отсюда ограничение на диапазон адресов: 2 7 = 128 минус нулевой адрес). Следующий бит посылки - это код операции (чтение или запись) и ещё один бит - бит подтверждения (ACK), что ведомое устройство приняло запрос. Если бит подтверждения не пришёл, на этом обмен заканчивается. Или мастер продолжает посылать повторные запросы.

    Это проиллюстрировано на рисунке ниже.. В первом случае, для примера, отключим ведомое устройство от шины. Видно, что мастер пытается установить связь с устройством с адресом 0x27, но не получает подтверждения (NAK). Обмен заканчивается.


    Теперь подключим к шине I2C ведомое устройство и повторим операцию. Ситуация изменилась. На первый пакет с адресом пришло подтверждение (ACK) от ведомого. Обмен продолжился. Информация передаётся также 9-битовыми посылками, но теперь 8 битов занимают данные и 1 бит - бит подтверждения получения ведомым каждого байта данных. Если в какой-то момент связь оборвётся и бит подтверждения не придёт, мастер прекратит передачу.

    2 Реализация I2C в Arduino

    Arduino использует для работы по интерфейсу I2C два порта. Например, в Arduino UNO и Arduino Nano аналоговый порт A4 соответствует SDA, аналоговый порт A5 соответствует SCL.


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

    3 Библиотека "Wire" для работы с IIC

    Для облегчения обмена данными с устройствами по шине I2C для Arduino написана стандартная библиотека Wire . Она имеет следующие функции:

    Функция Назначение
    begin(address) инициализация библиотеки и подключение к шине I2C; если не указан адрес, то присоединённое устройство считается ведущим; используется 7-битная адресация;
    requestFrom() используется ведущим устройством для запроса определённого количества байтов от ведомого;
    beginTransmission(address) начало передачи данных к ведомому устройству по определённому адресу;
    endTransmission() прекращение передачи данных ведомому;
    write() запись данных от ведомого в ответ на запрос;
    available() возвращает количество байт информации, доступных для приёма от ведомого;
    read() чтение байта, переданного от ведомого ведущему или от ведущего ведомому;
    onReceive() указывает на функцию, которая должна быть вызвана, когда ведомое устройство получит передачу от ведущего;
    onRequest() указывает на функцию, которая должна быть вызвана, когда ведущее устройство получит передачу от ведомого.

    4 Подключение I2C устройства к Arduino

    Давайте посмотрим, как работать с шиной I2C с помощью Arduino.

    Сначала соберём схему, как на рисунке. Будем управлять яркостью светодиода, используя цифровой 64-позиционный потенциометр AD5171 (см. техническое описание), который подключается к шине I2C. Адрес, по которому мы будем обращаться к потенциометру - 0x2c (44 в десятичной системе).


    5 Управление устройством по шине IIC

    Рассмотрим диаграммы информационного обмена с цифровым потенциометром AD5171, представленные в техническом описании:


    Нас тут интересует диаграмма записи данных в регистр RDAC . Этот регистр используется для управления сопротивлением потенциометра.

    Откроем из примеров библиотеки "Wire" скетч: Файл Образцы Wire digital_potentiometer . Загрузим его в память Arduino.

    #include // подключаем библиотеку "Wire" byte val = 0; // значение для передачи потенциометру void setup() { Wire.begin(); // подключаемся к шине I2C как мастер } void loop() { Wire.beginTransmission(44); // начинаем обмен с устройством с I2C адресом "44" (0x2C) Wire.write(byte(0x00)); // посылаем инструкцию записи в регистр RDAC Wire.write(val); // задаём положение 64-позиционного потенциометра Wire.endTransmission(); // завершаем I2C передачу val++; // инкрементируем val на 1 if (val == 63) { // по достижении максимума потенциометра val = 0; // сбрасываем val } delay(500); }

    После включения вы видите, как яркость светодиода циклически нарастает, а потом гаснет. При этом мы управляем потенциометром с помощью Arduino по шине I2C.

    Пожалуй один из самых популярных экранов на рынке. Собран на популярном контроллере HD44780U. Из названия модели следует, что экран состоит из двух строк по 16 символов. Поддержки русского языка в этой конкретной модели нет.

    Шина данных ш2с позволяет по двум проводам подключать до 127 устройств, при чем одновременно. Данный I2C реализован на чипе PCF8574T.

    Схема подключения:

    Синяя штука — переменное сопротивление, позволяет настроить контрастность экрана.

    Перемычка слева — отвечает за подсветку экрана.

    Блок из 4х контактов подключается к arduino так:

    GND — GND
    VCC — 5V
    SDA — A4 (если Arduino MEGA, то к D20)
    SCL — A5 (если Arduino MEGA, то к D21)

    Библиотека

    Скетч

    У дисплея может быть другой IIC адрес, вместо 0x27 может оказаться 0x3F. Чтобы точно определить адрес можете воспользоваться сканером i2c устройств .

    #include #include //задаем адрес LCD экрана 0x27, 16 символов, 2 строки LiquidCrystal_I2C lcd(0x27, 16, 2); void setup () { lcd.init(); // Инициализируем экран //включаем подсветку lcd.backlight(); //Устанавливаем позицию начиная с которой выводится текст. lcd.setCursor (2, 0); //выводим строку 1 lcd.print ("Hello, World!" ); //аналогично выводим вторую строку lcd.setCursor (1, 1); lcd.print ("www.сайт" ); } void loop () { }