Arduino - SPI 通信
串行外设接口(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 时钟设置为系统时钟频率的四分之一(5 Mhz 用于 20 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
:引脚 10MOSI
:引脚 11MISO
:第 12 针SCK
:引脚 13
将两个板子共地。以下是两块板之间连接的图示 -
让我们看一下 SPI 作为 Master 和 SPI 作为 Slave 的例子。
SPI 作为 MASTER
例
#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 作为 SLAVE
例
#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
}
}