Logo
Версия для печати
Интерфейс SPI
Интерфейс SPI

Интерфейс SPI и Arduino

8 комментарии Arduino
Print Friendly, PDF & Email

Изучаем интерфейс SPI и подключаем к Arduino сдвиговый регистр, к которому мы будем обращаться по этому протоколу для управления светодиодами.

Инструкция по работе Arduino с интерфейсом SPI

Нам понадобится:

1Описание последовательного интерфейса SPI

SPI – Serial Peripheral Interface или «Последовательный периферийный интерфейс» – это синхронный протокол передачи данных для сопряжения ведущего устройства (Master) с периферийными устройствами (Slave). Ведущим устройством часто является микроконтроллер. Связь между устройствами осуществляется по четырём проводам, поэтому SPI иногда называют «четырёхпроводной интерфейс». Вот эти шины:

НазваниеНазначение шины SPI
MOSI (Master Out Slave In)линия передачи данных от ведущего к ведомым устройствам;
MISO (Master In Slave Out)линия передачи от ведомого к ведущему устройству;
SCLK (Serial Clock)тактовые импульсы синхронизации, генерируемые ведущим устройством;
SS (Slave Select)линия выбора ведомого устройства; когда на линии логический "0", ведомое устройство «понимает», что сейчас обращаются к нему.

Существует четыре режима передачи данных (SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3), обусловленные сочетанием полярности тактовых импульсов (работаем по уровню HIGH или LOW), Clock Polarity, CPOL, и фазой тактовых импульсов (синхронизация по переднему или заднему фронту тактового импульса), Clock Phase, CPHA. В последнем столбце таблицы приведены поясняющие иллюстрации. На них Sample обозначены моменты, когда данные на линии должны быть готовы и считываются устройствами. Буквой Z отмечено, что состояние данных на линии неизвестно или не важно.

РежимПолярность тактовых импульсов (CPOL)Фаза тактовых импульсов (CPHA)Диаграмма режима
SPI_MODE000Диаграмма сигналов при режиме SPI 0
SPI_MODE101Диаграмма сигналов при режиме SPI 1
SPI_MODE210Диаграмма сигналов при режиме SPI 2
SPI_MODE311Диаграмма сигналов при режиме SPI 3

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

Виды подключения устройств: независимое и каскадное
Виды подключения устройств для работы по интерфейсу SPI: независимое и каскадное

2Реализация интерфейса SPI на платах семейства Arduino

В Arduino шины интерфейса SPI находятся на определённых портах. У каждой платы своё соответствие выводов. Для удобства выводы продублированы и вынесены также на отдельный разъём ICSP (In Circuit Serial Programming, программирование устройства, включённого в цепь, по последовательному протоколу). Обратите внимание, что на разъёме ICSP отсутствует пин выбора ведомого – SS, т.к. подразумевается, что Arduino будет использоваться как ведущее устройство в сети. Но при необходимости вы можете назначить любой цифровой вывод Ардуино в качестве SS.

На рисунке приведено стандартное соответствие выводов шинам SPI для Arduino UNO и Nano.

Реализация интерфейса SPI на платах Arduino UNO и Arduino Nano
Реализация интерфейса SPI на платах Arduino UNO и Arduino Nano

3Стандартная библиотека для работы по интерфейсу SPI

Для Arduino написана специальная библиотека, которая реализует протокол SPI. Она устанавливается вместе со средой разработки Arduino IDE. Подключается она так: в начале программы добавляем #include SPI.h.

Чтобы начать работу по протоколу SPI, нужно задать настройки и затем инициализировать протокол с помощью процедуры SPI.beginTransaction(). Можно выполнить это одной инструкцией: SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0))

Это значит, что мы инициализируем протокол SPI на частоте 14 МГц, передача данных идёт, начиная с MSB (наиболее значимого бита), в режиме SPI_MODE0.

После инициализации выбираем ведомое устройство, переводя соответствующий пин SS в состояние LOW. Затем передаём ведомому устройству данные командой SPI.transfer(). После передачи возвращаем SS в состояние HIGH.

Временная диаграмма работы интерфейса SPI
Временная диаграмма работы интерфейса SPI

Работа с протоколом завершается командой SPI.endTransaction().

Желательно минимизировать время выполнения передачи между инструкциями SPI.beginTransaction() и SPI.endTransaction(), чтобы не возникло накладок, если другое устройство попробует инициализировать передачу данных, используя другие настройки.

Если вы планируете в своём скетче использовать стандартные пины Arduino, можно не описывать их в начале программы, т.к. они уже определены в самой библиотеке и имеют следующие имена:

#define PIN_SPI_SS    (10)
#define PIN_SPI_MOSI  (11)
#define PIN_SPI_MISO  (12)
#define PIN_SPI_SCK   (13)

Данные пины определены в файле pins_arduino.h , который находится по пути %programfiles%\arduino-(версия)\hardware\arduino\avr\variants\ (если вы устанавливали программу в стандартное расположение). То есть, например, чтобы опустить пин выбора ведомого в состояние "0", можно написать:

digitalWrite(PIN_SPI_SS, LOW);

4Подключение сдвигового регистра к Arduino

Рассмотрим практическое применение интерфейса SPI. Будем зажигать светодиоды, управляя 8-битным сдвиговым регистром по шине SPI. Подключим к Arduino сдвиговый регистр 74HC595. К каждому из 8-ми выходов регистра через ограничительный резистор подключим по светодиоду номиналом 220 Ом. Схема приводится на рисунке.

Схема подключения сдвигового регистра 74HC595 к Arduino
Схема подключения сдвигового регистра 74HC595 к Arduino

5Скетч для управления сдвиговым регистром по интерфейсу SPI

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

#include <SPI.h>

const int pinSelect = 8; // пин выбора регистра

void setup() {
  SPI.begin(); // инициализация интерфейса SPI
  pinMode(pinSelect, OUTPUT); // 
  digitalWrite(pinSelect, LOW); // выбор ведомого устройств (регистра)
  SPI.transfer(0); // очищаем содержимое регистра
  digitalWrite(pinSelect, HIGH); // конец передачи
  Serial.begin(9600);
}

void loop() {
  for (int i=0; i<8; i++) {    
    double L = pow(2, i); // вычисляем активный светодиод
    int leds = round(L); // округляем число до целого
    digitalWrite(pinSelect, LOW); // выбор регистра сдвига
    SPI.transfer(leds); // передаём значение в сдвиговый регистр
    digitalWrite(pinSelect, HIGH); // конец передачи
    Serial.println(leds, BIN); // вывод в двоичном представлении
    delay(125); // задержка 125 мс
  }
  Serial.println("--------");
}

Сначала подключим библиотеку SPI и инициализируем интерфейс SPI. Определим пин 8 как пин выбора ведомого устройства SS. Очистим сдвиговый регистр, послав в него значение "0". Инициализируем последовательный порт.

Чтобы зажечь определённый светодиод с помощью сдвигового регистра, нужно подать на его вход 8-разрядное число. Например, чтобы загорелся первый светодиод – подаём двоичное число 00000001, чтобы второй – 00000010, чтобы третий – 00000100, и т.д. Эти двоичные числа при переводе в десятичную систему счисления образуют такую последовательность: 1, 2, 4, 8, 16, 32, 64, 128 и являются степенями двойки от 0 до 7.

Соответственно, в цикле loop() по количеству светодиодов делаем пересчёт от 0 до 7. Функция pow(основание, степень) возводит 2 в степень счётчика цикла. Микроконтроллеры не очень точно работают с числами типа "double", поэтому для преобразования результата в целое число используем функцию округления round(). И передаём получившееся число в сдвиговый регистр. Для наглядности в монитор последовательного порта выводятся значения, которые получаются при этой операции: единичка «бежит» по разрядам – светодиоды загораются волной.

Числа, посылаемые в сдвиговый регистр 74HC595
Числа, посылаемые в сдвиговый регистр 74HC595

6«Бегущая волна» из светодиодов

Светодиоды загораются по очереди, и мы наблюдаем бегущую «волну» из огоньков. Управление светодиодами осуществляется с помощью сдвигового регистра, к которому мы подключились по интерфейсу SPI. В результате для управления 8-ю светодиодами задействованы всего 3 вывода Arduino. Если бы мы подключали светодиоды напрямую к цифровым портам Arduino, нам бы потребовалось для каждого светодиода использовать отдельный порт.

Мы изучили самый простой пример работы Arduino с шиной SPI. Более подробно рассмотрим работу нескольких сдвиговых регистров при независимом и каскадном подключениях в отдельной статье.

Последнее изменениеСреда, 10 Январь 2024 18:54 Прочитано 86070 раз

Поблагодарить автора:

Поделиться

Print Friendly, PDF & Email
Template Design © Joomla Templates | GavickPro. All rights reserved.