SPI一共有四根信号线CS、CLK、MOSI、MISO 从设备选择信号线、串行SPI通信的时钟信号、主设备输出从设备输入、主设备输入从设备输出信号线。在硬件上主设备和从设备的两条数据线MOSI和MISO要相互交叉连接(个人理解成串口通信时的TX发接RX,RX接TX)。SPI的数据采集和传输依赖于CLK,一个周期的时钟移动一个位的数据。下面是SPI的时序图,从图中可以看出CPHA和CPOL的作用和意义。
![](https://i-blog.csdnimg.cn/blog_migrate/6d6d2be76d70cbaa424a61b03c70eaed.jpeg)
从SPI的时序图可以明显的看出CPHA的作用是控制数据采样的点如CPHA=1时数据在跳变后一个时钟采样,上升沿采样还是下降沿采样数据由CPOL决定(也决定了CLK空闲时刻的电平情况)。所以我们在使用单片机自带的硬件SPI的时候这些配置就很重要了,这关系到是否能通讯成功。
SPI的配置一般有以下步骤:1、配置SPI的硬件SPI相应的引脚。2、开启GPIO时钟和SPI时钟。3、配置SPI的主从模式。4、配置SPI的CPHA和CPOL。5、配置SPI的数据宽度。6、配置SPI的移位是LSB或者是MSB。7、配置SPI的传输速度。8、如有多个SPI的一半还有SPI的选择配置。一般大致就是这些就基本OK了。
下面是谋产品的SPI的通信时序图。
从该图给出的时序图就知道需要配置CPHA=1,CPOL=0;即时钟空闲的时候为低电平状态,当被主设备选中CS拉低之后的时钟在跳变后的下降沿采样数据。
当然在编写SPI的读写程序的时候也需要注意一点,写数据的时候将数据放到SPI的发送寄存器的时候会自动产生硬件的时钟CLK和数据写的电平。但是读数据的时候需要SPI主设备的发送空数据来产生时钟使从设备的数据移位到主设备中。
SPI的读写程序:
void SPI_write(u8 addr, u32 data,u8 len)
{
uint8_t i,B;
GPIO->PBCLR =1<<4;
SPI->STA |=0<<0;
SPI->TX = (1<<7)|(0XFF&addr); //起始第一位为1是写数据
while(SPI->STA&0X10);
for(i=len;i>0;i--)
{
B=(data>>8*(i-1));
SPI->STA |=0<<0;
SPI->TX = 0XFF&B;
while(SPI->STA&0X10);
}
GPIO->PBSET = 1<<4;
}
u32 SPI_Read(u8 addr,u8 len)
{
uint32_t ReadData,B;
uint8_t i;
GPIO->PBCLR =1<<4;
SPI->STA |=0<<0;
SPI->TX = 0Xff&addr;
while(SPI->STA&0X10);
for(i=0;i<len;i++)
{
SPI->STA |=0<<0;
SPI->TX = 0Xff; //读从设备数据的时候发送空数据产生时钟CLK
while(SPI->STA&0X10);
ReadData = (ReadData <<8)|(SPI->RX &0XFF); //数据移位
}
GPIO->PBSET = 1<<4;
return ReadData;
}
记录自己对SPI的理解。