I2C Arduino он же TWI и IIC. Обмен даными Arduino по протоколу I2C

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

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

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

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

Arduino поддерживает много интерфейсов передачи данных, одним из которых является достаточно популярный на сегодняшний день I2C. Когда-то давно этот протокол связи придумала компания Philips и зарегистрировала под запатентованным названием “I2C”, вы также можете встретить его под названиями TWI, 2 line interface, но все они работают по единому принципу.

Весь смысл I2С шины состоит в том, что на 2 провода можно повесить большое (128) количество различных устройств, от датчиков температуры, до микроконтроллеров.

Но в тоже время по скорости I2C уступает UART и SPI , из-за основных принципов работы, т.к. две линии всегда подтянуты к резисторам(Vcc), а значит на графике мы получаем не прямоугольные импульсы, а трапециевидные, в отличие от вышеупомянутых.

SDA - отвечает за передачу информации(начало передачи, адрес, данные)
SCL - тактирование шины

В I2C устройства могут быть двух типов Master и Slave

Теперь разберём основные принципы программирования с помощью стандартной библиотеки Wire.h:

Wire.begin(uint8_t address) - используется для инициализации устройства, в режиме слейва нужно ввести адрес, в режиме мастера Wire.begin() . Вместо Wire можно использовать любое другое слово.

Wire.requestFrom(uint8_t address, uint8_t quantity) – запрос на получения какого-то количества байт от определенного устройства(7 бит адрес). Возвращает число считанных байт.

Wire.beginTransmission(uint8_t address)- начало передачи

Wire.endTransmission()- конец передачи,возвращает номер ошибки или успех(0)

Wire.write(uint8_t data) –может принимать значение одиночного байта(value), нескольких байт(string), массива, определенной длинны (data, lenght). Располагается между: beginTransmission и endTransmission. Возращает число записанных байт.

Wire.available() – возвращает количество байт доступных для обработки. Вызывается мастером после requestFrom.

Wire.read() – считывает байт от ведомого устройства. Пишется после requestFrom.

Подключение библиотек к Ардуино IDE не представляет сложности, так как поставляется в комплекте со стандартным редактором.

Есть еще несколько функций, но думаю для начала этой основы вполне достаточно, к тому же почти на любую периферию можно найти библиотеку.

Для примера рассмотрим подключение и работу акселерометра и гироскопа Gy-521.

Подключаем согласно схеме (подтягивающие резисторы встроены в модуль):

Модуль может работать как от 3.3 вольт, так и от 5.

#include // подключаем библиотеку работы с i2c интерфейсом const int MPU_addr = 0x68; // I2C адрес GY-521 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // переменные для записи значений void setup() { Wire.begin(); // инициализируем i2c шину Wire.beginTransmission(MPU_addr); // начало передачи Wire.write(0x6B); // записываем определенные регистры для инициализации модуля Wire.write(0); // отправляем ноль для выведения модуля из сна Wire.endTransmission(true); Serial.begin(9600); } void loop() { Wire.beginTransmission(MPU_addr); Wire.write(0x3B); // начинаем с этого регистра Wire.endTransmission(false); Wire.requestFrom(MPU_addr, 14, true); // читаем все регистры AcX = Wire.read() << 8 | Wire.read(); // 0x3B AcY = Wire.read() << 8 | Wire.read(); // 0x3D AcZ = Wire.read() << 8 | Wire.read(); // 0x3F Tmp = Wire.read() << 8 | Wire.read(); // 0x41 GyX = Wire.read() << 8 | Wire.read(); // 0x43 GyY = Wire.read() << 8 | Wire.read(); // 0x45 GyZ = Wire.read() << 8 | Wire.read(); // 0x47 Serial.print("AcX = "); Serial.print(AcX); // выводим данные в Serial Serial.print(" | AcY = "); Serial.print(AcY); Serial.print(" | AcZ = "); Serial.print(AcZ); Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); // выводим температуры по формуле Serial.print(" | GyX = "); Serial.print(GyX); Serial.print(" | GyY = "); Serial.print(GyY); Serial.print(" | GyZ = "); Serial.println(GyZ); delay(333); }

Как расширить функциональность разрабатываемой системы на основе микроконтроллера? Да, этот вопрос интересует многих схемотехников, работающими над прототипами электронных устройств. Удивительно, но добавить к системе новые блоки, не изменяя схемы, позволит шина, разработанная инженерами Philips более 30 лет назад.

Благодаря интерфейсу I2C можно превратить микроконтроллер в простой конструктор, к которому можно подключить несколько сотен микросхем. Сразу стоит отметить, что их количество ограничивается емкостью шины в 400 пФ, но это один из немногих недостатков I2C.

Схема внутренней связи – так можно расшифровать название шины, которую сегодня можно встретить практически в каждом электронном устройстве. Стоит отметить, что в Philips запатентовали столь удачное в практическом плане решение и другие производители дублировали I2C под другими названиями.

Именно эта шина устанавливается для связи с внешним миром дисплеев, камер, сотовых телефонов. Количество периферических устройств, подключаемых к устройствам с помощью I2C, вообще не поддается учету. В чем же преимущества интерфейса?

Основные достоинства и недостатки I2C

I2C – последовательная асимметричная шина для связи между интегральными схемами внутри электронных приборов. Использует две двунаправленные линии связи (SDA и SCL).

Шина представляет собой два проводника, а для управления интерфейсом достаточно одного микроконтроллера. Удивительно, но подобная простота позволяет производить отключение микросхем в процессе работы. Специальный встроенный фильтр способен справляться с всплесками, гарантируя сохранность обрабатываемой информации.

Среди недостатков I2C, кроме ограниченной емкости, сложность программирования и трудность с определением неисправности в ситуации с состоянием низкого уровня.

Изначально скорость шины была всего 100 кбит, а подключить к ней было можно всего 120 устройств. В 90-х годах стандарты изменились и скорость передачи данных увеличилась в 4 раза и появилась возможность подключения до 1000 микросхем.

Однако большинство производителей интерфейса зациклились на 400 кбит с подключением 120 устройств.

Принцип подключения и работы

Проводники шины подсоединены к плюсу резисторами 1-10к, один из проводников является шиной данных, другой – тактирование. Работает такая схема просто: на линии есть одно ведущее устройство (микроконтроллер) и несколько периферийных устройств. Так как линии запитаны на плюсе, то подключенному слейву (ведомому элементу) достаточно прижать провод к земле и передать тем самым 0.

Когда периферическое устройство отпускает провод, по проводнику передается 1. Все элементарно, но если при совместной работе один из слейвов выдал 0, то остальным подключенным к шине устройствам придется подождать. Осуществляет тактирование и передачу микроконтроллер, предварительно уточнив, свободна ли линия. Для этого передается 1 на SCL и SDA, после чего создается старт-условие – прижимается линия SDA при значении SCL равном 1.

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

При этом нужно помнить, что считывание данных осуществляется при SCL =1, а передача идет вперед старшим битом.

Первые 7 бит – адрес устройства, 8 – команда записать (0) или читать (1).

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

Даже в том случае, если подключенная микросхема медленно обрабатывает сигнал, все равно она придержит SCL.

Режим работы multi-master

Вопросы демократии в схемотехнике регламентируются . В его основе лежит способность ведущего устройства контролировать результат работы. Обязательно перепроверяется – отпущена линия или нет, если она отпустилась – то мастер на данный момент ведущий, если нет – то что-то более важное пока держит линию. В этом случае нужно подождать просвет и сделать свою работу, когда таковой появится.

Однако, вполне возможно что все ведущие устройства решать заняться делом одновременно. В этом случае первенство будет за тем мастером, который первым начал тактирование и сделал это быстро. Если два устройства будут работать сверхсинхронно, то первым победит то из них, которое сгенерирует 0 чуть быстрее оппонента.