Как работает протокол I2C в Arduino. Какие выводы используются для I2C. Как настроить обмен данными между устройствами по I2C. Пример программы для обмена данными между двумя Arduino по I2C.
Что такое шина I2C и как она работает
I2C (Inter-Integrated Circuit) — это последовательный протокол связи, разработанный компанией Philips для обмена данными между микроконтроллерами и периферийными устройствами на коротких расстояниях. Основные особенности I2C:
- Использует всего 2 линии связи — SDA (данные) и SCL (тактирование)
- Поддерживает подключение множества устройств к одной шине
- Имеет систему адресации устройств
- Обеспечивает скорость передачи до 3,4 Мбит/с
Протокол I2C работает по принципу «ведущий-ведомый» (master-slave). Ведущее устройство инициирует обмен данными и генерирует тактовые импульсы. Ведомые устройства отвечают на запросы ведущего.
Аппаратная реализация I2C в Arduino
В платах Arduino для работы с I2C используются следующие выводы:
- SDA — линия данных (A4 в Arduino Uno)
- SCL — линия тактирования (A5 в Arduino Uno)
Эти линии подтягиваются к питанию через резисторы 4.7 кОм. Для работы с I2C в Arduino используется библиотека Wire.
Настройка обмена данными по I2C
Для использования I2C в Arduino необходимо:
- Подключить библиотеку Wire.h
- Инициализировать шину I2C с помощью Wire.begin()
- Для ведущего устройства — использовать методы Wire.beginTransmission() и Wire.endTransmission() для отправки данных
- Для ведомого устройства — установить адрес и обработчик получения данных
Пример обмена данными между двумя Arduino по I2C
Рассмотрим пример, в котором одна плата Arduino отправляет данные, а вторая их принимает по шине I2C.
Код для ведущего устройства (отправитель):
«`cpp #includeКод для ведомого устройства (приемник):
«`cpp #includeВ этом примере ведущее устройство каждую секунду отправляет строку «Hello Slave» по шине I2C. Ведомое устройство принимает эти данные и выводит их в Serial-порт.
Преимущества использования I2C в Arduino проектах
Использование I2C в проектах на Arduino дает ряд преимуществ:
- Простота подключения — требуется всего 2 провода
- Возможность подключения множества устройств к одной шине
- Наличие готовых библиотек для работы с различными I2C устройствами
- Достаточно высокая скорость обмена данными
- Поддержка на аппаратном уровне во многих микроконтроллерах
Это делает I2C удобным выбором для проектов, где требуется обмен данными между несколькими устройствами.
Типичные проблемы при работе с I2C и их решение
При работе с I2C могут возникать некоторые сложности. Рассмотрим наиболее распространенные из них:
Конфликт адресов устройств
Если на шине I2C окажутся два устройства с одинаковым адресом, возникнет конфликт. Как этого избежать.
- Проверяйте адреса всех устройств перед подключением
- Используйте устройства с настраиваемыми адресами
- Применяйте I2C мультиплексоры для разделения устройств с одинаковыми адресами
Проблемы с подтягивающими резисторами
Для надежной работы I2C требуются подтягивающие резисторы на линиях SDA и SCL. Что делать, если с ними возникли проблемы.
- Проверьте наличие и номинал подтягивающих резисторов
- Для длинных линий может потребоваться уменьшение номинала резисторов
- При использовании нескольких устройств с встроенными подтягивающими резисторами может потребоваться отключение лишних
Несогласованность скоростей устройств
Если одно из устройств на шине I2C не поддерживает выбранную скорость, могут возникнуть ошибки связи. Как это исправить.
- Проверьте максимальную поддерживаемую скорость для всех устройств
- Установите скорость шины равной минимальной из поддерживаемых всеми устройствами
- Используйте команду Wire.setClock() для настройки скорости шины
Расширенные возможности I2C в Arduino
Помимо базового функционала, I2C в Arduino предоставляет ряд расширенных возможностей:
Прерывания по событиям I2C
Arduino позволяет использовать прерывания для обработки событий I2C, что упрощает асинхронный обмен данными. Как это реализовать.
- Используйте функцию Wire.onReceive() для назначения обработчика получения данных
- Применяйте Wire.onRequest() для обработки запросов данных от ведущего устройства
Использование нескольких шин I2C
Некоторые платы Arduino позволяют использовать несколько шин I2C одновременно. Это полезно при работе с большим количеством устройств или для разделения устройств с конфликтующими адресами.
Работа в режиме ведомого устройства
Arduino может работать не только как ведущее, но и как ведомое устройство на шине I2C. Это позволяет создавать сложные системы с несколькими микроконтроллерами.
Заключение
Шина I2C предоставляет удобный и гибкий способ организации обмена данными между устройствами в проектах на Arduino. Понимание принципов работы I2C и умение эффективно использовать этот протокол значительно расширяет возможности при разработке электронных устройств.
Шина i2c arduino в категории «Телекоммуникации и связь»
SunFounder IIC I2C TWI Serial 2004 20 x 4 Pantalla LCD совместимый с Arduino R3 Mega2560
Доставка по Украине
по 342 грн
от 2 продавцов
380 грн
Купить
Шина I2C в радиотехнических конструкциях
Доставка по Украине
345 — 375 грн
от 4 продавцов
345 грн
Купить
LCD модуль интерфейса I2C IIC SPI для экрана 1602 Arduino
На складе в г. Вознесенск
Доставка по Украине
35 грн
Купить
Вознесенск
Серво контроллер / драйвер 16-канальный 12-разрядный интерфейс PWM/Servo Driver-I2C Модуль PCA9685 Arduino
На складе в г. Винница
Доставка по Украине
200 грн
Купить
Винница
I2C модуль LCD дисплея 1602, 2004 на PCF8574AT, Arduino
Доставка по Украине
23 грн
Купить
Модуль IIC/I2C для дисплеев LCD 1602 Arduino
Доставка из г. Ровно
56.50 грн
Купить
Датчик температуры и влажности SI7021 (GY-21, HTU21, Arduino, I2C)
Под заказ
Доставка по Украине
90 грн
Купить
Винница
Двунаправленный конвертер IIC I2C 5V-3.3V для Arduino
Доставка из г. Днепр
14.80 грн
Купить
Адаптер для LCD1602 по I2C Arduino AVR PIC [#G-9]
На складе в г. Запорожье
Доставка по Украине
38 грн
Купить
Запорожье
Модуль расширения I2C PCF8574 PCF8574T Arduino (15917)
На складе
Доставка по Украине
68.20 грн
Купить
Датчик температуры и влажности SI7021 (Arduino, I2C) [#7-2]
На складе в г. Запорожье
Доставка по Украине
85 грн
Купить
Запорожье
Шина I2C в радиотехнических конструкциях
Под заказ
Доставка по Украине
540 — 560 грн
от 2 продавцов
540 грн
Купить
Индикатор LED 4-разрядный I2C драйвер TM1637 Arduino (15344)
На складе
Доставка по Украине
63. 80 грн
Купить
Шины Hankook Winter I*Cept evo2 SUV W320C 255/50 R19 107V RunFlat XL Венгрия 2022 (зима)
Доставка по Украине
6 542 грн
Купить
Чотириканальний перетворювач логічного рівня IIC I2C двонаправлений модуль від 5 до 3,3 B для Arduino
Доставка из г. Кропивницкий
15 грн
Купить
Кропивницкий
Смотрите также
OLED дисплей 1.3″ I2C (синий) 128х64
Доставка по Украине
189 грн
Купить
Датчик температуры температури і вологості SHT31-D, I2C
На складе в г. Умань
Доставка по Украине
160 грн
Купить
I2C модуль LCD дисплея 1602, 2004 на PCF8574AT, Arduino
Доставка по Украине
23 грн
Купить
Цифровий датчик струму та напруги на MCU-219 INA219 з шиною I2C
Доставка по Украине
100 грн
Купить
Плата расширения для Ардуино PWM servo с I2C управлением на PCA9685PW
На складе в г. Киев
Доставка по Украине
199 грн
438 грн
Купить
PCF8574 Преобразователь I2C интерфейса в LCD1602
На складе в г. Киев
Доставка по Украине
60 грн
251 грн
Купить
Плата IIC I2C TWI SP I интерфейс, модуль Arduino
На складе в г. Умань
Доставка по Украине
38 грн
Купить
LCD 2004 для Arduino, ЖК дисплей, 20х4 (без i2c модуля)
На складе в г. Умань
Доставка по Украине
200 грн
Купить
LCD 1602 для Arduino, ЖК дисплей c синей подсветкой (без i2c модуля)
На складе в г. Умань
Доставка по Украине
87 грн
Купить
LCD 12864 графический ЖК-дисплей модуль для Arduino (без i2c модуля)
На складе в г. Умань
Доставка по Украине
298 грн
Купить
Зимние шины Hankook Winter I*Cept Evo2 W320C SUV 255/50 R19 107V XL FR HRS
Заканчивается
Доставка по Украине
7 258 грн
Купить
Перехідник для LCD HD44780 IIC I2C Arduino AVR PIC
Доставка по Украине
80. 90 грн
Купить
16 канальний 12-bit PWM/Servo Shield Arduino I2C інтерфейс від Adafruit
Доставка по Украине
731.50 грн
Купить
LED индикатор I2C драйвер TM1637 4-разрядный Arduino (12512)
На складе
Доставка по Украине
59.40 грн
Купить
Шина I2C: принципы функционирования или зачем ещё тут нужны какие-то резисторы?
Добрый день, уважаемый читатель! Некоторое время назад я начал сочинительствовать на тему работы с шиной I2C с использованием фреймворка ESP-IDF. И она таки будет, но немного позже. Но вовремя сообразил, что придется отталкиваться от принципов функционирования данной шины, про которые я ещё не рассказывал. Поэтому решил отложить статью ESP-IDF + I2C в несколько более долгий ящик, а написать другую статью, на которую буду ссылаться впоследствии.
Принципы работы шины IIC (она же имеет более устоявшееся имя как I2C) не зависят от программной реализации, поэтому данная статья может быть полезна как программистам ESP-IDF, так и фанатам Arduino. Да и вообще всем, кто хочет понять как функционирует шина, зачем нужны какие-то резисторы, и как и в каком порядке улетают байты и биты по проводкам.
Статей на данную тему можно найти предостаточно, но я все-таки рискну написать ещё одну, авось вам понравится.
Немного теории
Интерфейс I2C (или по другому IIC) — это широко распространённый двухпроводный сетевой последовательный интерфейс, придуманный фирмой Philips более 30 лет назад и завоевавший популярность относительно высокой скоростью передачи данных (обычно до 100 кбит/с, в современных микросхемах до 400 кбит/с), дешевизной и простотой реализации.
Любое устройство на шине I2C может быть одного из двух типов: master (ведущий) или slave (ведомый). Как правило на шине только один master и одно или несколько slave-устройств, хотя это не строго обязательно – вполне можно иметь несколько мастеровых одновременно. Обмен данными происходит сеансами, которыми полностью управляет master: “начинает разговор”, “вызывает” нужного slave по его адресу и затем “дает ему слово”, если это требуется. Все ведомые устройства имеют уникальный номер – адрес, даже если такое устройство на всю сеть одно. Мастер номера не имеет. Ведомые молчат, слушают, что говорит ведущий и откликаются только тогда, когда ведущий их об этом напрямую просит, называя их по адресу, поэтому в сети всегда царит образцовый порядок (ну почти).
I2C позволяет подключать к одной шине до 127 slave-устройств одновременно, не используя дополнительного оборудования (если не считать двух подтягивающих резисторов), обращаясь к ним по 7-битному адресу (в некоторых реализациях адрес может быть и 10-битным, но это не наш случай). Но адреса slave-устройств на шине зачастую изменить нельзя, поэтому подключить к одной шине несколько однотипных устройств бывает сложно.
Картинка заимствована из статьи: https://3d-diy.ru/wiki/arduino-moduli/interfeys-peredachi-dannykh-i2c/. Не вижу смысла рисовать аналогичную, это лучшая иллюстрация в данном случае
Физическая реализация
Физически шина состоит из двух проводников (или линий):
- SCL или CLOCK (Serial CLock или Signal CLock) – эта линия (провод) служит для тактирования, то есть для управления передачей данных и согласования всех устройств между собой.
- SDA или DATA (Serial DAta или Signal DAta) – как и следует из названия, по этому проводу собственно и передаются данные.
Строго говоря, необходим как минимум ещё и третий провод — общий (или земля), но интерфейс принято называть двухпроводным по количеству сигнальных проводов. Да и питание на периферийные устройства зачастую подается с того же источника, что и на микроконтроллер, поэтому физически шина I2C может быть трехпроводной (без питания) или четырехпроводной (с питанием).
Все устройства I2C имеют сигнальные выводы с “открытым коллектором” или “открытом стоком” (в зависимости от реализации). Когда выходной транзистор закрыт — на соответствующей линии через внешний подтягивающий резистор устанавливается высокий уровень, когда выходной транзистор открыт — он притягивает соответствующую линию к земле и на ней устанавливается низкий уровень (смотрите рисунок). Поэтому наличие подтягивающих резисторов на линиях SDA и SCL строго обязательно, иначе высокий уровень в сигнальных линиях “сам собой” не появится.
Источник: https://radiohlam.ru/i2c/
Подтягивающие резисторы должны быть подключены к той линии питания, на напряжение которой рассчитаны GPIO используемого микроконтроллера и подключенных устройств
. Обычно это +5В или +3,3В, в зависимости от используемого микроконтроллера. Например для ESP32 и ESP8266 нельзя подключать подтягивающие резисторы к шине питания +5В, так как их GPIO рассчитаны на напряжение не более чем 3,7В, и это может привести к физическому повреждению микроконтроллера. Подробнее об согласовании уровней поговорим чуть ниже.Используемые выводы
На разных МК (микроконтроллерах, он же MCU), выводы шины I2C могут быть разными. В качестве ориентира можно использовать следующую таблицу (источник: enjoyneering):
Плата | SDA | SCL | Питание |
Arduino Uno, Mini, Pro, ATmega168, ATmega328 | A4 | A5 | 5в |
Arduino Mega2560 | 20 | 21 | 5в |
Arduino Due, SAM3X8E | 21 | 3. 3в | |
Arduino Leonardo, Micro, ATmega32U4 | 2 | 3 | 5в |
Digistump, Trinket, ATtiny85 | PB0 | PB2 | 5в |
Blue Pill, STM32F103xxxx boards | PB9/PB7 (1) | PB8/PB6 (1) | 3.3в / 5в |
ESP8266 ESP-01 | GPIO0 (2) | GPIO2 (2) | 3.3в / 5в |
ESP8266 NodeMCU 1.0, ESP8266 WeMos D1 Mini | GPIO4/D2 | GPIO5/D1 | 3.3в |
ESP32 (Arduino framework) | GPIO21/D21 (3) | GPIO22/D22 (3) | 3.3в |
Примечания:
- Аппаратный I2C, сопоставленный с 1-Wire в stm32duino, см. https://github. com/stm32duino/wiki/wiki/API#i2c
- Большинство плат имеют подтягивающий резистор 10 кОм … 12 кОм на GPIO0/D3, GPIO2/D4/LED и подтягивающий резистор на GPIO15/D8 для прошивки и загрузки
- Только для Arduino. Для ESP-IDF выводы GPIO могут быть любыми, кроме того, можно использовать одновременно сразу две отдельные программные шины (#0 и #1).
Что хорошо при работе с данной шиной – на два вывода GPIO можно “повесить” целую гирлянду датчиков или других устройств и, тем самым, освободить кучу драгоценных GPIO.
Как выбрать номинал подтягивающего резистора
Подтягивающие резисторы должны иметь номинал от нескольких килоОм до нескольких десятков килоОм. Чем меньше номинал (сопротивление) резисторов – тем больше ток в сигнальных линиях, больше помехозащищенность шины, выше скорость передачи данных. Но, соответственно выше общее энергопотребление устройства, что может быть важно при батарейном (автономном) питании.
На многочисленных схемах в интернете можно найти рекомендации устанавливать резисторы 4,7кОм, 5,1кОм и даже 10кОм. Так какой же выбрать? Давайте посчитаем. Воспользуемся банальным законом Ома.
Для микроконтроллеров, рассчитанных на напряжение 5В, максимальная сила тока в линиях SDA и SCL при подтяжке к земле через транзисторы любого устройства составит:
- для 10 кОм – 5 / 10000 = 0,0005А или 0,5мА или 500мкА
- для 4,7 кОм – 5 / 4700 = ~0,00106А или 1мА
Между тем, рекомендованный ток подтяжки, по некоторым данным и даташитам, составляет от 1-3 мA (standard and fast mode). То есть при резисторах 10кОм мы получаем ток подтяжки в 2 раза меньше рекомендованного, при 4,7кОм – рекомендованный.
Будет работать? Конечно будет!
Повторюсь, это расчетная максимальная величина, на деле ток будет чуть ниже за счёт сопротивления канала транзистора. 500 микроампер, на мой взгляд, вполне нормальный ток для провода сравнительно небольшой длины, мало подверженного помехам.
Но при напряжении питания 3,3в, например для микроконтроллеров ESP8266 и ESP32, ток будет в ~1,5 раза ниже, то есть 330мкА (для 10 кОм) и ~700мкА (для 4,7 кОм). 330 мкА уже заметно ниже нормы. Но будет ли работать? Конечно будет! Но при небольших помехах и коротких проводах.
Дело в том, что при небольших токах в шине в дело вступает паразитная емкость между соединительными проводами. Строго говоря паразитная емкость она есть всегда, нигде она не прячется, просто при небольших токах она оказывает большее влияние на переходные процессы.
Для тока частотой 100 кГц (стандартная частота работы шины) трех- или четырхпроводный кабель, по сути, является конденсатором. Не самым банальным и простым, но все же конденсатором:
Упрощенное представление соединения между устройствами
И чем выше паразитная емкость между проводами, в том числе между сигнальными линиями и “землей” или “питанием”, тем больше тока при переключениях уровня будет “уходить впустую”, рассеиваясь в “конденсаторах”. Это приведет к тому, то крутизна фронтов и спадов импульсов будет сильно искажаться, и вместо теоретически прямоугольных импульсов мы получим нечто такое:
На самом деле здесь взята иллюстрация нормальной работы из какого-то datasheet-а. Но при больших потерях спады и фронты импульсов будут еще плавнее.
Что, конечно же, приведет к различным сбоям и помехам на шине.
Стандарт шины предусматривает общую паразитную емкость между линиями шины в стандартном режиме (100 кбит/с) не более 400 пикоФарад, а в более высокоскоростных режимах может быть и ещё меньше:
Источник: https://en.wikipedia.org/wiki/Two-wire_interface
Кроме того, возможны перекрестные наводки сигнала SCL на линию SDA и наоборот (как в банальном трансформаторе). На практике это приводит к тому, что максимальная физическая длина проводов шины I2C составляет несколько метров (без применения специальных устройств, о них ниже).
Подведем итоги. Существуют обоснованные рекомендации по выбору резисторов подтяжки в зависимости от напряжения питания, паразитной емкости и скорости работы шины:
Слева зависимость максимального сопротивления подтяжки от суммарной паразитной емкости проводов шины, справа – минимальное допустимое значение в зависимости от напряжения питания. Выбирайте значение в указанных пределах, балансируя между потребляемым током и надежностью работы.
На практике в своих устройствах я ставлю резисторы подтяжки не более 5,1кОм, так как использую в основном трехвольтовые контроллеры от Espressif. С учетом, что на некоторых шилдах сенсоров уже стоят подтягивающие резисторы 10кОм, которые в таком случае будут включены параллельно “моим” (и общее сопротивление снизится) – в самый раз.
Борьба с помехами на шине I2C
Бывают случаи, особенно когда нужно “отодвинуть” какой-либо сенсор подальше от устройства, начинают наблюдаться различные помехи и сбои – ошибки CRC (контрольной суммы при передаче), “приходят” неверные данные, устройства “не слушаются”.
В этом случае в первую очередь стоит попробовать снизить номинал подтягивающих резисторов, например до 1 кОм при 3,3В (для 3В это вполне допустимый вариант). Увеличение тока до ~ 3 мА позволит выправить крутизну импульсов за счет более быстрой перезарядки паразитной емкости и наладить работу шины. Но сильно увлекаться этим не стоит – дабы не “спалить” микроконтроллер или периферийное устройство (например сенсор). Допустимый ток через вывод GPIO для ESP32 составляет аж 40 миллиампер, но я далеко не уверен, что подключенное slave-устройство выдержит такое издевательство.
Как вариант можно попробовать снизить частоту шины, если ваше программное обеспечение это позволяет. Это уменьшит скорость передачи данных, но для чтения данных о температуры с сенсоров высокая скорость не всегда и нужна. Зато это уменьшит помехи, если они вызваны большой емкостью шины. Пробовал, в моем случае не очень сильно, но все-таки помогло. Кардинально решил заменой кабеля.
Очень важное значение может иметь кабель и расположение жил в кабеле. Например 4-проводный плоский “телефонный” кабель плохо подходит для шины I2C – особенно при расположении SDA и SCL “рядом” (например желтый и зеленый на рисунке ниже), в этом случае помехи начинаются уже от ~1 м. Для лучшей стабильности следует располагать линии SCL и SDA по краям кабеля, а внутренние жилы использовать для питания и общего провода, это позволит существенно подавить перекрестные наводки.
Я использую так: желтый – SCL, черный – SDA, красный – питание, зеленый – общий
Как ни странно, обычная 8-проводная “витая пара” (так называемый UTP-кабель) на практике довольно хорошо подходит для подключения различных I2C устройств и сенсоров, но при этом следует учитывать расположение жил в кабеле для лучшей работы! Не следует использовать одну и ту же перекрученную пару для SCL и SDA – в этом случае возникают сильные перекрестные помехи (перекрученная пара работает как трансформатор). Лучше использовать одну пару для SCL + “питание”, вторую как SDA + “земля”. Это сильно снизит перекрестные помехи и улучшит работу. Если у вас имеется кабель категории 6 (с сердечником внутри, разделяющим пары), то это даст ещё более лучшие результаты.
Если длина проводов относительно невелика, а помехи всё же присутствуют, то скорее всего причина этому – некачественный блок питания, который дает слишком сильные помехи на всё устройство, в том числе и на шину. Уменьшение резисторов тут уже ничего не дает. Попробуйте его заменить на заведомо исправный, если проблемы прекратятся – причина именно в нём.
Удлинение шины
Если нужно существенно “удлинить” шину, придется применять спецсредства – например специализированные микросхемы типа PCA9615 или P82B715. Они позволяют существенно поднять напряжение и токи внутри “физической шины” и тем самым снизить потери и помехи. Но это дается за счет очень существенного дополнительного энергопотребления, разумеется. За счет этого можно “удлинить” шину до 20 метров.
Типовая схема включения. Ток в линиях связи может достигать ~10мА. Обратите внимание на разделение проводов по парам – как раз об этом я и писал выше. Но вот подтягивать локальные SDA и SCL к 5В при трехвольтовом контроллере я б не стал. Преобразователи уровней копейки стоят
Нужно расстояние больше? Используйте сенсоры или устройства на шине RS232 или RS485, но это отдельная тема для разговора.
Подключение готовых модулей сенсоров с уже установленными резисторами подтяжки
Чаще всего в любительской практике используются I2C устройства, уже распаянные на миниплатах – модулях. Как правило, на таких модулях уже установлены резисторы подтяжки, например такие:
Плата сенсора с уже установленными резисторами 10 кОм
В этом случае резисторы рядом с MCU можно и не устанавливать. Тем более, когда вы планируете подключить к одной шине 2-3 или более устройств – в этом случае иногда придется выпаять или сдуть феном часть лишних подтягивающих резисторов с плат сенсоров. Иногда резисторы подтяжки выполнены отключаемыми, как на примере ниже, что позволяет задействовать их только при необходимости:
Здесь резисторы подтяжки 4,7кОм можно подключить или отключить с помощью капельки припоя
Сенсоры с встроенными стабилизаторами и согласователями логических уровней
При заказе сенсоров следует обращать особое внимание на то, на какое напряжение рассчитан тот или иной модуль. Почти все чипы (микросхемы) рассчитаны на напряжение питания не выше 3,6В. Но популярные платы Arduino работают с напряжением питания 5В, поэтому подключать такие сенсоры напрямую к 5-вольтовой логике нельзя. Для решения этой проблемы китайцы наладили выпуск пятивольтовых модулей с встроенным стабилизатором и устройством согласования уровней, например таких:
Две версии модуля с BME280 – маленькая 5В и большая 3.3В
В этом случае на плату (шилд) дополнительно устанавливается стабилизатор, который понижает напряжение питания для сенсора до положенных 3,3В. Беда в том, что стабилизатор греется, и может вносить погрешность в данные температуры.
Но и это еще не всё! Стабилизатор понизит напряжение на выводе питания сенсора, но вот на выводах SCL и SDA по прежнему останется 5В (если ничего не предпринимать), что может привести к выводу сенсора из строя даже при корректном напряжении питания. Дабы решить эту проблему, на плату устанавливается преобразователь логических уровней на двух полевых транзисторах по следующей схеме:
Классическая схема сопряжения уровней. Источник: Яндекс Картинки
Более подробно об согласовании логических уровней советую почитать тут, очень подробно всё расписано.
Схема модуля сенсора AHT10
То есть такие сенсоры можно смело и безопасно подключать к платам Arduino, да и резисторы подтяжки на них уже имеются.
Вопрос: можно ли такой пятивольтовый шилд подключать к трехвольтовым контроллерам типа ESP8266 или ESP32?
Можно, конечно. Некоторые сенсоры, например AHTxx, только со стабилизатором и продаются. Стабилизатор, конечно, немного “просадит” напряжение питания, но это не страшно, так как большинство популярных чипов сенсоров способно работать при напряжении питания уже от 1,7В. Работать будет даже немного лучше, так как стабилизатор почти не будет греться.
Только не стоит подключать такой модуль к питанию 5В, если ваш MCU рассчитан на 3.3В! В этом случае через резисторы подтяжки ex (R3 и R4 на схеме выше) на выводы вашего контроллера поступит поданное на модуль напряжение до стабилизатора, то есть 5В, что явно не пойдет ему на пользу.
Протокол передачи данных
С “физикой” процесса, надеюсь, разобрались, теперь самое время обсудить программную сторону вопроса – каким образом данные передаются по шине. Давайте разберемся хотя бы в общих чертах, как работает протокол I2C, это поможет правильно пользоваться им, понимая, что и в каком порядке происходит в недрах устройств.
Каждый сеанс обмена начинается с подачи master-ом стартового сигнала S (иногда называемого стартовым битом или стартовым условием или командой). “Стартовый бит” — это изменение уровня на линии SDA с высокого на низкий, но только при наличии высокого уровня на линии SCL. И наоборот – изменение уровня на линии SDA с низкого на высокий при наличии высокого уровня на линии SCL является стоп-сигналом P, означающим конец сеанса связи. Все, что происходит между этими событиями, называется “сообщением”, то есть собственно и есть передача данных. Обратите внимание: переключение уровней на линии SDA во время передачи данных всегда должно происходить только при низком уровне на линии SCL.
Источник: https://3d-diy.ru/wiki/arduino-moduli/interfeys-peredachi-dannykh-i2c/
После подачи “старт-сигнала” первым делом master должен сказать, с кем он хочет пообщаться и указать, что именно он хочет — передавать данные в устройство или читать их из него. Для этого он выдаёт на шину 7-ми битный адрес slave-устройства, с которым хочет общаться, и один бит, указывающий направление передачи данных: 0 — если от master к slave или 1 — если от slave к master. Первый байт после подачи “старт-сигнала” всегда всеми воспринимается как адресация.
Структура пакета данных на шине I2C. Источник: https://3d-diy.ru/wiki/arduino-moduli/interfeys-peredachi-dannykh-i2c/
После этого все slave-устройства на шине сверяют запрошенный адрес со своим, и если адрес совпал, ответить отправкой одного единственного бита подтверждения ACK, который означает “я здесь, все хорошо”. Ответить должно только запрошенное устройство, все остальные тупо молчат. Если бит ACK не вернулся, master-устройство понимает, что запрашиваемое устройство отсутствует на шине или “ушло в глухую несознанку”.
Есть ещё бит отсутствия подтверждения NACK, который может сигнализировать об занятости устройства (например идет измерение), или о том, что получатель хочет закончить передачу или же о том, что команда, посланная master-ом, почему-то не была выполнена.
После получения подтверждения master-устройство начинает отправку порции данных в 8 бит (1 байт), называемых кадром или пакетом. Это если планировалась передача данных master -> slave. Если же master хочет получить данные, то сразу после отправки первого бита ASC он ждет первый кадр данных от slave без каких-либо задержек. В ответ принимающая сторона должна отправить бит ASC в качестве подтверждения передачи кадра. Затем идет передача следующего байта / кадра и так далее. В конце сеанса связи вместо ASC отправляется NACK.
Когда все данные успешно переданы master отправляет “стоп-бит” для завершения сеанса.
Пожалуй лучшая иллюстрация процесса, что я нашел по данной теме:
Источник: https://radiohlam.ru/i2c/
На схеме выше изображен “идеальный” вариант – только прием или только передача. На практике же чаще используется комбинированный вариант, когда мастер всегда начинает работу с режима передачи master->slave, и первым делом самолёты передаёт номер регистра, из которого он хотел бы получить данные, и затем сразу же переходит “на прием”. Ведомое же устройство, получив адрес запрашиваемого регистра, в свою очередь начинает передачу данных. Это может происходить в рамках одного сеанса связи:
- start
- address + write
- send register
- read data
- stop
Но иногда необходимо время между запросом данных из регистра и их отправкой ведомым (например на время измерения). В этом случае информация передается за два сеанса:
- start
- address + write
- send register
- stop
пауза на время измерения
- start
- address + read
- read data
- stop
В разных источниках и даташитах эти самые регистры могут называться по разному – регистр, адрес, команда и т.д. Но по сути это одно и то же.
Вот собственно и всё, о чем я хотел вам поведать, прежде чем рассказывать о работе с шиной I2C из ESP-IDF. До встречи на сайте и на dzen-канале!
Как использовать связь I2C на Arduino? Arduino I2C Tutorial
В этом руководстве мы увидим, как настроить и использовать связь I2C на Arduino. В этом руководстве по Arduino I2C объясняются выводы I2C в Arduino, настройка главного и подчиненного устройств и, наконец, простая демонстрация, в которой две платы Arduino UNO обмениваются данными через I2C.
Схема
Что такое I2C?
I2C или I 2 C — это сокращение от Inter-Integrated Circuit, протокола синхронной последовательной связи, разработанного Phillips для связи между быстрым микроконтроллером и относительно медленными периферийными устройствами (такими как память или датчики) с использованием всего двух проводов. Следовательно, его иногда также называют TWI (двухпроводной интерфейс).
Используя I2C, вы можете передавать данные со скоростью 100 кбит/с (тактовая частота 100 кГц — стандартный режим), 400 кбит/с (тактовая частота 400 кГц — быстрый режим), 1 Мбит/с (тактовая частота 1 МГц — быстрый режим Plus) и 3,4 Мбит/с (тактовая частота 3,4 МГц — режим высокой скорости).
Это может показаться немного, но этого достаточно для сопряжения датчиков, памяти и дисплеев на небольших расстояниях.
Шина I2C
Шина I2C состоит из двух проводов, называемых последовательными данными (SDA) и последовательными часами (SCL). Данные передаются по линии SDA, а линия SCL используется для синхронизации устройств с тактовым сигналом.
Обе эти линии шины являются драйверами с открытым стоком, и поэтому вы должны использовать подтягивающие резисторы, чтобы поддерживать их ВЫСОКИЙ уровень.
Существует два типа устройств, которые подключаются к шине I2C: Master и Slave. Мастера шины отвечают за отправку и получение данных на ведомые устройства и с них. Тактовый сигнал также подается мастером.
Сеть I2C поддерживает несколько мастеров и несколько ведомых (но обычно мы видим одного ведущего и несколько ведомых). Каждое ведомое устройство, подключенное к шине I2C, имеет уникальный 7-битный адрес.
Используя этот адрес, ведущее устройство выбирает конкретное ведомое устройство для передачи данных (отправки или получения), и выбранное ведомое устройство отвечает в соответствии с запросом.
Я сделал подробное руководство по основам I 2 C Связь. Для получения дополнительной информации посетите « Основы связи I2C ».
I2C в Arduino
Arduino поддерживает связь I2C. Если вы посмотрите на распиновку Arduino UNO из руководства « ARDUINO UNO PINOUT », вы увидите, что контакты аналогового входа A4 и A5 имеют альтернативную функцию I2C.
Контакт A4 действует как SDA, а контакт A5 действует как SCL. В R3 оригинальной Arduino UNO есть еще два контакта рядом с выводом 13 цифрового ввода-вывода (рядом с разъемом USB), предназначенными для SDA и SCL.
Если вы используете любую другую плату, вам будет полезна следующая таблица, так как в ней описаны выводы I2C на всех популярных платах Arduino.
Доска | Контакты SDA и SCL |
Ардуино УНО | А4 и А5 |
Ардуино Нано | А4 и А5 |
Ардуино Мега 2560 | 20 и 21 |
Ардуино Микро | 2 и 3 |
Ардуино Леонардо | 2 и 3 |
Микроконтроллер ATmega328P, используемый в Arduino UNO и Nano, поддерживает скорость передачи данных I2C до 400 кГц.
Как использовать интерфейс Arduino I2C?
Чтобы продемонстрировать работу I2C в Arduino, давайте создадим небольшую схему. В этой демонстрации я соединил две платы Arduino UNO для связи по шине I2C. Чтобы сделать все интереснее и на самом деле увидеть связь, я добавил пару светодиодов и потенциометров (по одному набору для каждой платы UNO).
Потенциометры подключены к соответствующим контактам аналогового входа (A0), а светодиоды подключены к контакту цифрового ввода-вывода с ШИМ (контакт 9). Одна плата UNO настроена как ведущая шина I2C, а другая UNO настроена как ведомое устройство.
Когда я настраиваю потенциометр, подключенный к Master Arduino UNO, он захватывает аналоговое показание с POT, преобразует его в цифровое значение (в диапазоне 0–1023), сопоставляет его с правильным значением ШИМ (в диапазон от 0 до 255) и передает это значение на ведомое устройство Arduino по шине I2C.
Подчиненное устройство Arduino, получив значение ШИМ, регулирует яркость своего светодиода. Кроме того, ведомая плата Arduino отправляет значение собственного потенциометра, преобразованное в число ШИМ, в ведущую плату Arduino (по запросу ведущей).
Мастер Arduino затем считывает значение ШИМ с ведомого устройства Arduino и регулирует яркость своего светодиода в соответствии с этим значением. Эта связь продолжается и беспрепятственно повторяется по шине I2C.
Это простая схема для понимания коммуникации Arduino I2C. Вы можете изменить схему, чтобы создать сложную шинную сеть I2C с различными ведомыми устройствами, такими как ЖК-дисплей I2C, микросхема EEPROM, датчик атмосферного давления BMP180 и т. д. (метеостанция с регистрацией данных).
Необходимые компоненты
- Arduino UNO x 2
- Потенциометр 10 кОм x 2
- Светодиод 5 мм x 2
- Резистор 330 Ом x 2
- Макет
- Соединительные провода
- Блок питания макетной платы (дополнительно)
Принципиальная схема
На следующем изображении показана принципиальная схема для демонстрации Arduino I2C между двумя платами Arduino UNO.
Код
Чтобы запрограммировать периферийное устройство I2C в Arduino, вам необходимо разобраться в библиотеке Wire. Это основная библиотека, которая позволяет вам взаимодействовать с устройствами I2C или TWI через шину I2C (линии SDA и SCL).
Wire Library
Он поставляется с Arduino IDE, и вам не нужно ничего загружать дополнительно. Все, что вам нужно сделать, это включить библиотеку Wire для работы с I2C в Arduino.
#include
Библиотека Wire предоставляет вам 10 функций для разработки приложений, связанных с I2C. Это:
- Wire.begin()
- Wire.requestFrom()
- Wire.beginTransmission()
- Wire.endTransmission()
- Wire.write()
- Провод.доступный()
- Wire. read()
- Wire.SetClock()
- Wire.onReceive()
- Wire.onRequest()
Теперь давайте подробно рассмотрим некоторые важные функции Wire Library.
Функции библиотеки проводов
Wire.begin()
Используйте эту функцию для запуска связи I2C. Если вы передадите 7-битный адрес устройства в качестве аргумента этой функции, то устройство присоединится к шине I2C как ведомое, иначе оно присоединится как ведущее.
- Wire.begin() — Мастер
- Wire.begin(адрес) – Ведомый
Wire.beginTransmission(address)
Используйте эту функцию, чтобы начать передачу данных на ведомое устройство с указанным адресом.
Wire.write()
Как только вы начнете передачу с помощью вышеуказанной функции, вы можете начать отправку фактических данных с помощью функции Wire. write().
Вы также можете использовать эту функцию для записи данных от ведомого устройства к ведущему, когда ведущее устройство использует функцию Wire.RequestFrom().
- Wire.write(value) — Отправить однобайтовое значение
- Wire.write(string) — Отправить серию байтов в виде строки
- Wire.write(data, length) — Отправить массив данных указанной длины
Wire.endTransmission()
Чтобы завершить передачу данных I2C, используйте функцию Wire.endTransmission().
Wire.read()
Используйте эту функцию для чтения байта данных, которые были переданы от ведущего к ведомому или от ведомого к ведущему, когда мастер вызывает функцию Wire.requestFrom().
Wire.requestFrom()
Ведущее устройство I2C использует эту функцию для запроса байтов данных от ведомого устройства. Используйте функцию Wire.read() для получения данных.
- Wire.requestFrom(адрес, количество) – Запрос количества байтов данных, указанных количеством, от ведомого устройства с адресом, указанным в поле адреса.
Wire.onReceive()
Это функция-обработчик, используемая для определения функции, которая вызывается, когда ведомое устройство получает данные от ведущего устройства.
Wire.onRequest()
Это функция-обработчик, используемая для определения функции, которая вызывается, когда мастер запрашивает данные у ведомого.
Master Code
Используя вышеупомянутые функции, я написал простой код для Master Arduino, чтобы отправить значение PWM, а также запросить байт данных от Slave.
Код ведомого устройства
В коде ведомого устройства Arduino я определил адрес ведомого устройства как 0x14. Это может быть любое значение меньше 128. Важно отметить, что в ArduinoI2C Wire Library I используется 7-битный адрес I2C без бита чтения/записи.
Итак, если у вас есть 8-битный адрес (который включает в себя бит R/W), сдвиньте адрес вправо на 1 и затем используйте его в Wire Library. Библиотека автоматически изменит адрес в зависимости от операции чтения или записи.
Кроме того, убедитесь, что адрес ведомого устройства уникален и никакие два ведомых устройства не должны иметь одинаковый адрес.
Возвращаясь к коду, я объявил две функции «DataReceive» и «DataRequest», которые будут вызываться при получении данных ведомым устройством или при запросе данных от ведомого устройства. Данные, полученные Ведомым в функции DataReceive, содержат значение ШИМ, отправленное Ведущим.
Данные, которые должны быть переданы через функцию DataRequest, представляют собой значение ШИМ от ведомого к ведущему.
Заключение
В этом руководстве демонстрируется простая двусторонняя связь между двумя платами Arduino с использованием связи I2C. Вы узнали о периферийном устройстве Arduino I2C, нескольких важных основах связи I2C, библиотеке проводов, а также о том, как настроить и использовать связь Arduino I2c.
Сколько устройств можно подключить к шине I2C?
- Учебники
- Сколько устройств можно подключить к шине I2C?
Если вы когда-либо задавали этот вопрос на любом дискуссионном форуме для пользователей Arduino, энтузиастов электроники и коллег-инженеров, вы получите такие ответы:
· «У вас 7-битный адрес. Это означает, что вы можете адресовать до 127 ведомых устройств.»
· «Количество устройств, подключенных к шине, ограничено только общей допустимой емкостью шины 400 пФ.»
· «Короткий ответ: это зависит!»
Что ж, спасибо Интернету! Я уже чувствую себя умнее! А если серьезно, сколько датчиков я могу подключить к своей Arduino с помощью шины I2C?
Последний ответ был, несмотря на то, что он был самым раздражающим, возможно, самым правильным, но только потому, что вопрос был таким расплывчатым! Итак, попробуем перефразировать этот вопрос. Когда вы говорите «датчик», вы имеете в виду датчик, установленный на коммутационной плате? Да? Теперь это имеет огромное значение! Итак, вопрос теперь становится: сколько коммутационных плат можно подключить к шине I2C?
Эту проблему решить намного проще, и, к сожалению, ответ намного меньше, чем 127.
Да, мы кратко рассмотрим основы шины I2C. Но нам не нужно копать слишком глубоко, чтобы ответить на наш вопрос.
Давайте представим, что этот ужасный беспорядок волнистых линий — устройство с четырьмя контактами. Помимо контакта VCC для подачи питания на ваше устройство и контакта GND для выполнения независимо от того, что делают выводы заземления, у вас также есть вывод SDA или последовательных данных и SCL или вывод последовательных часов.
Возможно, вы заметили, что контакты SDA и SCL подключены к земле через переключатель внутри устройства. Это, конечно, очень просто представление. Когда вы соединяете два устройства друг с другом с помощью шины I2C, вам просто нужно соединить вывод VCC одного устройства с выводом VCC другого устройства и выполнить то же самое с выводами SDA, SCL и GND. Ну вы только посмотрите на красивую картинку!
Одно из устройств возьмет на себя роль Мастера. Это означает, что он будет отвечать за генерацию тактового сигнала на линии SCL и использовать SDA. строка для отправки команд ведомому. Ведомый, с другой стороны, использует линию SDA для отправки данных обратно ведущему. В большинстве случаев Arduino будет ведущим устройством, в то время как любое другое устройство управляемый Arduino, как и датчик, будет действовать как Slave.
Но мы еще не закончили! Для работы шины I2C нам необходимо подключить один резистор между линией VCC и линией SDA, а также еще один резистор между Линия VCC и линия SCL. Они называются подтягивающими резисторами.
Как это выглядит, если у нас есть более одного ведомого устройства, то есть более одного датчика, подключенного к Arduino? Ну, в этом случае у вас все равно был бы один резистор к линии SDA и еще один к линии SCL. Неважно, подключен ли к Arduino только один датчик или пятьдесят датчиков, вам нужен только один резистор на линии SCL и один резистор. по линии ПДД.
Но почему? Зачем вообще нужен резистор? И почему меня это должно волновать? Что ж, как вы уже могли догадаться, одна из основных проблем, вызванных подключение нескольких коммутационных плат на платах I2C вызвано подтягивающими резисторами.
Чтобы понять это, давайте посмотрим, как формируется цифровой сигнал, например, на линии SCL. Линия SDA работает так же, но для ясности я показываю здесь только линию SCL.
В этой схеме напряжение на линии VCC равно 5 В (или 3,3 В, в зависимости от вашего источника питания), напряжение на линии GND равно 0 В, а напряжение на SCL линия, фактически генерируемый сигнал зависит от положения переключателя.
Если переключатель разомкнут, потенциал 5 В с линии VCC также будет на линии SCL. В этом случае напряжение на линии SCL будет равно 5В, а сигнал будет интерпретироваться как логический ВЫСОКИЙ. Поскольку переключатель разомкнут, через устройство не будет протекать ток.
Если переключатель замкнут, 0 В с линии GND также будет на линии SCL, и сигнал будет интерпретироваться как логический НИЗКИЙ. Теперь у нас есть разница потенциал на резисторе, и ток будет течь через ключ.
Размыкание и замыкание переключателя генерирует хороший цифровой сигнал, варьирующийся от 0 В до 5 В.
Конечно, так выглядит идеальный цифровой сигнал, но давайте посмотрим, как выглядит реальный сигнал. Если вы подключаете один датчик, установленный на прорыве плату и подключите ее к Arduino с помощью шины I2C, у вас должно получиться что-то вроде этого:
Отлично, теперь возьмите осциллограф и измерьте сигнал на линии SCL. Что ты видишь?
Как видите, синяя линия, измеренный сигнал на линии SCL, сильно отличается от идеального цифрового сигнала. Максимальное значение немного ниже 5 В, минимальное значение немного выше 0 В, а переход напряжения с 0 В на 5 В занимает много времени. Несмотря на все это, именно так выглядит хороший сигнал!
Теперь давайте представим, что мы подключаем не одну коммутационную плату к Arduino, а несколько плат одновременно.
Как упоминалось ранее, подключение нескольких датчиков к шине I2C означает подключение контактов SCL всех плат друг к другу. Таким образом, сигнал SCL сгенерированный Arduino, используется всеми датчиками. То же самое относится к сигналу SDA, а также к источнику питания (VCC) и земле (GND). Итак, как выглядит сигнал SCL сейчас?
Новый сигнал SCL, показанный красным, больше похож на идеальный сигнал, чем раньше. Напряжение на логическом НИЗКОМ уровне теперь намного выше, чем раньше, но напряжение на логическом уровне HIGH выглядит так же, и теперь напряжение увеличивается намного быстрее от низкого уровня к высокому. Ну, это не так уж плохо, правда?
Очень неправильно! И единственной причиной является новое напряжение на логическом уровне НИЗКИЙ. Чтобы понять, насколько это плохо, вернемся к нашей первой диаграмме.
Ранее я показывал механический переключатель, подключенный между контактами SCL и GND. Но механических переключателей внутри устройства нет. Вместо этого соединение выполнено транзистором работает как коммутатор.
Включая и выключая транзистор, вы можете изменить сигнал SCL на логический НИЗКИЙ и логический ВЫСОКИЙ. Когда транзистор закрыт, сопротивление транзистора между контактами SCL и GND очень высокое, так что ток через транзистор и, следовательно, через резистор практически не течет. Напряжение на линии SCL будет очень близким до 5В, поэтому это будет интерпретироваться как ВЫСОКИЙ логический уровень.
Когда транзистор открыт, сопротивление на транзисторе становится очень маленьким, однако оно не равно нулю. Теперь через резистор течет небольшой ток. и, главное, через транзистор. Напряжение на линии SCL равно падению напряжения на транзисторе. Поскольку это падение напряжения очень близко к 0 В, сигнал SCL будет интерпретируется как логический НИЗКИЙ.
Теперь возникает большой вопрос: что произойдет, если мы уменьшим сопротивление подтягивающего резистора? Ток через резистор, естественно, увеличивается. Но такой же ток течет и через транзистор!
Больший ток через транзистор приводит к большему рассеиванию тепла внутри устройства, а перегрев является основной причиной выхода из строя полупроводниковых приборов. устройства. Зная это, Спецификация шины I2C и Пользовательский Вручную устанавливает максимум 3 мА на транзисторе. Этот ток известен как стоковой ток.
Это означает, что устройства, предназначенные для использования шины I2C, должны работать с потребляемым током 3 мА, протекающим через транзистор. Это также означает, что схема проектировщики должны учитывать это ограничение при определении размеров подтягивающих резисторов.
И как мы узнаем, превышает ли потребляемый ток в нашей цепи предел 3 мА? Что ж, увеличение стокового тока означает, что падение напряжения на транзистор тоже увеличивается. Падение напряжения на транзисторе, также известное как выходное напряжение низкого уровня, представляет собой уровень напряжения, когда сигнал имеет логический НИЗКИЙ уровень.
Спецификация шины I2C и руководство пользователя также устанавливают максимальное значение 0,4 В для выходного напряжения низкого уровня, поскольку это указывает, что максимальный потребляемый ток составляет 3 мА. течет через транзистор. Следовательно, всякий раз, когда мы измеряем сигналы SDA или SCL, а напряжение на логическом НИЗКОМ уровне выше 0,4 В, мы знаем, что ток стока слишком велик!
При максимальном токе стока 3 мА и максимальном низкоуровневом выходном напряжении 0,4 В мы можем рассчитать минимальное значение для подтягивающих резисторов. Все, что у нас есть нужно рассмотреть наихудшую ситуацию при работе в рамках спецификации. Минимальное значение для каждого подтягивающего резистора равно падению напряжения на резисторе, деленному на максимальное значение. потребляемый ток 3мА.
Для источника питания 5 В каждый подтягивающий резистор должен иметь сопротивление не менее 1,53 кОм, а для источника питания 3,3 В каждый резистор должен иметь сопротивление не менее 967 Ом.
Конечно, это не означает, что всякий раз, когда потребляемый ток превысит 3 мА, устройство немедленно перестанет работать. Но вы всегда должны быть осторожны при эксплуатации устройства за пределами его спецификации, поскольку это может привести к сбоям связи, сокращению срока его службы и даже к необратимому повреждению устройства.
Теперь вернемся к нашей проблеме: сколько коммутационных плат можно подключить к шине I2C? Не так много… Вы, наверное, уже заметили, у каждой пробивной доски есть своя пара подтягивающих резисторов. Значение этих резисторов варьируется от платы к плате, но большинство из них имеют номинал 10 кОм, 4,7 кОм или 2,2 кОм.
Когда мы соединяем несколько коммутационных плат вместе, мы фактически подключаем эти резисторы параллельно друг другу, уменьшая общее сопротивление. Даже соединение двух плат с подтягивающими резисторами 2,2 кОм уменьшит общее сопротивление до 1,1 кОм. Этого вполне достаточно для источника питания 3,3 В, но оно будет ниже минимального значения.