SPI知识总结以及库函数编程

本文详细介绍了SPI(串行外设接口)的基本概念、优缺点、特点以及通信时序,强调了SPI的全双工、高速特性。同时,讨论了SPI的四种模式,解释了CPOL和CPHA参数对通信模式的影响。文章还涵盖了SPI编程的关键步骤,包括初始化、配置、数据传输及应用实例,旨在帮助读者理解和掌握SPI接口的使用。

SPI知识总结

1、SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一
种同步串行接口技术,是一种高速的,全双工,同步的通信总线。

2、SPI优点
支持全双工通信
通信简单
数据传输速率块

3、缺点
没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据 可靠性上有一定的缺陷。

4、特点
1):高速、同步、全双工、非差分、总线式
2):主从机通信模式

5、协议通信时序详解
1):SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多
个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共
有的,它们是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。
(1)SDO/MOSI – 主设备数据输出,从设备数据输入;
(2)SDI/MISO – 主设备数据输入,从设备数据输出;
(3)SCLK – 时钟信号,由主设备产生;
(4)CS/SS – 其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。需要注意的是,在具体的应用中,当一条SPI总线上连接有多个设备时,SPI本身的CS有可能被其他的GPIO脚代替,即每个设备的CS脚被连接到处理器端不同的GPIO,通过操作不同的GPIO口来控制具体的需要操作的SPI设备,减少各个SPI设备间的干扰。

SPI是串行通讯协议,也就是说数据是一位一位从MSB或者LSB开始传输的,这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,MISO、MOSI则基于此脉冲完成数据传输。 SPI支持4-32bits的串行数据传输,支持MSB和LSB,每次数据传输时当从设备的大小端发生变化时需要重新设置SPI Master的大小端。

2):需要说明的是,我们SPI通信有4种不同的模式,不同的从设备可能在出厂是就是配
置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们
可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:
Mode0:CPOL=0,CPHA=0
Mode1:CPOL=0,CPHA=1
Mode2:CPOL=1,CPHA=0
Mode3:CPOL=1,CPHA=1

时钟极性CPOL是用来配置SCLK的电平出于哪种状态时是空闲态或者有效态,时钟相位CPHA
是用来配置数据采样是在第几个边沿:
CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时
CPHA=0,表示数据采样是在第1个边沿,数据发送在第2个边沿
CPHA=1,表示数据采样是在第2个边沿,数据发送在第1个边沿

例如:
CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。

CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第2个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第2个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。

需要注意的是:我们的主设备能够控制时钟,因为我们的SPI通信并不像UART或者IIC通信
那样有专门的通信周期,有专门的通信起始信号,有专门的通信结束信号;所以我们的
SPI协议能够通过控制时钟信号线,当没有数据交流的时候我们的时钟线要么是
保持高电平要么是保持低电平。

编程要点:
1.初始化通信使用的目标引脚和端口时钟
2.使能SPI外设的时钟
3.配置SPI外设的模式、通信方式、数据帧长度、时钟极性和时钟相位、片选引脚的使用模式、波特率分频因子等
4.编写SPI按字节收发的函数
5.编写对FLASH擦除和读写的函数
6.编写测试函数



/*SPI接口定义-开头****************************/
#define      FLASH_SPIx                        SPI1
#define      FLASH_SPI_APBxClock_FUN          RCC_APB2PeriphClockCmd
#define      FLASH_SPI_CLK                     RCC_APB2Periph_SPI1

//CS(NSS)引脚 片选选普通GPIO即可
#define      FLASH_SPI_CS_APBxClock_FUN       RCC_APB2PeriphClockCmd
#define      FLASH_SPI_CS_CLK                  RCC_APB2Periph_GPIOC    
#define      FLASH_SPI_CS_PORT                 GPIOC
#define      FLASH_SPI_CS_PIN                  GPIO_Pin_0

//SCK引脚
#define      FLASH_SPI_SCK_APBxClock_FUN      RCC_APB2PeriphClockCmd
#define      FLASH_SPI_SCK_CLK                 RCC_APB2Periph_GPIOA   
#define      FLASH_SPI_SCK_PORT                GPIOA   
#define      FLASH_SPI_SCK_PIN                 GPIO_Pin_5
//MISO引脚
#define      FLASH_SPI_MISO_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define      FLASH_SPI_MISO_CLK                RCC_APB2Periph_GPIOA    
#define      FLASH_SPI_MISO_PORT               GPIOA
#define      FLASH_SPI_MISO_PIN                GPIO_Pin_6
//MOSI引脚
#define      FLASH_SPI_MOSI_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define      FLASH_SPI_MOSI_CLK                RCC_APB2Periph_GPIOA    
#define      FLASH_SPI_MOSI_PORT               GPIOA
#define      FLASH_SPI_MOSI_PIN                GPIO_Pin_7

#define          SPI_FLASH_CS_LOW()                             GPIO_ResetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )
#define          SPI_FLASH_CS_HIGH()                            GPIO_SetBits( FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN )

/*等待超时时间*/
#define SPIT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT         ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))

/*信息输出*/
#define FLASH_DEBUG_ON         1

#define FLASH_INFO(fmt,arg...)           printf("<<-FLASH-INFO->> "fmt"\n",##arg)
#define FLASH_ERROR(fmt,arg...)          printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
#define FLASH_DEBUG(fmt,arg...)          do{\
                                          if(FLASH_DEBUG_ON)\
                                          printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
                                          }while(0)
/*
* 函数名:main
* 描述  :主函数
* 输入  :无
* 输出  :无
*/
int main(void)
{
   
        
    LED_GPIO_Config();
    LED_BLUE;
    
    /* 配置串口为:115200 8-N-1 */
    USART_Config();
    printf("\r\n 这是一个8Mbyte串行flash(W25Q64)实验 \r\n");
    
    /* 8M串行flash W25Q64初始化 */
    SPI_FLASH_Init();
    
    /* 获取 Flash Device ID */
    DeviceID = SPI_FLASH_ReadDeviceID();    
    Delay( 200 );
    
    /* 获取 SPI Flash ID */
    FlashID = SPI_FLASH_ReadID();    
    printf("\r\n FlashID is 0x%X,\
    Manufacturer Device ID is 0x%X\r\n", FlashID, DeviceID);
    
    /* 检验 SPI Flash ID */
    if (FlashID == sFLASH_ID)
    {
   
       
        printf("\r\n 检测到串行flash W25Q64 !\r\n");
        
        /* 擦除将要写入的 SPI FLASH 扇区,FLASH写入前要先擦除 */
        // 这里擦除4K,即一个扇区,擦除的最小单位是扇区
        SPI_FLASH_SectorErase(FLASH_SectorToErase);         
        
        /* 将发送缓冲区的数据写到flash中 */
        // 这里写一页,一页的大小为256个字节
        SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);        
        printf("\r\n 写入的数据为:%s \r\t", Tx_Buffer);
        
        /* 将刚刚写入的数据读出来放到接收缓冲区中 */
        SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
        printf("\r\n 读出的数据为:%s \r\n", Rx_Buffer);
        
        /* 检查写入的数据与读出的数据是否相等 */
        TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
        
        if( PASSED == TransferStatus1 )
        {
   
   
            LED_GREEN;
            printf("\r\n 8M串行flash(W25Q64)测试成功!\n\r");
        }
        else
        {
   
           
            LED_RED;
            printf("\r\n 8M串行flash(W25Q64)测试失败!\n\r");
        }
    }// if (FlashID == sFLASH_ID)
    else// if (FlashID == sFLASH_ID)
    {
   
   
        LED_RED;
        printf("\r\n 获取不到 W25Q64 ID!\n\r");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值