×
单片机 > 单片机程序设计 > 详情

arm底层通讯协议之SPI通讯

发布时间:2020-06-08 发布时间:
|

1、基本概念区分


    (1)SPI和SSP区别


        可能很多人在其他的地方都多次到过SPI和SSP,比如爱NXP的LPC11XX系列的SOC手册中多次出现SSP,这里作统一区分:SSP(Synchronize Serial Port,同步串行口)和SPI(Serial Peripheral Interface,串行外设接口)。SSP是在SOC和一些串行外部设备通信的通信模块,他有两种工作模式:SPI和IIC。


    (2)SPI协议和代码关系


        我们在使用SPI接口进行数据通信的时候,之所以要了解SPI通信协议的原因是我们需要了解SPI通信协议原理。虽然实际硬件通讯硬件电路已经做好了,但是我们还是需要通过配置寄存器来实现SPI通讯时序,所以说还是要学会SPI通信原理的。


        了解SPI通信原理只是第一步,第二步是阅读硬件用户手册,根据手册指示编写配置寄存器代码,实现基本配置(时钟频率、数据帧格式、引脚功能等),第三步就是实际收发接口程序编写。


2、SPI硬件接口



    通过上图可以知道,首先SPI通信有4线:SCK(同步时钟信号)、MISO(主接收从发送)、MOSI(主发送从接收)、NSS(片选信号)。SPI通信最少3根线:SCK同步时钟、NSS(或者CS)片选信号、MISO或者MOSI。


    SCK:作为同步通信的时钟,指示什么时候开始/结束通讯,以及中间数据传输(主设备什么时候发送,从设备什么时候接收)。时钟由主设备发出,控制。


    MISO:SPI通信分为主设备(Master)和从设备(Slave),主设备intput,从设备output


    MOSI:主设备发送(output输出),从设备接收(intput输入)


    NSS:SPI通信分为一主多从,主设备要想从多个从设备中选中和哪个从设备通信,直接将和从设备连接的NSS引脚拉低即可。这个和IIC不一样,IIC直接发送从设备ID来选择从设备。


3、专业术语解释


    (1)空闲态


        指的是SPI总线上没有数据发送时候的状态。


    (2)时钟极性(CPOL)


        SCK时钟线,在SPI总线空闲时候,所处的电平状态(帧与帧之间的状态):


            CPOL = 0,SCK空闲时,主设备持续发送低电平


            CPOL = 1,SCK空闲时,主设备持续发送高电平


    (3)时钟相位(CPHA)


        时钟相位,实际指的就是发送和接受双方如何协调收发:


            CPHA = 0,无论收发方,在第一个边沿(上升沿还是下降沿看CPOL=0还是1)处采样(读取数据),在第二个边沿处发送数据


            CPHA = 1,在第二个边沿处(上升沿还是下降沿看CPOL=0还是1)处采样(读取数据),在第一个边沿处发送数据。


4、SPI通信协议


    SPI通信协议总结起来就是一句话,解决SPI通信问题:


    (1)数据发送高位在前还是低位在前:比如0x55(0101 0101),先发送第0位的1还是第7位的0?


        高位在前,先发送0(MSB),最后发送1(LSB)


    (2)怎么区分正在发送数据还是处在空闲,例如0xff(1111 1111):区分空闲和数据发送?


        在开始发送之前SCK处在空闲态(根据CPOL时钟极性设置规定,持续输出高电平(CPOL=1)或者低电平(CPOL=0)),开始发送时候,主设备会控制SCK发生变化(低电平转高电平,高电平转换低电平),知道数据发送完,SCK会继续回到空闲状态(持续输出高电平或者低电平)。


    (3)发送方什么时候发送?


        根据CPHA时钟相位设置,向数据线上放数据:CPHA=1,在第一个边沿处,向数据线上放数据(发送),CPHA=0,在第二个边沿处,向数据线上放数据(发送)


    (4)接收方什么时候接收?


        根据CPHA设置采样(读取数据):CPHA=1,在第二个边沿处,从数据线上采样(读取数据),CPHA=0,在第一个边沿处,从数据线上采样(读取数据)。


    (5)总结


        从上图可以看出SPI通信双方内部的基本结构,在主设备在发送的时候,从设备也在发送,只不过主设备发送的数据是我们(程序员)放进去的有效数据,但是从设备发送过来的数据确是不确定的(当然我们也可以自己指定垃圾数据,比如0xff或者0x00)。


        所以SPI通信的特点就是,发送方发送数据的时候,是将实现准备好的有效数据在CPHA规定的边沿发送出去的(比如MOSI上,主设备发送数据),同一时刻从设备也在CPHA规定的边沿发送数据(比如MISO上,从设备发送),然后在CPHA规定的采样边沿处,收发双方都会从MOSI或者MISO上去采样(读取数据)。总结起来就是一句话:发送方发送数据的同时,接收方也在发送数据,只不过发送方发的是实际有意义的数据,接收方发送的是无效垃圾数据(这是SPI通信方式所限定的)。


5、LPC11C14平台特点


    在开始在LPC11C14平台上编写SPI通信代码接口之前,将这几个问题搞明白就可以了:


    (1)既然SPI都是一位一位的传送的,那么我(程序员)发送或者接收的时候可是都以byte为单位的,怎么去界定已经发送完或者接收完一个byte?



        在LPC11C14的芯片手册中,可以知道,整个SPI的传输都是以8bit一个字节为单位的(一帧),当帧传输完成时,如果想要传输多个字节,在每个字节传输后,释放总线(还原SCK到空闲态,拉高NSS片选线),这样会将SPI标记寄存器中关于接受和发送标记置位。


    (2)发送和接受有没有FIFO?FIFO的大小是多少?


        LPC11C14上发送和接受的FIFO是公用一个的(环路收发),都是2字节(16bit)


    (3)发送和接受方式是轮训?还是中断?


        SPI的接收和发送均是轮训方式的,当然也可以设置成中断(SSP0IMSC寄存器,半满中断(FIFO收够1个字节)),建议不这么做,因为单个byte就产生一次中断,中断次数太频繁,容易打断CPU主程序执行


    (4)需要写几个接口?每个接口什么功能?


        需要至少2个接口:


            a、SPI初始化配置接口:void spi__0_config(void)


                完成相关引脚功能、时钟选择和分频、SPI通信帧格式、主从角色设置、时钟极性和时钟相位设置


/****************************************************

* 函数名称:spi_0_config

* 功能描述:配置SPI通讯接口:引脚功能、时钟频率、主从模式、数据帧格式

* 参数:无

* 返回值:无

*****************************************************/

void spi_0_config(void)

{

//1、spi引脚初始化:CLK-PIO0_6,MOSI0-PIO0_9,MISO-PIO0_8,C/S-PIO2_4

    LPC_IOCON->PIO0_9 &= ~(0x7<<0);

    LPC_IOCON->PIO0_9 |= (1<<0); //MOSI0

    LPC_IOCON->PIO0_8 &= ~(0x7<<0);

    LPC_IOCON->PIO0_8 |= (1<<0); //MISO0

    LPC_IOCON->PIO0_6 &= ~(0x7<<0);

    LPC_IOCON->PIO0_6 |= (2<<0); //SCK0

    

    //2、设置SCK0管脚时钟功能

    LPC_IOCON->SCK_LOC &= ~(0x3<<0);

    LPC_IOCON->SCK_LOC |= (2<<0);

    

    //3、设置SSP0总线时钟使能

    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);

    

    //4、SPI时钟分频设置

    LPC_SYSCON->SSP0CLKDIV &= ~(0xff<<0);

    LPC_SYSCON->SSP0CLKDIV |= 2<<0;

    

    //5、关闭SSP0复位

    LPC_SYSCON->PRESETCTRL |= (1<<0);

    

    

    //6、使能GPIO时钟输出功能:SPI的SCK输出

    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);

    

    //7、设置SPI的偏选引脚为输出功能:PIO2_4

    LPC_IOCON->PIO2_4 &= ~(0x7<<0);

    LPC_GPIO2->DIR |= (1<<4); //设置PIO2_4引脚为输出功能

    LPC_GPIO2->DATA |= (1<<4); //设置PIO2_4引脚输出高电平(默认悬空不选中)

    

    

    //8、SPI通讯时钟选择、总线类型、数据长度设置

    LPC_SSP0->CR0 &= ~(0xf<<0);

    LPC_SSP0->CR0 |= (7<<0); //设置帧长度为8bit

    LPC_SSP0->CR0 &= ~(3<<4); //设置帧格式为SPI

    LPC_SSP0->CR0 &= ~(3<<6); //SPI时钟极性为低电平,在第一个边沿采样,第二个边沿输出

    

    LPC_SSP0->CR0 &= ~(0xf<<8);

    LPC_SSP0->CR0 |= (7<<8); //设置时钟分频因子7+1

    

    LPC_SSP0->CPSR = 2;//分频结果 = 48MHz/(2*(7+1)) = 3MHz

    

    //9、设置SPI通讯模式为主设备模式,使能SPI

    LPC_SSP0->CR1 &= ~(0xf<<0);

    LPC_SSP0->CR1 |= (1<<1);

}


b、spi收发接口:unsigned short spi_put_get(unsigned


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址