Arduino - 序列外設介面



序列外設介面 (SPI) 匯流排是一種序列通訊系統,最多使用四個導線,通常使用三個。一個導線用於資料接收,一個用於資料傳送,一個用於同步,另一個可選用於選擇要與其通訊的裝置。它是一種全雙工連線,這意味著資料可以同時傳送和接收。最大波特率高於 I2C 通訊系統。

開發板 SPI 引腳

SPI 使用以下四根線:

  • SCK - 這是由主裝置驅動的序列時鐘。

  • MOSI - 這是由主裝置驅動的主裝置輸出/從裝置輸入。

  • MISO - 這是由從裝置驅動的主裝置輸入/從裝置輸出。

  • SS - 這是從裝置選擇線。

使用以下函式。您必須包含 SPI.h。

  • SPI.begin() - 透過將 SCK、MOSI 和 SS 設定為輸出,將 SCK 和 MOSI 拉低,並將 SS 拉高來初始化 SPI 匯流排。

  • SPI.setClockDivider(divider) - 設定相對於系統時鐘的 SPI 時鐘分頻器。在基於 AVR 的開發板上,可用的分頻器為 2、4、8、16、32、64 或 128。預設設定為 SPI_CLOCK_DIV4,它將 SPI 時鐘設定為系統時鐘頻率的四分之一(對於 20 MHz 的開發板,為 5 MHz)。

  • 分頻器 - 它可以是 (SPI_CLOCK_DIV2, SPI_CLOCK_DIV4, SPI_CLOCK_DIV8, SPI_CLOCK_DIV16, SPI_CLOCK_DIV32, SPI_CLOCK_DIV64, SPI_CLOCK_DIV128)。

  • SPI.transfer(val) - SPI 傳輸基於同時傳送和接收:接收到的資料將返回到 receivedVal。

  • SPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode)) - speedMaximum 是時鐘,dataOrder (MSBFIRST 或 LSBFIRST),dataMode (SPI_MODE0, SPI_MODE1, SPI_MODE2 或 SPI_MODE3)。

SPI 有四種工作模式:

  • 模式 0(預設) - 時鐘通常為低電平 (CPOL = 0),資料在從低電平到高電平的躍遷時取樣 (CPHA = 0)。

  • 模式 1 - 時鐘通常為低電平 (CPOL = 0),資料在從高電平到低電平的躍遷時取樣 (CPHA = 1)。

  • 模式 2 - 時鐘通常為高電平 (CPOL = 1),資料在從高電平到低電平的躍遷時取樣 (CPHA = 0)。

  • 模式 3 - 時鐘通常為高電平 (CPOL = 1),資料在從低電平到高電平的躍遷時取樣 (CPHA = 1)。

  • SPI.attachInterrupt(handler) - 從裝置從主裝置接收資料時呼叫的函式。

現在,我們將連線兩個 Arduino UNO 開發板;一個作為主裝置,另一個作為從裝置。

  • (SS) : 10 號引腳
  • (MOSI) : 11 號引腳
  • (MISO) : 12 號引腳
  • (SCK) : 13 號引腳

地線共用。以下是兩個開發板之間連線的示意圖:

Connection of Boards

讓我們看看 SPI 作為主裝置和 SPI 作為從裝置的示例。

SPI 作為主裝置

示例

#include <SPI.h>

void setup (void) {
   Serial.begin(115200); //set baud rate to 115200 for usart
   digitalWrite(SS, HIGH); // disable Slave Select
   SPI.begin ();
   SPI.setClockDivider(SPI_CLOCK_DIV8);//divide the clock by 8
}

void loop (void) {
   char c;
   digitalWrite(SS, LOW); // enable Slave Select
   // send test string
   for (const char * p = "Hello, world!\r" ; c = *p; p++) {
      SPI.transfer (c);
      Serial.print(c);
   }
   digitalWrite(SS, HIGH); // disable Slave Select
   delay(2000);
}

SPI 作為從裝置

示例

#include <SPI.h>
char buff [50];
volatile byte indx;
volatile boolean process;

void setup (void) {
   Serial.begin (115200);
   pinMode(MISO, OUTPUT); // have to send on master in so it set as output
   SPCR |= _BV(SPE); // turn on SPI in slave mode
   indx = 0; // buffer empty
   process = false;
   SPI.attachInterrupt(); // turn on interrupt
}
ISR (SPI_STC_vect) // SPI interrupt routine { 
   byte c = SPDR; // read byte from SPI Data Register
   if (indx < sizeof buff) {
      buff [indx++] = c; // save data in the next index in the array buff
      if (c == '\r') //check for the end of the word
      process = true;
   }
}

void loop (void) {
   if (process) {
      process = false; //reset the process
      Serial.println (buff); //print the array on serial monitor
      indx= 0; //reset button to zero
   }
}
廣告