Описание интерфейса I2C: принцип работы, протокол и применение

Содержание

Интерфейс I2C (Inter-Integrated Circuit) представляет собой популярный стандарт для синхронной, серийной передачи данных между различными компонентами внутри электронного устройства. Он был разработан компанией Philips Semiconductor (ныне NXP Semiconductors) в 1982 году и нашел широкое применение в различных областях электроники благодаря своей простоте и гибкости.

Принцип работы I2C

Принцип работы I2C основан на двухпроводной схеме, которая включает в себя:

  1. SDA (Serial Data Line) — линия данных, по которой передаются данные.
  2. SCL (Serial Clock Line) — линия тактовых импульсов, которая синхронизирует передачу данных.

В схеме может быть только один мастер(ведущий), а все остальные подчиненные(ведомые). Мастер инициирует передачу данных, генерируя тактовые импульсы и управляющие сигналы, в то время как подчиненные отвечают на запросы мастера.

Схема подключения устройств через интерфейс I2C
Рисунок 1. Схема подключения устройств через интерфейс I2C

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

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

Протокол общения I2C

Протокол общения I2C включает несколько этапов:

  1. Стартовый условие (Start condition): Мастер генерирует стартовый сигнал, чтобы уведомить все устройства о начале передачи. Стартовый сигнал начинается с перехода линии данных SDA с высокого на низкое состояние. Через некоторое время(зависит о частоты) SCL опускается с высокого на низкое состояние.
  2. Адресация(ADDR): Мастер отправляет в первые 7 бит адрес подчиненного, к которому он хочет обратиться. 8 битом указывает направление передачи данных (чтение(1) или запись(0)).
  3. Бит подтверждения(ASK): ведомое устройство посылает логическую единицу, называемый битом подтверждения.
  4. Передача данных(DATA): Данные передаются между мастером и слейвом в виде последовательных байтов. Т.е. ведущий передается 8 бит, а ведомый бит подтверждения.
  5. Стоповое условие (Stop condition): Мастер генерирует стоповый сигнал, чтобы завершить передачу. При окончании передачи линия SDA поднимается с низкого на высокое состояние. Через некоторое время(зависит о частоты) SCL повторяет действие за SDA.

Главной особенностью является то, что мастер должен заранее определить на линия SDA логический бит, который хочет передать ведомому. Т.е. до поднятия фронта SCL.

Протокол передачи по интерфейсу I2C
Рисунок 2. Протокол передачи по интерфейсу I2C

Особенности построения I2C

  1. Адресация: Каждое устройство на шине I2C имеет уникальный адрес, который используется для идентификации устройств. Адрес может быть 7-битным или 10-битным.
  2. Скорость передачи: Стандартный режим передачи данных — до 100 кбит/с, быстрый режим — до 400 кбит/с, высокоскоростной режим — до 3,4 Мбит/с.
  3. Четкая синхронизация: данные принимаются всегда правильно, потому что есть синхронизация по тактовому сигналу SCL.

Применение I2C

I2C широко используется в различных электронных устройствах, таких как:

  • Микроконтроллеры
  • Сенсоры и датчики- Память EEPROM и SRAM
  • Цифровые аналоговые преобразователи (DAC)- Жидкокристаллические дисплеи (LCD)
    Эти устройства могут эффективно взаимодействовать друг с другом благодаря универсальности интерфейса I2C.

Преимущества и недостатки I2C

Преимущества:

  • Простота использования: I2C требует всего два провода для связи, что упрощает проектирование схем.
  • Поддержка множества устройств: На одной шине может быть подключено множество устройств, что позволяет создавать сложные системы.
  • Гибкость: Возможность работы с различными скоростями передачи данных.

Недостатки:

  • Ограниченная длина шины: Из-за паразитных емкостей длина шины ограничена несколькими метрами.
  • Скорость передачи: В сравнении с другими интерфейсами (например, SPI), I2C может быть медленнее.
  • Сложность арбитража: При одновременной работе нескольких мастеров возможны сложности с арбитражем.

Примеры реализации контроллеров I2C на разных устройствах

Общение 2-х плат Arduino через интерфейс I2C

Вот пример кода для передачи строки «Hello world» по интерфейсу I2C с использованием Arduino. В этом примере одна Arduino будет выступать в роли мастера, а другая – в роли ведомого устройства. В этом примере мастер отправляет строку «Hello world» на ведомое устройство с адресом 9 через шину I2C. Ведомое устройство принимает эти данные и выводит их в монитор порта Arduino IDE через последовательную связь.

Таблица 1. Схема подключения 2-х плат Arduino
Мастер (Arduino #1)Ведомое устройство (Arduino #2)
1SDA (A4)SDA (A4)
2SCL (A5)SCL (A5)
3GNDGND
Мастер (Arduino C/C++ #1):
#include <Wire.h> void setup() { Wire.begin(); // Инициализация шины I2C как мастер Serial.begin(9600); // Инициализация последовательной связи для вывода информации в монитор порта } void loop() { Wire.beginTransmission(9); // Начало передачи на устройство с адресом 9 (ведомое устройство) Wire.write("Hello world"); // Отправка строки "Hello world" Wire.endTransmission(); // Завершение передачи delay(1000); // Задержка 1 секунда между отправками }
Ведомое устройство (Arduino C/C++ #2):
#include <Wire.h> void setup() { Wire.begin(9); // Инициализация шины I2C с адресом 9 (ведомое устройство) Wire.onReceive(receiveEvent); // Установка функции-обработчика для приема данных Serial.begin(9600); // Инициализация последовательной связи для вывода информации в монитор порта } void loop() { delay(100); // Небольшая задержка } void receiveEvent(int numBytes) { while (Wire.available()) { // Пока есть данные для чтения char c = Wire.read(); // Чтение символа из шины I2C Serial.print(c); // Вывод принятого символа в монитор порта } Serial.println(); // Переход на новую строку для отделения принятых данных }

Реализация I2C на STM32

Пример кода(С/C++) инициализации интерфейсу I2C частотой 100кГц с использованием микроконтроллера STM32 (CubeMX и HAL библиотеки). Микроконтроллер STM32 будет выступать в роли мастера, а который передает строку «Hello world». Адрес ведомого устройства (в данном случае 0x08) должен быть адаптирован к вашей схеме и адресу ведомого устройства.
#include "stm32f4xx_hal.h" #include <stdio.h> #include <string.h> I2C_HandleTypeDef hi2c1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); char txBuffer[] = "Hello world"; HAL_I2C_Master_Transmit(&hi2c1, 0x08 << 1, (uint8_t *)txBuffer, strlen(txBuffer), HAL_MAX_DELAY); while (1); } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 16; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } static void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } void Error_Handler(void) { while (1) { } }

Заключение

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