SPI理解

来源:互联网 发布:单片机数码管显示0到9 编辑:程序博客网 时间:2024/06/08 17:05

SPI中分Master主设备和Slave从设备,数据发送都是由Master控制。

一个master可以接一个或多个slave

常见用法是一个Master接一个slave,只需要4根线: 

SCLKSerial Clock,(串行)时钟

MISOMaster In Slave Out,主设备输入,从设备输出

MOSIMaster Out  Slave In,主设备输出,从设备输入

SS:      Slave Select,选中从设备,片选

配置步骤:

1.一般的控制器(51单片机或者m3)的spi配置为主设备,传感器什么的是从设备。

2.配置主机的相关接口为spi模式

3.需要配置时钟,主机需要配置时钟,时钟配置可以根据主机读取数据快慢配置,同时也要考虑从设备的数据被获取速度(一般从设备可能有推荐的频率为多少)。

4.配置CPOL(时钟极性)和CPHA(时钟相位),两个的意思可以看上一篇博客,这两个的配置需要根据SPI从机读写数据要求来进行配置,一般从设备(SPI传感器)手册上面都会有说明。

5.。。。。。主机只有在发送的时候才有时钟,所以接收数据时候,需要发送一个无关数据来为接收数据过程提供时钟。(接收数据时候也需要时钟)

 

对于,SPI调试,可以用示波器进行调试。

1,用示波器看看SCLK这个是否有时钟(初始化完就应该有时钟),时钟是否对

2,用示波器看看MOSI(先做一个写函数)主设备发送的数据是否正确。

3,用示波器,然后在添加读函数,看看如(读取的ID号是否真确。)

 

4,,注意只有发送的时候才有时钟,接收也需要时钟。所以接收时候需要发送一个无关数据来提供时钟。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

下面是CC2541SPI配置说明:

 

 

CLKCONCMD = 0x80; while (CLKCONSTA != 0x80);        // 32MHz配置为32m晶振

// SPI Master Mode

PERCFG |= 0x00;        // map USART0 to its alternative 1 location. P0_2: SSN, P0_3: SCK, P0_4: MOSI, P0_5: MISO

P0SEL |= 0x3C;        // P0,2,3,4,5 are peripherals

P0SEL &= ~0x10;        // P0_4 is GPIO (SSN)

P0DIR |= 0x10;        // SSN is set as output,复位为0是输入模式

U0CSR &= ~0xA0;    // SPI Master Mode  CPOL=0CPHA=0

   U0CSR |= 0x40;           //允许接收 

//P1DIR &= ~0x80;// p1.7 as Input,这个不知道是否初始化

//P1 |= 0x10;   //P1.4初始化为高电平   spi片选低电平使能

U0BAUD = 0x00;

    U0GCR = 0x2F;    //cp0l=0,cpha=0,msb first , baud_e=15

比如下面的写函数:

 

void SPI0writeonebyte(uchar value)

{   P0_4 = 0;        // SSN LOW

       U0CSR &= ~0x02;                 // Clear TX_BYTE         

      U0DBUF = value;        

    while (!(U0CSR & 0x02));        // Wait for TX_BYTE to be set

P0_4 = 1;        // SSN high}

 

 这个SPI是低电平时候选通,同时需要发送的数据值,直接放到U0DBUF 中,然后查询发送是否完成即可。

 

void SPI0readregister(uchar value)

{

P0_4 = 0;        // SSN LOW

    U0CSR &= ~0x02;                 // Clear TX_BYTE         

   U0DBUF = 0xFF;   //这里随便发送一个数据,如00或者ff     

while (!(U0CSR & 0x02));        // Wait for TX_BYTE to be set

value = U0DBUF;

    P0_4 = 1;        // SSN high

  }

接收字节就不好理解了,这里是先随便发送一个字节,然后发送完后在读取U0DBUF值。首先对于发送数据是在线MOSI上面,而接收的数据是在MISO上面,当在mosi上面发送ff,然后在miso上面就会收到从机返回的数据。数据都是放在U0DBUF中的,为什么要先发送一个随便的字节,应为只有发送的时候才有时钟,才能收取从机返回的数据。(而这个顺便发送的字节对于从机来说是没有意思,只是主机这个时候有时钟,可以读取从机数据)

 

下面举一个读取ADXL362数据的例子,读取其ID

首先,写入读命令,写入读的地址,写一个空字节,读取数据。

P0_4 = 0;        // SSN LOW

    U0CSR &= ~0x02;                 // Clear TX_BYTE         

   U0DBUF = 0x0B;       //先传送一个读命令0B   

while (!(U0CSR & 0x02));        // Wait for TX_BYTE to be set

    U0CSR &= ~0x02;                 // Clear TX_BYTE         

   U0DBUF = 0x02;  //发送需要读的地址0X02,在这个地址读数据    

while (!(U0CSR & 0x02));        // Wait for TX_BYTE to be set

    U0CSR &= ~0x02;                 // Clear TX_BYTE         

   U0DBUF = 0xFF;   //这里随便发送一个数据,如00或者ff 为读                          取提供时钟 ,前面已经写了地址,这个时候 MISO上面就会返回器件ID号,只是需要在MOSI上面提供时钟,(这个时候在MOSI上面在继续发送FF,是不会影响接收的,无非就是提供时钟)  

while (!(U0CSR & 0x02));        // Wait for TX_BYTE to be set

value = U0DBUF;  //前面提供时钟的发送,和这个读取是同时进行的,前面发送完,这个U0DBUF中就会读到ADXL362返回的数据。

    P0_4 = 1;        // SSN high

 

1 0
原创粉丝点击