|

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.

Połączenie Arduino z urządzeniem SPI
Połączenie Arduino z urządzeniem SPI

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

Komunikacja SPI między dwoma Arduino
Komunikacja SPI między dwoma 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ł danych Arduino SPI
Przesył danych Arduino SPI Analizator stanów logicznych

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

Zobacz: Komunikacja radiowa SPI NRF24L01 z Arduino

Podobne wpisy

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *