Advertisement

SPI总线协议

阅读量:
复制代码
    SPI总线概述

SPI全称是串行外设接口(Serial Peripheral Interface),是由Motorola提出的一种全双工同步串行通信接口,通信波特率可以高达5Mbps,但具体速度大小取决于SPI硬件。SPI接口具有全双工操作,操作简单,数据传输速率较高的优点,但也存在没有指定的流控制,没有应答机制确认是否接收到数据的缺点。

SPI总线的构成及信号类型
SPI总线只需四条线(如图1所示)就可以完成MCU与各种外围器件的通讯:
1)MOSI – Master数据输出,Slave数据输入
2)MISO – Master数据输入,Slave数据输出
3)SCK – 时钟信号,由Master产生

4)CS – Slave使能信号,由Master控制。

SPI一主多从模式。

由此可以看出,每个SPI从机的片选端都要与主机的片选端一一对应,这是很浪费资源的。

在一个SPI时钟周期内,会完成如下操作:

  1. Master通过MOSI线发送1位数据,同时Slave通过MOSI线读取这1位数据
  2. Slave通过MISO线发送1位数据,同时Master通过MISO线读取这1位数据
    Master和Slave各有一个移位寄存器,如图所示,而且这两个移位寄存器连接成环状。依照SCK的变化,数据以MSB first的方式依次移出Master寄存器和Slave寄存器,并且依次移入Slave寄存器和Master寄存器。当寄存器中的内容全部移出时,相当于完成了两个寄存器内容的交换。

SPI的四种工作模式
CPOL:时钟极性选择,为0时SPI总线空闲为低电平,为1时SPI总线空闲为高电平
CPHA:时钟相位选择,为0时在SCK第一个跳变沿采样,为1时在SCK第二个跳变沿采样
工作方式1:
当CPHA=0、CPOL=0时SPI总线工作在方式1。MISO引脚上的数据在第一个SPSCK沿跳变之前已经上线了,而为了保证正确传输,MOSI引脚的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,首先将数据上线,然后在同步时钟信号的上升沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(下降沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。
工作方式2:
当CPHA=0、CPOL=1时SPI总线工作在方式2。与前者唯一不同之处只是在同步时钟信号的下降沿时捕捉位信号,上升沿时下一位数据上线。
工作方式3:
当CPHA=1、CPOL=0时SPI总线工作在方式3。MISO引脚和MOSI引脚上的数据的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,在同步时钟信号周期开始时(上升沿)数据上线,然后在同步时钟信号的下降沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(上升沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。
工作方式4:
当CPHA=1、CPOL=1时SPI总线工作在方式4。与前者唯一不同之处只是在同步时钟信号的上升沿时捕捉位信号,下降沿时下一位数据上线。

SP1与SP3的差别
SP1与SP3的差别是对数据的采样时间点不同,SP1是在第一个跳变沿采样,SP3是在第二个跳变沿采样,此外,SP1中在传输最高位时MOSI、MISO上的数据是不同步的,MISO上的数据要先与MOSI上的数据的出现,它们在第二个时钟周期才同步。而SP3 MOSI、MISO在第一个时钟周期的上升沿已经同步了。

软件模拟SPI

注意:下面的程序都没有涉及SS线。

SP1模式:CPHA=0、CPOL=0

复制代码
 /*IO定义*/

    
 #define MOSI P0^0
    
 #define MISO P0^1
    
 #define SCK  P0^2
    
 /*函数功能:模式SPI*/
    
 /*参数说明:data要发送的数据*/
    
 /*返回值:接收到的数据*/
    
 unsigned  char spi_simulate(unsigned char data)
    
 {
    
     unsigned char i;
    
    	for(i=0;i<8;i++)          // 循环8次
    
    	{
    
 	  if(data&0x80)           //若要发送的数据最高位为1
    
 	    MOSI=1;               //则将1送到MOSI线上
    
 	  else
    
 	    MOSI=0;        // 则将0送到MOSI线上
    
    	  data<<=1;     //最高位已经发送出去,将data左移一为腾出最低位来存放接收到的数据
    
    	  SCLK=1;       //拉高SCK
    
    	  delay();      //根据传输速率来做调整
    
    	 /*拉高SCK后,从机从MOSI读入1位数据,同时主机从MISO接收1位数据,如*/
    
    	 /*果MISO输出的是0则不需要date|=0x01,因为data<<1后会在低位自动补0,如果MISO输出的是1,则byte最低位要置1*/
    
 	  if(MISO)    
    
    	    data|=0x01;     
    
    	  SCLK=0;           // SCK置低,低电平表示空闲
    
    	  delay();  //根据传输速率来做调整
    
    	}
    
     return(data);           	// 返回读出的一字节
    
 }

SP2模式:CPHA=0、CPOL=1

复制代码
 /*IO定义*/

    
 #define MOSI P0^0
    
 #define MISO P0^1
    
 #define SCK  P0^2
    
 /*函数功能:模式SPI*/
    
 /*参数说明:data要发送的数据*/
    
 /*返回值:接收到的数据*/
    
 unsigned  char spi_simulate(unsigned char data)
    
 {
    
     unsigned char i;
    
    	for(i=0;i<8;i++)          // 循环8次
    
    	{
    
 	  if(data&0x80)           //若要发送的数据最高位为1
    
 	    MOSI=1;               //则将1送到MOSI线上
    
 	  else
    
 	    MOSI=0;        // 则将0送到MOSI线上
    
    	  data<<=1;     //最高位已经发送出去,将data左移一为腾出最低位来存放接收到的数据
    
    	  SCLK=0;       //拉低SCK
    
    	 /*拉高SCK后,从机从MOSI读入1位数据,同时主机从MISO接收1位数据,如*/
    
    	 /*果MISO输出的是0则不需要date|=0x01,因为data<<1后会在低位自动补0,如果MISO输出的是1,则byte最低位要置1*/
    
 	  if(MISO)    
    
    	    data|=0x01;     
    
    	  SCLK=1;           // SCK置高,低电平表示空闲
    
    	}
    
     return(data);           	// 返回读出的一字节
    
 }

SP3模式:CPHA=1、CPOL=0

复制代码
 /*IO定义*/

    
 #define MOSI P0^0
    
 #define MISO P0^1
    
 #define SCK  P0^2
    
 /*函数功能:模式SPI*/
    
 /*参数说明:data要发送的数据*/
    
 /*返回值:接收到的数据*/
    
 unsigned  char spi_simulate(unsigned char data)
    
 {
    
     unsigned char i;
    
    	for(i=0;i<8;i++)          // 循环8次
    
    	{
    
    	    SCLK=1;       //拉高SCK
    
    	    delay();      //根据传输速率来做调整
    
 	    if(data&0x80)           //若要发送的数据最高位为1
    
 	        MOSI=1;               //则将1送到MOSI线上
    
 	    else
    
 	        MOSI=0;        // 则将0送到MOSI线上
    
    	    data<<=1;     //最高位已经发送出去,将data左移一为腾出最低位来存放接收到的数据
    
    	    SCLK=0; 
    
    	    delay();  //根据传输速率来做调整
    
    	    /*拉低SCK后,从机从MOSI读入1位数据,同时主机从MISO接收1位数据,如*/
    
    	    /*果MISO输出的是0则不需要date|=0x01,因为data<<1后会在低位自动补0,如果MISO输出的是1,则byte最低位要置1*/
    
 	    if(MISO)    
    
    	        data|=0x01;     
    
    	}
    
     return(data);           	// 返回读出的一字节
    
 }

SP4模式:CPHA=1、CPOL=1

复制代码
 /*IO定义*/

    
 #define MOSI P0^0
    
 #define MISO P0^1
    
 #define SCK  P0^2
    
 /*函数功能:模式SPI*/
    
 /*参数说明:data要发送的数据*/
    
 /*返回值:接收到的数据*/
    
 unsigned  char spi_simulate(unsigned char data)
    
 {
    
     unsigned char i;
    
    	for(i=0;i<8;i++)          // 循环8次
    
    	{
    
    	    SCLK=0;       //拉高SCK
    
    	    delay();      //根据传输速率来做调整
    
 	    if(data&0x80)           //若要发送的数据最高位为1
    
 	        MOSI=1;               //则将1送到MOSI线上
    
 	    else
    
 	        MOSI=0;        // 则将0送到MOSI线上
    
    	    data<<=1;     //最高位已经发送出去,将data左移一为腾出最低位来存放接收到的数据
    
    	    SCLK=1; 
    
    	    delay();  //根据传输速率来做调整
    
    	    /*拉低SCK后,从机从MOSI读入1位数据,同时主机从MISO接收1位数据,如*/
    
    	    /*果MISO输出的是0则不需要date|=0x01,因为data<<1后会在低位自动补0,如果MISO输出的是1,则byte最低位要置1*/
    
 	    if(MISO)    
    
    	        data|=0x01;     
    
    	}
    
     return(data);           	// 返回读出的一字节
    
 }

图片的出处请看下标

全部评论 (0)

还没有任何评论哟~