I2c arduino подключение нескольких устройств. Давайте разберемся с самой удобной коммуникацией физически заложенной в контроллеры Arduino

Вам понадобится

  • - Arduino;
  • - цифровой потенциометр AD5171;
  • - светодиод;
  • - резистор на 220 Ом;
  • - 2 резистора на 4,7 кОм;
  • - соединительные провода.

Инструкция

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

Arduino использует для работы по интерфейсу I2C два порта. Например, в Arduino UNO и Arduino Nano аналоговый порт A4 соответствует SDA, аналоговый порт A5 соответствует SCL.
Для других моделей плат:
Arduino Pro и Pro Mini - A4 (SDA), A5 (SCL)
Arduino Mega - 20 (SDA), 21 (SCL)
Arduino Leonardo - 2 (SDA), 3 (SCL)
Arduino Due - 20 (SDA), 21 (SCL), SDA1, SCL1

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

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

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 () { }

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

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

I2C это последовательная асимметричная шина для связи между интегральными схемами внутри электронных приборов. Тоесть данный протокол связи был разработан для внутренней связи внутри коробки устройства или внутри щита. Перед ним не ставилось задание передавать данные на большие расстояния, поэтому ходит множество мифов о максимальной дальности связи - у кого-то плохо работает уже при 50см, у кого-то при 2м.

На шине I2C может сидеть до 128 устройств. Адреса от 0 до 127.

В контроллерах Arduino заложена физическая коммуникация I2C, которая позволяет по двум информационным проводам подключать к ним как различные датчики, расширители дискретных входов-выходов, цифро-аналоговые и аналого-цифровые преобразователи, так и другие контроллеры.

О скорости передачи на сайте производителя не пишут. Но по общей документации на протокол она должна составлять как минимум 100 кбит/с


Теперь хотелось бы потестировать на сколько действительно хороша шина I2C, и на сколько сложно по ней обмениваться данными между несколькими контроллерами Arduino

Я возьму три контроллера , объединю их шиной I2C, и разберусь, как по ней обмениваться данными. Первый контроллер будет выполнять роль ведущего, а остальные два - роль ведомого.

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

Ведущий контроллер будет последовательно опрашивать второго и третьего контроллера. Принятые данные первый контроллер должен выводить на индикатор. Опрос ведомых Arduino Nano будет проводиться с частотой 1 раз/сек.

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

Четыре провода от каждого из 4-х устройств нужно соединить параллельно. Вывод А4 платы Arduino Nano - это шина SDA протокола I2C, а А5 - это SCL.

Я буду использовать монтажные шилды под контроллеры Nano для удобства соединений.

Питание будет подаваться просто на один из контроллеров через mini USB вход.

У LCD адрес в сети I2C по умолчанию 27. У второго контроллера установим адрес 2 и у третьего 3. У ведущего первого контроллера адрес не нужен.

Программа контроллера - мастера.

#include #include // Set the LCD address to 0x27 for a 16 chars and 2 line display LiquidCrystal_I2C lcd(0x27, 16, 2); int nano1=0; int nano2; int nano3; void setup() { Serial.begin(9600); // initialize the LCD lcd.begin(); // Turn on the blacklight and print a message. lcd.backlight(); } void loop() { lcd.setCursor(0, 0); lcd.print(nano1); Wire.requestFrom(2, 2); // request 6 bytes from slave device #8 int i=0;nano2=0; while (Wire.available()) { // slave may send less than requested byte c = Wire.read(); // receive a byte as character Serial.print(c); if (i==0) nano2 = ((c & 0xff) << 8); else nano2 = nano2 | c; i++; } Serial.println(""); Serial.println(nano2); lcd.setCursor(9, 0); lcd.print(nano2); delay(100); Wire.requestFrom(3, 2); // request 6 bytes from slave device #8 i=0;nano3=0; while (Wire.available()) { // slave may send less than requested byte c = Wire.read(); // receive a byte as character Serial.print(c); if (i==0) nano3 = ((c & 0xff) << 8); else nano3 = nano3 | c; i++; } lcd.setCursor(0, 1); lcd.print(nano3); delay(100); nano1++; delay(800); }

Первый контроллер изменяет свою переменную типа integer и выводит ее значение на индикатор. Так же он поочереди опрашивает слейв со 2-м и 3-м адресом. Запрашивает у них два байта информации, преобразовывает их в переменную integer. В результате в первом контроллере крутятся три переменные с трёх Nano и он может вывести их на индикатор.

Программа второго контроллера

#include int nano2=0; byte high; void setup() { Wire.begin(2); // join i2c bus with address #8 Wire.onRequest(requestEvent); // register event } void loop() { delay(1000); nano2--; } // function that executes whenever data is requested by master // this function is registered as an event, see setup() void requestEvent() { high = (nano2 >>

Программа третьего Arduino Nano

#include int nano2=0; byte high; void setup() { Wire.begin(3); // join i2c bus with address #8 Wire.onRequest(requestEvent); // register event } void loop() { delay(1500); nano2--; } // function that executes whenever data is requested by master // this function is registered as an event, see setup() void requestEvent() { high = (nano2 >> 8); high = (nano2 & 0xff); Wire.write(high); // respond with message of 2 bytes Wire.write(high); }

Отличаются последние две программы просто адресом в функции Wire.begin(3); и частотой изменения переменной.

Эти программы постоянно изменяют переменную integer и ожидают запроса от мастера. При запросе эта переменная раскладывается на два байта и отправляется как ответ на запрос ведущему контроллеру.

Таким образом работу связи по I2C можно контролировать по изменяющимся значениям трех переменных на жидкокристаллическом индикаторе.

Выводы

Прекрасно все работает - цифры на дисплее меняются. Я попробовал удлиннять шлейф проводов между вторым и третьим контроллерами Arduino. Проверил работу шины связи при длине 3 м - без притензий. Длиннее не пробовал, но многие мне утверждали, что I2C не работает дальше 0,5 ... 2 м и меня воодушевила длина 3 м.

Для себя я уже вижу, где применю такую связь именно между тремя Nano.

Я здесь ещё не попробовал передачу данных от мастера слейву. Если попробуете - отпишитесь.

Недостатков здесь на небольших расстояниях ощутимо меньше чем превосходств.

С номиналами от 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.