Подключаем несколько i2c экранов к arduino

Представим задачу, когда одного экрана подключенного к ардуино не хватает. Например, при создании электронного замка, информацию надо выводить с обеих сторон двери. В таком случае i2c шина ваш лучший друг.
Все экраны подключаются в одни и те же пины благодаря шине i2c. Давайте подключим сразу два экрана.

Вся суть управления разными экранами в изменении i2c адреса одного из них. Для этого надо запаять вместе площадки внутри квадрата А0, А1, А2 на i2c переходнике (а можно и комбинировать, те А0 и А2 вместе). На картинке контакты изображены под синим потенциометром.

Теперь установите Liquid crystal i2c библиотеку.
Загружаем скетч i2c сканера на arduino и открываем монитор com порта.


Здесь мы получили i2c адрес экрана. Можно пометить на задней стороне.
Теперь переходим к прошивке. Здесь надо объявить два экрана с разными адресами и именами и обращаться к конкретному экрану. Прошивка есть на github.
//подключаем библиотеки #include #include LiquidCrystal_I2C lcd (0x26, 16, 2); //объявляем первый экран LiquidCrystal_I2C lcd2(0x27, 16, 2); //объявляем второй экран void setup() < lcd.init(); // инициалищируем первый экран lcd2.init(); // инициалищируем второй экран lcd.backlight(); //подсвктка первого экрана lcd2.backlight(); //подсвктка второго экрана //Устанавливаем курсор и печатаем на первом экране lcd.setCursor(0, 0); lcd.print("Hello, world!"); lcd.setCursor(0, 1); lcd.print("First screen"); //Устанавливаем курсор и печатаем на втором экране lcd2.setCursor(0, 0); lcd2.print("Hello, world!"); lcd2.setCursor(0, 1); lcd2.print("Second screen"); >void loop()
Вот наш результат.


Любые вопросы и предложения пишите в комментариях. Буду рад!
Интерфейс i2c Ардуино, сканер i2c шины (scl sda)

I2C Arduino (i2c — Inter-Integrated Circuits) — это протокол последовательной связи по двум линиям связи. Эти линии также называются: шина SDA (последовательные данные) и шина SCL (последовательный тактовый генератор). Порты SDA и SCL Ардуино подтягиваются к шине питания микроконтроллера через резисторы. Рассмотрим, что такое шина i2c Arduino Nano и как подключить к плате Ардуино несколько устройств по интерфейсу i2c.
Необходимые компоненты:
- Arduino Uno / Arduino Nano / Arduino Mega
- lcd 1602 i2c дисплей
- модуль rtc ds1307 i2c
- коннекторы
- библиотека LiquidCrystal_I2C.h и iarduino_RTC.h
- Подключение устройств по шине SPI к Arduino
- Порты коммуникации на Arduino Uno, Nano, Mega
- Язык программирования Ардуино C++
Микроконтроллеры Arduino используют два контакта для работы i2c. В Arduino Uno и Nano линия SDA соответствует аналоговому порту A4, а SCL — аналоговому порту A5. В Ardunio Mega линия SDA — это 20 вывод, а линия SCL — 21 вывод. Чтобы облегчить работу с шиной i2c и обмен данными между устройствами, для IDE Arduino написана стандартная библиотека Wire (скачивать и устанавливать библиотеку не требуется).
Протокол интерфейс i2c Ардуино: описание

Каждому устройству при подключении к микроконтроллеру по протоколу i2c присваивается уникальный адрес (можно подключить до 127 устройств). Изменить адрес устройства на шине невозможно, так как он встроен в микросхему. Часто производители модулей предлагают возможность изменения адреса устройства в небольшом диапазоне, что позволяет подключить к шине iic Arduino несколько одинаковых устройств одновременно.
I2C scanner Arduino (сканер шины i2c)

| LCD 1602 i2c | Arduino Uno | Arduino Nano | Arduino Mega |
| GND | GND | GND | GND |
| VCC | 5V | 5V | 5V |
| SDA | A4 | A4 | 20 |
| SCL | A5 | A5 | 21 |
Следующая программа позволяет узнать адреса всех устройств, подключенных к шине i2c. Если устройство не было подключено или подключено неправильно, на мониторе порта появится сообщение о том, что устройство не найдено. Вместо дисплея можно подключить любое устройство, поддерживающее связь с микроконтроллером по протоколу iic — модуль часов реального времени DS1302, датчик атмосферного давления BMP180 и т.д.
Скетч для сканирования шины I2C Arduino
#include "Wire.h" void setup() < Wire.begin(); Serial.begin(9600); >void loop() < byte error, address; int nDevices; Serial.println("Scanning. "); nDevices = 0; for(address = 8; address < 127; address++ )< Wire.beginTransmission(address); 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("Unknow 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); >
Подключение несколько устройств к шине i2c Ардуино

| DS1307 i2c | Arduino Uno | Arduino Nano | Arduino Mega |
| GND | GND | GND | GND |
| VCC | 5V | 5V | 5V |
| SDA | A4 | A4 | 20 |
| SCL | A5 | A5 | 21 |
В следующем примере два устройства: дисплей 1602 и модуль часов времени будут подключены к шине IIC. После сборки схемы можно провести предварительное сканирование шины, используя программу, размещенную выше. Адреса всех устройств различны, и можно изменить только iic адрес жк дисплея 1602 i2c. Для остальных устройств адреса «жестко привязаны» и используются в библиотеках по умолчанию.
Скетч несколько устройств на i2c, scanner i2c шины
#include "Wire.h" #include "LiquidCrystal_I2C.h" LiquidCrystal_I2C LCD(0x27,16,2); #include "iarduino_RTC.h" iarduino_RTC time (RTC_DS1307); // DS1307 i2C // iarduino_RTC time (RTC_DS3231); // DS3231 i2C void setup() < Serial.begin(9600); LCD.init(); LCD.backlight(); time.begin(); // 0 sec, 30 min, 18 hour, 2 date, january, 2022, wed time.settime(0, 30, 18, 2, 1, 22, 0); >void loop() < // выводим время 1 раз в секунду if (millis() % 1000 == 0) < Serial.println(time.gettime("d-m-Y, H:i:s, D")); LCD.setCursor(0,0); LCD.print(time.gettime("d M Y, D")); LCD.setCursor(4,1); LCD.print(time.gettime("H:i:s")); >>
Заключение. Мы исследовали возможность подключения нескольких i2c устройств к плате Ардуино, что будет полезно знать при разработке различных DIY проектов. Например, метеостанции на Ардуино с дисплеем и датчиком давления. Если у вас остались вопросы о сканере шины i2c или о подключении нескольких периферийных устройств по этому протоколу, не стесняйтесь оставлять их в комментариях к этой статье.
Урок 26.3 Соединяем две arduino по шине I2C
При создании некоторых проектов, требуется разделить выполняемые задачи между несколькими arduino.
В этом уроке мы научимся соединять две arduino по аппаратной шине I2C.

Преимущества:
- Реализуется возможность подключения до 126 устройств.
(не рекомендуется присваивать устройствам адреса 0x00 и 0x7F) - Не требуются дополнительные модули.
- Все устройства одинаково подключаются к шине.
- Каждое ведомое устройство имеет свой уникальный адрес на шине.
Недостатки:
- Код программы немного сложнее чем для шины UART.
Нам понадобится:
- Arduino х 3шт.
- LCD дисплей LCD1602 IIC/I2C(синий) или LCD1602 IIC/I2C(зелёный) х 1шт.
- Trema Shield х 3шт.
- Trema кнопка x 2шт.
- Trema светодиод x 1шт.
- Trema потенциометр x 1шт.
- Trema I2C Hub x 1шт.
- Шлейф «мама-мама» (4 провода) для шины I2С х 4шт.
Для реализации проекта нам необходимо установить библиотеки:
- Библиотека LiquidCrystal_I2C_V112 (для подключения дисплеев LCD1602 по шине I2C).
- Библиотека iarduino_I2C_connect (для удобства соединения нескольких arduino по шине I2C).
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki — Установка библиотек в Arduino IDE, а о том, как работать с LCD дисплеями, на странице Wiki — Работа с символьными ЖК дисплеями.
Видео:
Схема подключения:
На шине i2С находятся 4 устройства: 3 arduino и 1 LCD дисплей. Все устройства шины I2C соединены через Trema I2C Hub. Для подключения Arduino используются аппаратные выводы шины I2C.
- Arduino master — к цифровому выводу D2 подключена trema кнопка.
- Arduino slave 0x01 — к цифровому выводу D2 подключена trema кнопка.
- Arduino slave 0x02 — к цифровому выводу D13 подключён trema светодиод, к аналоговому выводу A0 подключён Trema потенциометр.
- LCD I2C дисплей — является устройством slave 0x27.
На шине I2C не используются дополнительные подтягивающие резисторы (для линий SDA и SCL), так как они интегрированы в LDC I2C дисплее.
Код программы:
Arduino master:
// Подключаем библиотеки: #include // подключаем библиотеку для работы с шиной I2C #include // подключаем библиотеку для работы с LCD дисплеем #include // подключаем библиотеку для соединения arduino по шине I2C // Объявляем переменные и константы: iarduino_I2C_connect I2C2; // объявляем переменную для работы c библиотекой iarduino_I2C_connect LiquidCrystal_I2C lcd(0x27,16,2); // объявляем переменную для работы с LCD дисплеем, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) const byte PIN_Button_master = 2; // объявляем константу с указанием номера цифрового вывода, к которому подключена кнопка bool VAR_Button_master = 0; // объявляем переменную для чтения состояний собственной кнопки bool VAR_Button_slave = 0; // объявляем переменную для чтения состояний кнопки ведомого 0x77 int VAR_Potentiometer = 0; // объявляем переменную для чтения значения с потенциометра ведомого 0x77 void setup() < //Wire.setClock(400000); // устанавливаем скорость передачи данных по шине I2C = 400кБит/с Wire.begin(); // инициируем подключение к шине I2C в качестве ведущего (master) устройства pinMode(PIN_Button_master, INPUT); // Устанавливаем режим работы вывода собственной кнопки, как вход //Выводим данные на LCD дисплей: lcd.init(); // инициируем LCD дисплей lcd.backlight(); // включаем подсветку LCD дисплея lcd.setCursor(0, 0); lcd.print("iArduino.ru"); // выводим текст "iArduino.ru" delay(1000); // ждём 1 секунду lcd.setCursor(0, 0); lcd.print("button = "); // выводим текст "button = " lcd.setCursor(0, 1); lcd.print("resistor = "); // выводим текст "resistor = " >void loop() < //Считываем данные: VAR_Button_master = digitalRead(PIN_Button_master);// Считываем состояние собственной кнопки VAR_Button_slave = I2C2.readByte(0x01,0); // Считываем состояние кнопки ведомого (адрес ведомого 0x01, номер регистра 0) VAR_Potentiometer = I2C2.readByte(0x02,1)
Arduino slave 0x01:
// Подключаем библиотеки: #include // подключаем библиотеку для работы с шиной I2C #include // подключаем библиотеку для соединения arduino по шине I2C // Объявляем переменные и константы: iarduino_I2C_connect I2C2; // объявляем переменную для работы c библиотекой iarduino_I2C_connect const byte PIN_Button = 2; // объявляем константу с указанием номера цифрового вывода, к которому подключена кнопка byte REG_Array[1]; // объявляем массив, данные которого будут доступны для чтения/записи по шине I2C void setup() < //Wire.setClock(400000); // устанавливаем скорость передачи данных по шине I2C = 400кБит/с Wire.begin(0x01); // инициируем подключение к шине I2C в качестве ведомого (slave) устройства, с указанием своего адреса на шине. I2C2.begin(REG_Array); // инициируем возможность чтения/записи данных по шине I2C, из/в указываемый массив pinMode(PIN_Button, INPUT); // Устанавливаем режим работы вывода кнопки, как вход >void loop() < REG_Array[0] = digitalRead(PIN_Button); // Сохраняем состояние кнопки в 0 ячейку массива REG_Massive >
Arduino slave 0x02:
// Подключаем библиотеки: #include // подключаем библиотеку для работы с шиной I2C #include // подключаем библиотеку для соединения arduino по шине I2C // Объявляем переменные и константы: iarduino_I2C_connect I2C2; // объявляем переменную для работы c библиотекой iarduino_I2C_connect const byte PIN_Potentiometer = 0; // объявляем константу с указанием номера аналогового вывода, к которому подключён потенциометр const byte PIN_LED = 13; // объявляем константу с указанием номера цифрового вывода, к которому подключен светодиод int VAR_Potentiometer = 0; // объявляем переменную для чтения значения с потенциометра byte REG_Massive[3]; // объявляем массив, данные которого будут доступны для чтения/записи по шине I2C void setup() < //Wire.setClock(400000); // устанавливаем скорость передачи данных по шине I2C = 400кБит/с Wire.begin(0x02); // инициируем подключение к шине I2C в качестве ведомого (slave) устройства, с указанием своего адреса на шине. I2C2.begin(REG_Massive); // инициируем возможность чтения/записи данных по шине I2C, из/в указываемый массив pinMode(PIN_LED, OUTPUT); // Устанавливаем режим работы вывода светодиода, как выход >void loop()< VAR_Potentiometer = analogRead(PIN_Potentiometer); // Считываем значение потенциометра REG_Massive[1] = VAR_Potentiometer>>8; // Сохраняем старший байт значения потенциометра в 1 ячейку массива REG_Massive REG_Massive[2] = VAR_Potentiometer; // Сохраняем младший байт значения потенциометра во 2 ячейку массива REG_Massive digitalWrite(PIN_LED, REG_Massive[0]); // вкл/выкл светодиод в соответствии со значением 0 элемента массива REG_Massive >
Алгоритм работы:
- Arduino master проверяет состояние собственной кнопки.
- Arduino master опрашивает две Arduino Slave.
- Arduino Slave 0x01 возвращает состояние кнопки.
- Arduino Slave 0x02 возвращает значение падения напряжения плеча потенциометра.
- Arduino Slave 0x02 включает или выключает светодиод, в соответствии с полученными данными.
Настройка параметров шины I2C:
Максимальная, аппаратно реализуемая частота передачи данных, может достигать 1/16 от тактовой частоты.
Библиотека Wire позволяет устанавливать скорость передачи данных через функцию setClock(), которую требуется вызвать до функции begin().
Библиотека Wire позволяет аппаратно подключить Arduino к шине I2C с указанием роли Arduino на шине: ведущий или ведомый.
- Wire.setClock(400000); // скорость передачи данных 400 кБит/с.
- Wire.begin(); // подключение к шине I2C в роли ведущего.
- Wire.begin(адрес); // подключение к шине I2C в роли ведомого, с указанием адреса.
Функции библиотеки iarduino_I2C_connect:
В библиотеке iarduino_I2C_connect реализованы 4 функции: 2 для ведущего и 2 для ведомого.
На ведомом устройстве достаточно вызвать функцию begin() с указанием массива, данные которого требуется сделать доступными для мастера. Далее можно работать с этим массивом, «забыв» про шину I2C. Мастер обращаясь к ведомому сможет получать и изменять данные элементов указанного массива (обращаясь к номеру элемента массива как к номеру регистра).
Если требуется запретить мастеру менять значения некоторых ячеек массива, то достаточно вызвать «необязательную» функцию writeMask() с указанием маскировочного массива, каждый элемент которого является флагом, разрешающим запись в соответствующий элемент массива доступного по шине I2C.
На ведущем устройстве доступны функции readByte() и writeByte(). Указывая в качестве параметров функций, адрес ведомого устройства и номер регистра, можно побайтно читать и записывать данные.
Функции для ведомого:
begin():
- Назначение: указание массива, элементы которого будут доступны для чтения/записи по шине I2C.
- Синтаксис: begin(массив); // тип данных массива - byte.
- Возвращаемые значения: Нет.
- Примечание: Вызывается 1 раз в коде функции Setup().
writeMask():
- Назначение: указание маскировочного массива, каждый элемент которого является флагом разрешения записи по шине I2C.
- Синтаксис: writeMask(маскировочный_массив); // тип данных массива - bool.
- Возвращаемые значения: Нет.
- Примечание: Вызывается 1 раз в коде функции Setup().
- Пример:
#include
#include
iarduino_I2C_connect ccc;
byte aaa[5]; // объявляем 5 элементов массива, к которому разрешим доступ.
bool bbb[5] = ; // объявляем 5 элементов маскировочного массива.
Wire.begin(0x33); // подключаемся к шине I2C в роли ведомого с адресом 0x33.
ccc.begin(aaa); // разрешаем доступ к массиву aaa по шине I2C.
ccc.wtiteMask(bbb); // маскируем разрешение на запись в массив aaa.- В соответствии со значениями массива bbb, мастер сможет записывать данные в ячейки 1,2,3 массива aaa, а попытка записи в 0 и 4 элементы будет проигнорирована.
- Если массив aaa имеет больше элементов чем массив bbb, то попытка мастера записать данные в «лишние» элементы будет проигнорирована.
- Если не объявлять маскировочный массив (не вызывать функцию writeMask() вообще), то все элементы массива aaa будут доступны для записи мастером.
Функции для ведущего:
readByte():
- Назначение: Чтение одного байта данных из устройства на шине I2C.
- Синтаксис: readByte(адрес_устройства, адрес_регистра);
- Возвращаемые значения: uint8_t байт - данные считанные из указанного адреса, указанного устройства.
- Примечание: Если производится чтение по шине I2C из массива объявленного функцией begin(), то адрес регистра соответствует номеру элемента массива.
writeByte():
- Назначение: Запись одного байта данных в устройство на шине I2C.
- Синтаксис: writeByte(адрес_устройства, адрес_регистра, байт_данных);
- Возвращаемые значения: uint8_t байт - результат операции записи, соответствует значению возвращаемому функцией Wire.endTransmission().
- 0 - успех.
- 1 - переполнение буфера передачи данных.
- 2 - получен NACK на переданный адрес устройства.
- 3 - получен NACK на переданный адрес регистра.
- 4 - неизвестная ошибка.
Ссылки:
- Код программы - Arduino master.
- Код программы - Arduino slave 0x01.
- Код программы - Arduino slave 0x02.
- Библиотека LiquidCrystal_I2C_V112.
- Библиотека iarduino_I2C_connect.
- Wiki - Установка библиотек в Arduino IDE .
- Wiki - Работа с символьными ЖК дисплеями.
- Wiki - Trema Shield.
Использование интерфейса I2C в Arduino – полное руководство
В предыдущей статье на нашем сайте мы рассмотрели использование интерфейса SPI в плате Arduino. А здесь мы рассмотрим еще один очень популярный в настоящее время протокол последовательной связи I2C (Inter Integrated Circuits - последовательная шина обмена данными между интегральными схемами ) и как его использовать в плате Arduino. Если сравнивать протоколы I2C и SPI, то I2C использует только 2 линии (провода), а SPI использует 4 линии, I2C может иметь несколько ведущих (Master) и несколько ведомых (Slave), а SPI может иметь только одного ведущего и нескольких ведомых. То есть если в вашем проекте сразу несколько микроконтроллеров должны быть ведущими, то тогда вам нужно использовать интерфейс (протокол) I2C. Протокол I2C обычно используется для взаимодействия с гироскопами, акселерометрами, датчиками давления, LED дисплеями и т.д.

В этом проекте мы будем использовать протокол I2C для обмена данными между двумя платами Arduino и передавать между ними значения (от 0 до 127) с помощью потенциометра. Эти принятые значения будут отображаться на ЖК дисплеях, подключенных к каждой плате Arduino. Одна из плат Arduino будет выступать в роли ведущего (Master), а другая – в роли ведомого (Slave).
Что такое протокол I2C и как он работает
Термин IIC расшифровывается как “Inter Integrated Circuits” и часто обозначается как I2C или даже как TWI (2-wire interface protocol), но во всех случаях за этими обозначениями скрывается один и тот же протокол. I2C представляет собой протокол синхронной связи – это значит что оба устройства, которые обмениваются информацией с помощью данного протокола должны использовать общий сигнал синхронизации. Поскольку в этом протоколе используются всего 2 линии (провода), то по одной из них должен передаваться сигнал синхронизации, а по другой – полезная информация.
Впервые протокол I2C был предложен фирмой Phillips. Протокол в самом простом случае соединяет с помощью 2-х линий 2 устройства, одно из устройств должно быть ведущим, а другое – ведомым. Связь возможна только между ведущим и ведомым. Преимуществом протокола (интерфейса) I2C является то, что к одному ведущему можно подключить несколько ведомых.
Схема связи с помощью протокола I2C представлена на следующем рисунке.

Назначение линий данного интерфейса:
- Serial Clock (SCL): по ней передается общий сигнал синхронизации, генерируемый ведущим устройством (master);
- Serial Data (SDA): по ней осуществляется передача данных между ведущим и ведомым.
В любой момент времени только ведущий может инициировать процесс обмена данными. Поскольку в этом протоколе допускается несколько ведомых, то ведущий должен обращаться к ним, используя различные адреса. То есть только ведомый с заданным (указанным) адресом должен отвечать на сигнал ведущего, а все остальные ведомые в это время должны "хранить молчание". Таким образом, мы можем использовать одну и ту же шину (линию) для обмена данными с несколькими устройствами.
Уровни напряжений для передаваемых сигналов в интерфейсе I2C жестко не определены. В этом плане I2C является достаточно гибким, то есть если устройство запитывается от напряжения 5v, оно для связи с помощью протокола I2C может использовать уровень 5v, а если устройство запитывается от напряжения 3.3v, то оно для связи с помощью протокола I2C может использовать уровень 3v. Но что делать если с помощью данного протокола необходимо связать между собой устройства, работающие от различных питающих напряжений? В этом случае используются преобразователи/переключатели напряжения (voltage shifters).
Существует несколько условий для осуществления передачи данных в протоколе I2C. Инициализация передачи начинается с падения уровня на линии SDA, которое определяется как условие для начала передачи (‘START’ condition) на представленной ниже диаграмме. Как видно из этого рисунка, в то время как на линии SDA происходит падение уровня, в это же самое время на линии SCL ведущий поддерживает напряжение высокого уровня (high).

То есть, как следует из рисунка, падение уровня на линии SDA является аппаратным триггером для условия начала передачи. После этого все устройства на этой шине переключаются в режим прослушивания.
Аналогичным образом, повышение уровня на линии SDA останавливает передачу данных, что на представленной диаграмме обозначено как условие окончания передачи данных (‘STOP’ condition). В это же самое время ведущим на линии SCL поддерживается напряжение высокого уровня (high).
На следующем рисунке представлена структура адреса ведомого в протоколе I2C.

Бит R/W показывает направление передачи следующих за ним байт, если он установлен в HIGH – это значит что будет передавать ведомый (slave), а если он установлен в low – это значит что будет передавать ведущий (master).
Каждый бит передается в своем временном цикле, то есть нужно 8 временных циклов чтобы передать байт информации. После каждого переданного или принятого байта 9-й временной цикл используется для подтверждения/не подтверждения (ACK/NACK) приема информации. Этот бит подтверждения (ACK bit) формируется либо ведомым, либо ведущим в зависимости от ситуации. Для подтверждения приема информации (ACK) на линии SDA ведущим или ведомым устанавливается низкий уровень (low) в 9 временном цикле, в противном случае происходит не подтверждение приема информации (NACK).
На следующем рисунке представлена структура передаваемого сообщения в протоколе I2C.

Где применяется протокол I2C
Протокол I2C используется для передачи информации только на короткие расстояния. Он обеспечивает достаточно надежную передачу данных из-за наличия в нем сигнала синхронизации. Обычно данный протокол используется для передачи информации от датчиков или других устройств ведущим устройствам. В данном случае несомненным удобством использования протокола I2C является то, что при обмене данными с ведомыми устройствами ведущий микроконтроллер использует минимум линий (контактов). Если вам нужна связь на более далекие расстояния, то вам необходимо присмотреться к протоколу RS232, если же вам нужна более надежная связь чем в протоколе I2C, то вам лучше использовать протокол SPI.
Протокол I2C в Arduino
На следующем рисунке показаны контакты платы Arduino UNO, которые используются для связи по протоколу I2C.

Линия протокола I2C Контакт платы Arduino UNO SDA A4 SCL A5 Для осуществления связи по протоколу I2C в плате Arduino используется библиотека . В ней содержатся следующие функции для связи по протоколу I2C.
1. Wire.begin(address).
Эта команда производит инициализацию библиотеки Wire и осуществляет подключение к шине I2C в качестве ведущего (master) или ведомого (slave). 7-битный адрес ведомого в данной команде является опциональным и если он не указан [Wire.begin()], то устройство (плата Arduino) подключается к шине I2C в качестве ведущего (master).
2. Wire.read().
Эта функция используется для считывания байта, принятого от ведущего или ведомого.
3. Wire.write().
Эта функция используется для записи данных в устройство, являющееся ведомым или ведущим.
От ведомого ведущему (Slave to Master): ведомый записывает (передает) данные ведущему когда в ведущем работает функция Wire.RequestFrom().
От ведущему ведомому (Master to Slave): в этом случае функция Wire.write() должна использоваться между вызовами функций Wire.beginTransmission() и Wire.endTransmission().
Функцию Wire.write() можно использовать в следующих вариантах:
- Wire.write(value); value - значение передаваемого одиночного байта;
- Wire.write(string) – для передачи последовательности байт;
- Wire.write(data, length); data – массив данных для передачи в виде байт, length – число байт для передачи.
4. Wire.beginTransmission(address).
Эта функция используется для начали передачи по протоколу I2C устройству с заданным адресом ведомого (slave address). После этого вызывается функция Wire.write() с заданной последовательностью байт для передачи, а после нее функция endTransmission() для завершения процесса передачи.
5. Wire.endTransmission().
Эта функция используется для завершения процесса передачи ведомому устройству, который до этого был инициирован функциями beginTransmission() и Wire.write().
6. Wire.onRequest().
Эта функция вызывается когда ведущий запрашивает данные с помощью функции Wire.requestFrom() от ведомого устройства. В этом случае мы можем использовать функцию Wire.write() для передачи данных ведущему.
7. Wire.onReceive().
Эта функция вызывается когда ведомое устройство получает данные от ведущего. В этом случае мы можем использовать функцию Wire.read() для считывания данных передаваемых ведущим.
8. Wire.requestFrom(address,quantity).
Эта функция используется в ведущем устройстве чтобы запросить байты (данные) с ведомого устройства. После этого используется функция Wire.read() чтобы принять данные переданные ведомым устройством.
address: 7-битный адрес устройства, с которого запрашиваются байты (данные).
quantity: число запрашиваемых байт.Необходимые компоненты
- Плата Arduino Uno – 2 шт. (купить на AliExpress).
- ЖК дисплей 16х2 – 2 шт. (купить на AliExpress).
- Потенциометр 10 кОм – 4 шт. (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Работа схемы
Схема проекта по применению интерфейса I2C в плате Arduino представлена на следующем рисунке.

Для демонстрации возможностей использования связи по протоколу I2C мы использовали две платы Arduino Uno с подключенными к ним ЖК дисплеями и потенциометрами. С помощью потенциометров будут определяться значения, передаваемые между платами в направлениях ведущий-ведомый и ведомый-ведущий.
Мы будем считывать аналоговое значение напряжения, подаваемое на контакт A0 платы Arduino с помощью потенциометра и преобразовывать его в цифровое значение в диапазоне от 0 до 1023 (с помощью АЦП на этом контакте). В дальнейшем эти значения с выхода АЦП (аналогово-цифрового преобразователя) будут преобразовываться в диапазон 0-127 поскольку мы можем передавать только 7-битные данные при помощи протокола I2C. Интерфейс I2C мы будем использовать на выделенных для него в плате Arduino контактах A4 и A5.
Значения на ЖК дисплее, подключенном к ведомой плате Arduino, будут изменяться в зависимости от положения потенциометра на ведущей стороне и наоборот.

Объяснение программ для Arduino
Нам будут необходимы две программы – одна для ведущей платы Arduino, а другая – для ведомой. Полные тексты обоих программ приведены в конце статьи, здесь же мы рассмотрим их основные фрагменты.
Объяснение программы для ведущей (Master) платы Arduino
1. Первым делом в программе мы должны подключить библиотеку Wire для задействования возможностей протокола I2C и библиотеку для работы с ЖК дисплеем. Также нам необходимо сообщить плате Arduino к каким ее контактам подключен ЖК дисплей.