什么是SPI

SPI通常有一个主设备和一个或多个从设备,通常采用的是4根线,它们是MISO(数据输入,针对主机来说)、MOSI(数据输出,针对主机来说)、SCLK(时钟,主机产生)、CS/SS(片选,一般由主机发送或者直接使能,通常为低电平有效)。全双工。

SPI 物理层

image-20230220102559280

一个主机可以连接多个从机,其中SCK,MOSI,MISO所有从机共用。SSx单独连接主机。当主机需要和从机通信时,主机把对应的从机的SSx线拉低。从机发现自己的SSx线被拉低,则表示主机要和它通信了。对比IIC,SPI不需要外接上拉电阻,也不需要广播地址来寻机。

SPI协议层

SPI只有开始信号,停止信号,和数据有效性信号,读写信号(同步的)。相比IIC,少了应答机制。

  • 开始信号:NSS被拉低的下降沿(SSx、CS。都叫做使能线,片选线。叫法很多,作用一样 都是让从机使能通信)

  • 停止信号:NSS被拉高的上升沿。

  • 触发。表示主机读一位从机的数据,从机读一位主机的数据。
  • 采样。表示总线的上数据已就绪,可以读了。采样后,MISO、MOSI线上的数据被锁存直到被转移。

SPI的4种模式

SPI的4种模式,先说一下两个概念:时钟极性CPOL和时钟相位CPHA。CPOL和CPHA均有0 1两种状态,组合成4种状态。

时钟极性(CPOL)

指 SPI 通讯设备处于空闲状态时,SCK 信号线的电平信号(即 SPI 通讯开始前、 NSS 线为高电平时 SCK 的状态)。

CPOL=0 时, SCK 在空闲状态时为低电平①,在SCK有效期间为高电平 ②

CPOL=1 时,SCK 在空闲状态时为高电平③,在SCK有效期间为低电平 ④

image-20230220103812802

时钟相位(CPHA)

是指数据的采样的时刻

CPHA=0 时,MOSI 或 MISO 数据线上的信号在 SCK 时钟线的“奇数边沿” 被采样。

CPHA=1 时,MOSI 或 MISO数据线的信号在 SCK 的“偶数边沿” 采样。

image-20230220104042456

具体用哪种模式,还得看传感器设备需要那种方式,4种模式如下表:

image-20230220103529502

软件模拟SPI(模式0)

SPI发送函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void SPI_Write(uint8_t Data)
{
uint8_t i=0;
CS_L; //片选拉低开始传输数据
SCK_L;
/*循环8次,发送8bit数据*/
for(i=0;i<8;i++)
{
/*切换数据*/
if(Data&0x80)//通过8次循环移位,将一个字节的数据,由高到低一位一位的放置到数据线上
{
MOSI_H;
}
else
{
MOSI_L;
}
SCK_H; //产生上升沿(从机在此上升沿时采集数据)
delay_us(5);//(这个延时根据通讯的设备来看)
SCK_L;//拉回低电平
delay_us(5);
Data <<= 1;
}
MOSI_L;
SCK_L;
CS_H;//片选拉高等待下次数据传输
}

SP接收函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
uint8_t MISO_sate;//这个是要定义为输入引脚的状态,就是GPIO配置成输入引脚接收的状态位

uint8_t SPI_Read(void)
{
uint8_t i=0;
uint8_t receive_temp=0;
CS_L; //片选拉低开始传输数据
SCK_L;
/*循环8次,发送8bit数据*/
for(i=0;i<8;i++)
{
receive_temp <<=1;
SCK_H; //产生上升沿(从机在此上升沿时采集数据)
delay_us(5);//(这个延时根据通讯的设备来看)
/*切换数据*/
if(MISO_sate == MISO_H)//通过8次循环移位,将一个字节的数据,由高到低一位一位的放置到数据线上
{
receive_temp |= 1;
}
else
{
receive_temp |= 0;
}
SCK_L;//拉回低电平
delay_us(5);
}
SCK_L;
CS_H;//片选拉高等待下次数据传输
return receive_temp;
}