Урок 7 из 18 · Модуль 3. I²C: шина датчиков
Протоколы в БАС: полный курс · Урок 7 из 18 · Модуль 3. Шины датчиков: I²C, SPI, CAN
Всего два сигнальных проводника на всю шину: подтягивающие резисторы, адресация, подтверждения. Компасы, барометры, OLED-дисплеи и лидары — их типовые неисправности.
Без подтягивающих резисторов шина I²C не работает, а два устройства с одинаковым адресом не могут работать одновременно. Типичный случай: после подключения второго однотипного GPS/GNSS-модуля со встроенным компасом оба компаса перестают работать.
Содержание
1. Цели урока
После этого урока вы сможете:
- объяснить устройство шины I²C: линии SDA и SCL, подтягивающие резисторы, 7-битная адресация;
- описать полный цикл обмена: условие «старт», кадр адреса, байты данных с подтверждениями, условие «стоп»;
- назвать адреса типовых микросхем: 0x76 — барометр, 0x0D — компас QMC5883L;
- диагностировать зависание шины и конфликты адресов.
2. Шина I²C
I²C (произносится «ай-скве́рд-си», от англ. Inter-Integrated Circuit) — шина, разработанная компанией Philips (ныне — NXP Semiconductors) для обмена данными между микросхемами в пределах одной печатной платы. В БпЛА она применяется там, где скорость передачи не критична, а важна простота подключения: барометры, внешние компасы (магнитометры), компактные OLED-дисплеи, лазерные дальномеры, датчики тока и напряжения. Для обмена достаточно двух сигнальных линий: SDA (данные) и SCL (тактирование); дополнительно требуются общий провод (GND) и питание.
Как устроена шина

Ключевая особенность I²C: обе линии выполнены по схеме с открытым стоком или открытым коллектором (open-drain / open-collector). Устройства могут только притягивать линию к логическому нулю; высокий уровень создаётся подтягивающим резистором, соединённым с шиной питания. Благодаря этому:
- шину могут одновременно использовать несколько устройств — это не вызывает короткого замыкания. У обычного двухтактного выхода (push-pull) активны оба уровня: если бы два таких устройства одновременно подали на одну линию «единицу» и «ноль», между ними возник бы ток короткого замыкания. Выход I²C устроен иначе: микросхема может только притянуть линию к нулю или «отпустить» её; «единицу» формирует подтягивающий резистор, который заодно ограничивает ток до безопасного значения. Поэтому конфликт передатчиков электрически безопасен (такое соединение называют «монтажным И», wired-AND);
- подтверждение приёма передаётся по уже имеющейся линии SDA, без дополнительных проводов. Каждый байт занимает девять тактовых импульсов: восемь — биты данных, девятый — подтверждение. К девятому такту передатчик освобождает линию, а приёмник, получивший байт, притягивает SDA к низкому уровню — это и есть сигнал «байт принят». Передатчик проверяет линию в девятом такте: низкий уровень — подтверждение есть (ACK), высокий — подтверждения нет (NACK), то есть устройство не отвечает или завершает обмен.
Как проходит обмен по I²C
Обменом на шине управляет ведущее устройство (master). Шина I²C допускает несколько ведущих (multi-master), однако в каждый момент времени конкретную транзакцию ведёт ровно одно из них. В БпЛА ведущим обычно выступает полётный контроллер; барометр, компас, OLED-дисплей и дальномер — ведомые (slave): они передают данные только после обращения к ним по адресу. Вся передача состоит из транзакций: ведущее устройство формирует условие «старт», передаёт кадр адреса, обменивается байтами данных и завершает обмен условием «стоп».
Чтобы понимать обмен и осциллограммы I²C, достаточно трёх правил:
- такты формирует ведущее устройство. Каждый бит передаётся ровно за один тактовый импульс на линии SCL;
- линию SDA разрешено менять только при низком уровне SCL. Пока SCL высокий, уровень на SDA остаётся стабильным — именно в этот момент приёмник считывает очередной бит;
- каждый байт подтверждается девятым тактом: ACK — «байт принят», NACK — «не принят» либо «данных больше не требуется».
Условия «старт» и «стоп» — единственные события, которым позволено нарушать второе правило, поэтому приёмник распознаёт их однозначно:
- условие СТАРТ (S) — SDA переходит из высокого уровня в низкий, пока SCL высокий;
- условие СТОП (P) — SDA переходит из низкого уровня в высокий, пока SCL высокий; после этого шина считается свободной.
Транзакция по шагам:
- Ведущее устройство формирует условие «старт».
- Передаёт кадр адреса: 7 бит адреса ведомого устройства и бит направления — 0 («запись») или 1 («чтение»).
- Все ведомые устройства слушают шину; то, чей адрес совпал, отвечает ACK. Остальные в обмене не участвуют.
- Передаются байты данных: номера регистров, команды настройки либо измеренные значения. Каждый байт завершается тактом подтверждения.
- При чтении ведущее устройство подтверждает каждый принятый байт (ACK), но последний — не подтверждает (NACK): так ведомое устройство понимает, что данные больше не требуются.
- Ведущее устройство формирует условие «стоп» — транзакция завершена.
Реальный пример — полётный контроллер читает измерения барометра BMP280 (адрес 0x76). Датчик хранит результаты в регистрах, начиная с 0xF7, поэтому транзакция выглядит так:
- условие «старт»;
- байт 0xEC — адрес 0x76 с битом «запись»; барометр отвечает ACK;
- байт 0xF7 — «данные будешь передавать с этого регистра»; ACK;
- повторный старт (repeated START) — смена направления на чтение без освобождения шины;
- байт 0xED — тот же адрес 0x76 с битом «чтение»; ACK;
- барометр выдаёт байты результата; ведущее устройство отвечает ACK на каждый, последний — NACK;
- условие «стоп».
Ниже — ASCII-осциллограмма той же транзакции по фазам. Для примера предположим, что барометр возвращает два байта: 0x5A и 0x3C.
Как читать диаграммы: HIGH (логическая единица) — линия вверху; LOW (логический ноль) — линия внизу. Бит считывается в момент, когда SCL HIGH (фронт). Если несколько подряд идущих битов одинаковы — SDA не меняет уровень, перехода нет.
Фаза 1 — START + адрес 0xEC (запись) + ACK (обращение мастера к барометру по его адресу)
0xEC = 1 1 1 0 1 1 0 0. Перед стартом обе линии подтянуты к HIGH. START: SDA падает, пока SCL ещё HIGH. Затем мастер тактирует 8 бит + 9-й такт для ACK.
S b7 b6 b5 b4 b3 b2 b1 b0 ACK
1 1 1 0 1 1 0 0 0
┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐
SCL ─────────┐ │ ││ ││ ││ ││ ││ ││ ││ ││ │
└───┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └──
▲
SDA ─────┐ ┌──────────────┐ ┌───────┐
└───┘ 1 1 1 └─0─┘ 1 1 └──0───0───0──
▲ ▲
START: ACK от
SDA↓ при барометра
SCL=HIGH
Мастер выдал 0xEC — это 0x76 << 1 | 0 (запись). Барометр узнал свой адрес и прижал SDA к LOW на 9-м такте → ACK. Два «горба» HIGH на SDA соответствуют двум группам единиц в 0xEC: 1 1 1 0 1 1 0 0.
Фаза 2 — байт данных 0xF7 (адрес регистра) + ACK (запрос данных из конкретного регистра)
0xF7 = 1 1 1 1 0 1 1 1
b7 b6 b5 b4 b3 b2 b1 b0 ACK
1 1 1 1 0 1 1 1 0
┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐
SCL ─────────┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └──
SDA ────────────────────────┐ ┌───────────┐
1 1 1 1 └─0─┘ 1 1 1 └──0──
▲
ACK от
барометра
Мастер сказал барометру: «выдавай данные, начиная с регистра 0xF7». Барометр ответил ACK. Два «горба» HIGH: 1 1 1 1 0 1 1 1.
Фаза 3 — Repeated START + адрес 0xED (чтение) + ACK
0xED = 1 1 1 0 1 1 0 1. Мастер не отпускает шину (нет STOP), а формирует ещё один START — repeated START (Sr). Адрес тот же 0x76, но младший бит теперь 1 → 0xED (чтение).
Sr b7 b6 b5 b4 b3 b2 b1 b0 ACK
1 1 1 0 1 1 0 1 0
┌───┐ ┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐
SCL ─────┘ │ │ ││ ││ ││ ││ ││ ││ ││ ││ │
└───┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └──
▲ ▲
│ └── SDA падает при SCL=HIGH → Sr (repeated START)
│
SDA сначала отпущена в HIGH
SDA ───── ┌──────────────┐ ┌───────┐ ┌─┐
(данные) └───┘ 1 1 1 └─0─┘ 1 1 └─0─┘1└──0──
▲
ACK от
барометра
Три HIGH: 1 1 1 0 1 1 0 1. Барометр снова ответил ACK и готов выдавать данные.
Фаза 4 — барометр выдаёт первый байт данных (0x5A) + мастер отвечает ACK
0x5A = 0 1 0 1 1 0 1 0. Теперь каналом SDA управляет барометр, а мастер только тактирует SCL и подтверждает. Обратите внимание: биты b4 и b3 — обе единицы, поэтому SDA остаётся HIGH два такта подряд (один широкий «импульс», перехода внутри нет).
b7 b6 b5 b4 b3 b2 b1 b0 ACK
0 1 0 1 1 0 1 0 0
┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐
SCL ─────────┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └──
SDA ────────┐ ┌───┐ ┌───────┐ ┌───┐
└───┘ └───┘ └───┘ └──────────
0 1 0 1 1 0 1 0 0
b7 b6 b5 b4 b3 b2 b1 b0 ACK
▲ ▲
SDA остаётся HIGH ACK от
два такта подряд мастера
(b4+b3=1,1) «давай ещё»
Три HIGH на SDA — ровно три группы единиц в 0x5A: 0 1 0 1 1 0 1 0
Фаза 5 — второй (последний) байт данных (0x3C) + NACK + STOP
0x3C = 0 0 1 1 1 1 0 0. Мастер знает, что этот байт последний, поэтому на 9-м такте не подтверждает (NACK = SDA HIGH). Затем формирует STOP: притягивает SDA к LOW (пока SCL ещё низкий), отпускает SCL, а затем отпускает SDA — переход LOW→HIGH при SCL = HIGH.
b7 b6 b5 b4 b3 b2 b1 b0 NACK P
0 0 1 1 1 1 0 0 1
┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐┌──┐ ┌─────
SCL ─────────┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └┘ └──┘
┌───────────────┐ ┌───┐ ┌──────
SDA ────────────────┘ └───────┘ └──┘
0 0 1 1 1 1 0 0 1 ▲
b7 b6 b5 b4 b3 b2 b1 b0 │
▲ │
NACK │ STOP:
(SDA │ SDA↑ при
HIGH)│ SCL=HIGH
│
«хватит,
данных не надо»
Один широкий HIGH (четыре такта подряд, b5–b2): 0 0 1 1 1 1 0 0. После NACK мастер кратковременно притягивает SDA к LOW и затем отпускает — этот переход LOW→HIGH при SCL = HIGH и есть условие STOP.
Вся транзакция одной строкой — так она выглядит в окне логического анализатора:
┌─────────┬─────────────┬───────────────┬────────┬─────────────┬───────────────┬────────────────┬──────┐
│ START │ 0xEC (W) │ 0xF7 (reg) │ Sr │ 0xED (R) │ 0x5A + ACK │ 0x3C + NACK │ STOP │
│ │ ACK │ ACK │ │ ACK │ (мастер) │ (мастер) │ │
└─────────┴─────────────┴───────────────┴────────┴─────────────┴───────────────┴────────────────┴──────┘
мастер мастер → мастер → мастер мастер → ← барометр ← барометр мастер
барометру барометру барометру мастеру мастеру
«я к тебе, «начни с «теперь «вот первый «вот второй
пишу» регистра читаю» байт» байт»
0xF7»
Соответствие полей в декодере логического анализатора (Saleae Logic, PulseView):
| Поле в декодере | Значение | Пояснение |
|---|---|---|
| Address | 0x76 |
7-битный адрес барометра |
| Write | 0xEC |
0x76 << 1 | 0 |
| Data (W) | 0xF7 |
адрес начального регистра |
| Repeated Start | Sr | смена направления без освобождения шины |
| Read | 0xED |
0x76 << 1 | 1 |
| Data (R) | 0x5A 0x3C … |
байты из регистров датчика |
| NACK | на последнем байте | мастер завершает чтение |
| Stop | P | шина свободна |
Две тонкости, о которых полезно знать:
- повторный старт (repeated START) — новое условие «старт» без предварительного «стопа». Нужен, когда в одной транзакции требуется сначала записать (выбрать регистр), а затем прочитать (получить данные). Большинство датчиков, включая BMP280, обычно используют именно такой порядок (хотя по техническому описанию BMP280 допускает и промежуточный «стоп»);
- растяжение такта (clock stretching) — медленное ведомое устройство вправе удерживать SCL в низком уровне, и ведущее устройство обязано ждать. Если на осциллограмме SCL «залип» в нуле — это не обязательно неисправность. В большинстве распространённых датчиков для БпЛА clock stretching не используется, но по протоколу он возможен.
Скорости и адреса
Стандартные режимы: 100 кбит/с (standard), 400 кбит/с (fast — типовой режим для БпЛА), 1 Мбит/с (fast+). Для сравнения: UART на скорости 115200 бод обеспечивает около 11,5 Кбайт/с полезных данных, I²C на 400 кГц — до ~40 Кбайт/с. Адреса типовых микросхем, которые необходимо знать наизусть:
| Микросхема | Назначение | Адрес (7-битный) |
|---|---|---|
| BMP280 / BMP388 / SPL06 / DPS310 | барометр | 0x76 или 0x77 (выбирается перемычкой) |
| QMC5883L | компас (в модулях Matek M8Q-5883 и др.) | 0x0D |
| HMC5883L | компас (устаревший, встречается в недорогих модулях) | 0x1E |
| IST8310 | компас (типовой внешний компас в экосистеме ArduPilot) | 0x0E |
| SSD1306 | OLED-дисплей 0,96″ | 0x3C (иногда 0x3D) |
| VL53L0X / VL53L1X | лазерный дальномер | 0x29 |
| INA226 / INA228 | датчик тока и напряжения | 0x40–0x4F (назначается конфигурацией) |
Где I²C встречается в БпЛА
- Барометр на плате полётного контроллера — исторически подключался почти всегда по I²C; в настоящее время производители всё чаще применяют SPI.
- Внешний компас — GPS/GNSS-модули со встроенным компасом (Matek M8Q-5883, Holybro M9N/M10): по UART передаются координаты, по I²C — данные магнитометра. На самолетах и крупных мультироторных БпЛА компас выносят на максимальное удаление от силовых проводов — на штангу или в хвостовую часть — и подключают именно по I²C.
- OLED-дисплеи — на самодельных аппаратах и самолетах: компактный экран отображает режим полёта, напряжение аккумуляторной батареи, уровень принимаемого сигнала (RSSI).
- Лидары для автоматической точной посадки — модули на VL53L0X и другие; лидары серии TFmini чаще применяются в исполнении с интерфейсом UART.
- Цифровые датчики тока и напряжения (INA226/INA228) — в самодельных индикаторах состояния аккумуляторной батареи и в отдельных системах контроля аккумуляторов (BMS).
Классический модуль I²C: компас GY-273 на микросхеме QMC5883L. Четыре контакта: VCC, GND, SCL, SDA. Именно такие компасы (или компасы, встроенные в GPS/GNSS-модули) подключают к шине I²C полётного контроллера. После установки на борт обязательна калибровка: без неё показания компаса недостоверны и представляют опасность в полёте.
Типовые неисправности I²C и способы устранения
| Симптом | Вероятная причина | Способ устранения |
|---|---|---|
| Устройство не обнаруживается (сканер адресов не находит устройств) | отсутствуют подтягивающие резисторы, обрыв SDA/SCL, отсутствует питание | проверить +3,3 В на линиях в состоянии покоя, проверить целостность проводников |
| Устройство обнаруживается, но периодически пропадает | длинные провода, паразитная ёмкость линии, помехи от электродвигателей | укоротить провода, сформировать витую пару из SDA и GND, снизить скорость до 100 кГц |
| Шина «зависла»: SDA удерживается на низком уровне | ведомое устройство прервало транзакцию и удерживает линию | восстановить шину: сформировать девять тактовых импульсов на SCL (стандартный алгоритм ведущего устройства), перезагрузить полётный контроллер |
| Два однотипных устройства конфликтуют | совпали адреса | изменить адрес перемычкой или прошивкой либо установить разные модели |
| Компас выдаёт недостоверные (хаотичные) показания | электромагнитные наводки от силовых проводов, не выполнена калибровка | вынести компас на большее удаление от силовых проводов, перевить провода, выполнить калибровку |
💻 Для программиста
Первое программное средство, которое разрабатывают для работы с I²C, — сканер адресов. Он перебирает все возможные адреса и по наличию ACK в кадре адреса определяет, какие устройства реально подключены к шине (см. раздел «Как проходит обмен по I²C»). На платформе Arduino он занимает около двадцати строк и незаменим при диагностике:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
for (byte a = 8; a < 120; a++) {
Wire.beginTransmission(a);
if (Wire.endTransmission() == 0) {
Serial.print("Найден: 0x");
Serial.println(a, HEX);
}
}
}
void loop() {}
В прошивках полётных контроллеров драйвер I²C реализован с защитой от сбоев: Betaflight и ArduPilot автоматически восстанавливают работу зависшей шины и повторно опрашивают устройства. Поэтому при нестабильной работе барометра или компаса первое действие — перезагрузка полётного контроллера, второе — проверка целостности соединений.
3. Чек-лист самопроверки
Урок освоен, если каждый пункт выполнен на практике:
- Сканер адресов обнаруживает все подключённые устройства
- Понятно назначение подтягивающих резисторов и причина, по которой их не следует дублировать
- Понятно, почему внешний компас выносят на удаление от силовых проводов
4. Что дальше
- Предыдущий урок: Урок 6. UART: диагностика и логический анализатор
- Следующий урок: Урок 8. SPI: скоростной конвейер
- Полный перечень тем — в статье «Содержание курса».
