I2C, SPI и UART: три способа, которыми модули говорят с Arduino
Кнопка и светодиод обходятся одним проводом: на нём либо есть напряжение, либо нет. Дисплей, гироскоп или модуль часов должны передать числа — а числа одним проводом не передашь. Для этого придуманы интерфейсы: договорённости о том, как по двум-четырём проводам гонять данные. В мире Arduino их три, и у каждого своя ниша.
Коротко: чем они отличаются
I2C 2 сигнальных
SPI 4 сигнальных
UART 2 сигнальных
I2C До 127, по адресам
SPI Сколько угодно, по проводу выбора на каждое
UART Два: точка-точка
I2C Низкая, 100–400 кбит/с
SPI Высокая, мегабиты
UART Средняя, 9600–115200 бит/с
I2C OLED, часы, гироскоп, расширители
SPI TFT-дисплей, SD-карта, радио nRF24, RFID
UART Bluetooth, GPS, GSM, второй Arduino
I2C: два провода на всех
Линия данных SDA и линия тактов SCL, плюс питание и земля. На одну пару проводов вешается сколько угодно модулей — дисплей, датчик, часы, — и все они различаются адресами. Плата говорит: «адрес 0x3C, прими картинку», и отвечает только дисплей.
Это делает I2C любимым интерфейсом для модулей: четыре провода, и дисплей работает. На UNO и Nano шина живёт на A4 и A5, и пока модуль подключён, эти выводы для другого недоступны. Библиотека — встроенная Wire, но напрямую с ней почти не работают: у каждого модуля своя библиотека поверх.
Если модуль молчит, первым делом узнают его адрес. Скетч ниже перебирает все адреса и печатает, кто отозвался. Пусто — значит, дело в проводах или питании; адрес есть, но не тот, что в примере, — поправьте его в коде.
// Сканер I2C: печатает адреса всех модулей на шине
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Ищу устройства на I2C...");
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Найден адрес 0x");
Serial.println(addr, HEX);
}
}
Serial.println("Готово");
}
void loop() {}SPI: быстро, но проводов больше
Четыре линии: MOSI — от платы к модулю, MISO — обратно, SCK — такты, и SS (он же CS) — выбор устройства. Адресов нет: чтобы обратиться к модулю, плата притягивает его провод выбора к земле. Два модуля — два провода выбора, остальные три линии общие.
Зато скорость в десятки раз выше, чем у I2C. Поэтому всё, что гонит много данных, сидит на SPI: цветные дисплеи, карты памяти, радиомодули. На UNO это выводы 10–13, и вывод 13 совпадает со встроенным светодиодом — он будет мерцать при передаче, это нормально.
Модули SPI чаще всего рассчитаны на 3,3 В: TFT-дисплеи, nRF24L01, RFID RC522. С UNO их питают от вывода 3.3V, а вот сигнальные линии с 5-вольтовых выводов формально им великоваты — обычно терпят, но преобразователь уровней надёжнее.
UART: последовательный порт
Самый старый и самый простой: провод туда, провод обратно, общая земля. Никаких адресов и тактов — обе стороны заранее договариваются о скорости, и если она не совпала, в монитор порта сыплется мусор. Отсюда цифра 9600 в Serial.begin: она должна быть одинаковой с обеих сторон.
По UART плата общается с компьютером через USB — на UNO это выводы 0 и 1, и занимать их модулем нельзя: загрузка скетча перестанет работать. Для Bluetooth или GPS берут любые два других вывода с библиотекой SoftwareSerial, а на Mega и ESP32 есть настоящие дополнительные порты.
Правило, которое путают все: TX платы идёт в RX модуля, и наоборот. Что один передаёт — другой принимает. Соединить одинаковые надписи — значит соединить два выхода, и связи не будет.
Где какой интерфейс на каждой плате
На ESP32 это выводы по умолчанию — там любой интерфейс можно перевести на другие выводы в коде. На Arduino выводы жёсткие.
На чём попадаются
Два I2C-модуля с одним адресом
Два одинаковых OLED на одной шине откликаются оба, и оба показывают мусор. На части модулей адрес меняется перемычкой на обороте; если нет — второй вешают на программную шину на других выводах.
Длинные провода на I2C
Шина рассчитана на сантиметры, не метры. Полметра шлейфа — и модуль то виден, то нет. Укоротить провода или снизить скорость шины помогает почти всегда.
Модуль на выводах 0 и 1
Скетч перестал загружаться с ошибкой «not in sync». Bluetooth-модуль на аппаратном порту перебивает загрузчик. Отключите его на время прошивки или переведите на другие выводы.
Скорость не совпала
В мониторе порта иероглифы. Цифра внизу окна монитора и цифра в Serial.begin должны быть одинаковыми. У модулей своя скорость по умолчанию: у Bluetooth HC-05 чаще 38400, у GPS — 9600.
Что дальше
- OLED SSD1306: модуль на I2C со схемой
- TFT ILI9341: модуль на SPI со схемой
- Распиновка UNO: где какой интерфейс
Сканер I2C собран под Arduino UNO перед публикацией