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
   }
}
广告