Как работает SPI (Serial Peripheral Interface)? Полное руководство для Arduino и электроники

SPI (Serial Peripheral Interface) — это высокоскоростной синхронный протокол передачи данных, широко используемый в микроконтроллерах, датчиках, SD-картах и дисплеях. В отличие от UART, SPI работает с тактовым сигналом, что обеспечивает быстрый и надёжный обмен данными.
В этой статье мы разберём:
- Что такое SPI и где он применяется?
- Принцип работы SPI (устройство, режимы передачи)
- Основные линии SPI: MOSI, MISO, SCK, SS
- SPI в Arduino: аппаратная и программная реализация
- Примеры кода для работы с SPI
- Сравнение SPI с I2C и UART
- Частые проблемы и их решение
1. Что такое SPI и зачем он нужен?
SPI — это синхронный последовательный интерфейс, разработанный для быстрого обмена данными между микросхемами. Он используется в:
- Датчиках (акселерометры, гироскопы, термометры)
- Памяти (EEPROM, Flash, SD-карты)
- Дисплеях (OLED, TFT, LED-драйверы)
- Беспроводных модулях (Wi-Fi, Bluetooth, NRF24L01)
Ключевые особенности SPI:
✔ Высокая скорость (до десятков МГц)
✔ Полный дуплекс (одновременная передача и приём)
✔ Простая аппаратная реализация
✔ Гибкость (поддержка множества ведомых устройств)
Главный недостаток: Требует больше линий, чем I2C или UART. Обычно требуется 7-8 проводов для подключения SPI устройств, из них 2-3 питание.
2. Как работает SPI? Основы синхронной передачи
SPI использует 4 основные линии:
| Линия | Назначение |
|---|---|
| SCK | Тактовый сигнал (синхронизация) |
| MOSI | Данные от мастера к ведомому (Master Out Slave In) |
| MISO | Данные от ведомого к мастеру (Master In Slave Out) |
| SS/CS | Выбор ведомого устройства (Slave Select/Chip Select) |

Принцип работы:
- Мастер (например, Arduino) генерирует тактовый сигнал SCK.
- Данные передаются по MOSI и принимаются по MISO одновременно (полный дуплекс).
- SS (Slave Select) переводится в LOW, чтобы активировать нужное устройство.
Режимы SPI (CPOL и CPHA)
SPI поддерживает 4 режима передачи, определяемые фазами тактового сигнала:
| Режим | CPOL (Polarity) | CPHA (Phase) | Описание |
|---|---|---|---|
| 0 | 0 | 0 | Такт начинается с LOW, данные читаются по фронту |
| 1 | 0 | 1 | Такт начинается с LOW, данные читаются по срезу |
| 2 | 1 | 0 | Такт начинается с HIGH, данные читаются по фронту |
| 3 | 1 | 1 | Такт начинается с HIGH, данные читаются по срезу |
Важно: Устройства должны использовать одинаковый режим SPI!
3. SPI в Arduino: аппаратная и программная реализация
Аппаратный SPI (Hardware SPI)
В Arduino Uno (ATmega328P) аппаратный SPI выведен на контакты:
- SCK → 13
- MOSI → 11
- MISO → 12
- SS (CS, chip select) → 10 (но можно выбрать любой цифровой пин)
Пример чтения/записи в EEPROM (25LC512):
#include <SPI.h>
void setup() {
SPI.begin(); // Инициализация SPI
pinMode(10, OUTPUT); // SS (Slave Select)
digitalWrite(10, HIGH); // Деактивировать EEPROM
}
void writeEEPROM(uint16_t addr, uint8_t data) {
digitalWrite(10, LOW); // Активировать EEPROM
SPI.transfer(0x06); // Команда "Write Enable"
digitalWrite(10, HIGH);
digitalWrite(10, LOW);
SPI.transfer(0x02); // Команда записи
SPI.transfer(addr >> 8); // Старший байт адреса
SPI.transfer(addr & 0xFF); // Младший байт адреса
SPI.transfer(data); // Данные
digitalWrite(10, HIGH);
}
uint8_t readEEPROM(uint16_t addr) {
digitalWrite(10, LOW);
SPI.transfer(0x03); // Команда чтения
SPI.transfer(addr >> 8);
SPI.transfer(addr & 0xFF);
uint8_t data = SPI.transfer(0x00); // Чтение данных
digitalWrite(10, HIGH);
return data;
}
void loop() {
writeEEPROM(0x0001, 0xAB); // Запись байта 0xAB по адресу 0x0001
uint8_t value = readEEPROM(0x0001); // Чтение
delay(1000);
}
Программный SPI (Bit Banging)
Если аппаратного SPI недостаточно (например, нужно несколько шин), можно реализовать SPI вручную:
#define SCK_PIN 13
#define MOSI_PIN 11
#define MISO_PIN 12
#define SS_PIN 10
void setup() {
pinMode(SCK_PIN, OUTPUT);
pinMode(MOSI_PIN, OUTPUT);
pinMode(MISO_PIN, INPUT);
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH);
}
uint8_t softSPITransfer(uint8_t data) {
uint8_t received = 0;
for (int i = 0; i < 8; i++) {
digitalWrite(MOSI_PIN, (data & 0x80) ? HIGH : LOW);
digitalWrite(SCK_PIN, HIGH);
received <<= 1;
if (digitalRead(MISO_PIN)) received |= 1;
digitalWrite(SCK_PIN, LOW);
data <<= 1;
}
return received;
}
4. Сравнение SPI с I2C и UART
| Параметр | SPI | I2C | UART |
|---|---|---|---|
| Скорость | До 50 МГц | До 3.4 МГц | До 1 МГц |
| Линии | 4 (SCK, MOSI, MISO, SS) | 2 (SDA, SCL) | 2 (TX, RX) |
| Тип передачи | Полный дуплекс | Полудуплекс | Полудуплекс |
| Синхронизация | Тактовый сигнал (SCK) | Тактовый сигнал (SCL) | Асинхронный |
| Подключение устройств | До 10+ (с отдельными SS) | До 128 (по адресам) | 1:1 (без преобразователей) |
Когда выбирать SPI?
- Нужна высокая скорость (SD-карты, дисплеи).
- Не критично количество проводов.
- Не требуется поддержка множества устройств на одной шине.
5. Частые проблемы и их решение
1. Устройство не отвечает
✅ Проверьте:
- Правильно ли подключены MOSI/MISO (не перепутаны местами).
- Верный ли режим SPI (CPOL/CPHA) выбран в коде.
- Активирован ли SS (Chip Select).
2. Помехи и искажённые данные
✅ Решения:
- Уменьшите скорость SPI (например, с
SPI_CLOCK_DIV2наSPI_CLOCK_DIV8). - Используйте экранированные провода и подтягивающие резисторы.
3. Конфликт нескольких устройств на одной шине
✅ Каждое ведомое устройство должно иметь отдельный SS-сигнал!
Заключение
SPI — мощный интерфейс для высокоскоростной передачи данных между микросхемами. Он идеален для работы с памятью, датчиками и дисплеями в Arduino-проектах.
Главные выводы:
- SPI использует 4 линии (SCK, MOSI, MISO, SS).
- Поддерживает полный дуплекс и скорость до десятков МГц.
- В Arduino есть аппаратная поддержка SPI, но можно реализовать и программно.
Теперь вы знаете, как работает SPI, и сможете применять его в своих устройствах! 🚀
P.S. Попробуйте подключить SPI-модуль (например, RFID RC522 или SD-карту) к Arduino — это отличный способ закрепить знания.
Спасибо за внимание! =)
