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); //将 usart 的波特率设置为 115200
digitalWrite(SS, HIGH); // 禁用从属选择
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);//将时钟除以 8
}

void loop (void) {
char c;
digitalWrite(SS, LOW); // 启用从属选择
// 发送测试字符串
for (const char * p = "Hello, world!
" ; c = *p; p++) {
SPI.transfer (c);
Serial.print(c);
}
digitalWrite(SS, HIGH); // 禁用从属选择
delay(2000);
}

SPI 作为从属设备

示例

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

void setup (void) {
    Serial.begin (115200);
    pinMode(MISO, OUTPUT); // 必须在主机上发送,因此将其设置为输出
    SPCR |= _BV(SPE); // 在从属模式下打开 SPI
    indx = 0; // 缓冲区为空
    process = false;
    SPI.attachInterrupt(); // 打开中断
}
ISR (SPI_STC_vect) // SPI 中断例程
{
    byte c = SPDR; // 从 SPI 数据寄存器读取字节
    if (indx < sizeof buff) {
        buff [indx++] = c; // 将数据保存在数组 buff 中的下一个索引中
        if (c == '
        ') //检查单词的结尾
        process = true;
    }
}

void loop (void) {
    if (process) {
        process = false; //重置进程
        Serial.println (buff); //在串行监视器上打印数组
        indx= 0; //将按钮重置为零
    }
}