Komunikacja SPI w Arduino
Magistrala SPI pozwala na jednoczesne wysyłanie i odbieranie danych z różnymi prędkościami. Arduino pełni rolę urządzenia nadrzędnego i może się komunikować z wieloma urządzeniami podrzędnymi w trybie Full Duplex.
Komunikacja SPI przebiega na podstawie 4 przewodów:
SCK (clock) – pin 13
MISO (main in sub out) – pin 12
MOSI (main out sub in) – pin 11
SS / CS (chip select) – pin 10 (domyślnie)
Linie MOSI, MISO i SCK są wspólne dla wszystkich urządzeń przyłączonych do magistrali SPI.
Każde urządzenie ma osobną linie SS, która decyduje o tym , z którym urządzeniem następuje przesył danych w danym momencie.
Domyślnie na pinie SS utrzymywany jest stan HIGH, który uniemożliwia przesył danych. Przełączenie stanu na LOW jest sygnałem do przesyłu danych do danego urządzenia. Po transmisji danych stan pinu ponownie ustawiany jest na HIGH, co pozwala zwolnić magistralę dla innych urządzeń.
Komunikacja SPI jest możliwy za pomocą biblioteki SPI.
#include "SPI.h"
pinMode(SS, OUTPUT);
digitalWrite(SS, HIGH);
SPI.begin(); //rozpoczęcie komunikacji SPI
SPI.beginTransaction(SPISettings(clockSpeed, bitOrder, dataMode));
//ustawienia komunikacji
// clockSpeed: Prędkość zegara SPI, np. 500000 dla 500 kHz.
// bitOrder: Kolejność przesyłania bitów. MSBFIRST lub LSBFIRST
// dataMode: Tryb SPI (kombinacja CPOL i CPHA). Dostępne tryby to:
// SPI_MODE0: CPOL = 0, CPHA = 0,
// SPI_MODE1: CPOL = 0, CPHA = 1,
// SPI_MODE2: CPOL = 1, CPHA = 0,
// SPI_MODE3: CPOL = 1, CPHA = 1.
digitalWrite(SS, LOW);
SPI.transfer(byte); //przesyłanie danych, linia SS w stanie LOW
digitalWrite(SS, HIGH);
SPI.endTransaction(); // zakończenie transakcji, zwolnienie magistrali dla innych urządzeń
Komunikacja SPI między dwoma płytkami Arduino
//MASTER ARDUINO
#include<SPI.h>
int counter = 0;
int btnPin = 2;
bool btnPrevState = false;
void setup(){
Serial.begin(9600);
SPI.begin();
SPI.beginTransaction(SPISettings(125000, MSBFIRST , SPI_MODE0));
pinMode(SS, OUTPUT);
}
void onClick() {
bool btnNowState = digitalRead(btnPin);
if (btnNowState == 1 && btnPrevState == 0) {
digitalWrite(SS, LOW);
SPI.transfer(counter);
digitalWrite(SS, HIGH);
SPI.endTransaction();
counter++;
}
btnPrevState = btnNowState;
}
void loop(){
onClick();
}
//SLAVE ARDUINO
#include<SPI.h>
volatile bool flag1 = false;
void setup(){
Serial.begin(9600);
pinMode(MOSI, OUTPUT); //should be made output to send data to Master
SPCR |= _BV(SPE); //SPI Port is enabled or SPCR |= (1 << SPE);
SPI.attachInterrupt();
pinMode(SS, INPUT_PULLUP);
}
void loop(){
if (flag1 == true){
Serial.println(SPDR);
flag1 = false;
}
}
ISR (SPI_STC_vect){
flag1 = true;
}
Przesył danych SPI
Przesyłanie danych tekstowych SPI
//master
#include<SPI.h>
char txMsg[] = "Arduino!";
char rxMasg[20] = "";
void setup(){
Serial.begin(9600);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV128); //16 MHz/128
pinMode(SS, OUTPUT); //SS is DPin-10
digitalWrite(SS, LOW); //Slave is selected
}
void loop(){
SPI.transfer('<'); //start mark
for(int i=0; i< sizeof(txMsg); i++) {
SPI.transfer(txMsg[i]);//SPI transfer is byte-by-byte
}
SPI.transfer('>'); //end mark
delay(1000); //test interval
}
//slave
#include<SPI.h>
char rxMsg[20] = "";
volatile bool flag1 = false;
bool flag2 = false;
int i = 0;
void setup(){
Serial.begin(9600);
pinMode(SS, INPUT_PULLUP); //SPI.h helps to get the meaning of SS
pinMode(MOSI, OUTPUT); //should be made output to send data to Master
SPCR |= _BV(SPE); //SPI Port is enabled
SPI.attachInterrupt(); //SPI interrupt is enabled
}
void loop(){
if (flag1 == true) { //SPDR has data
if (flag2 == false) //start mark of message not yet received
{
char q = SPDR;
if (q == '<')
{
flag2 = true; //start mark is detected
flag1 = false; //must be made false for the next cycle
}
}
else {
if (SPDR == '>') //checking if end mark has arived
{
flag1 = false;
flag2 = false;
i = 0;
Serial.print(rxMsg); //end mark has arrived; show the received message
Serial.println(); //insert newline
}
else
{
rxMsg[i] = SPDR; //save received charcater/data byte in array
i++; //adjust array pointer
flag1 = false; //must be false for next cycle
}
}
}
}
ISR (SPI_STC_vect) { //MCU comes here when there is a data byte in SPDR
flag1 = true; //flag to indicate there is data in the SPDR register
}
Zobacz: Wgrywanie programu do Arduino za pomocą programatora ISP USBasp
Zobacz: Arduino jako programator ISP
Zobacz: Komunikacja I2C w Arduino
Zobacz: Komunikacja SPI w Arduino