• STM32(13)——SPI


    简介:

      SPI,Serial Peripheral interface串行外围设备接口。

      接口应用在:EEPROM, FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。

      特点:高速的、全双工、同步的通信总线、占用4根线;可以同时发生和接收串行数据;可以当做主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

      接口使用的4条通讯线

    1. MISO  主设备数据输入,从设备数据输出
    2. MOSI  主设备数据输出,从设备数据输入
    3. SCLK  时钟信号,由主设备产生
    4. CS      从设备片选信号,由主设备控制

      SPI的功能很强大,SPI时钟最多可以到18Mhz,支持DMA,可以配置为SPI协议或者I2S协议。

      使用STM32的SPI的主模式,配置步骤如下:

    1.配置相关引脚的复用功能,使能SPI2时钟

      第一步就要使能 SPI2 的时钟。其次要设置 SPI2 的相关引脚为复用输出,这样才会连接到SPI2上,否则这些IO口还是默认的状态,也就是标准的输入输出口。这里我们使用PB13、14、15这三个(SCK、MISO、MOSI、CS使用软件管理方式)所以设置这三个复用IO。

    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//PORTB 时钟使能 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );//SPI2 时钟使能   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   //PB13/14/15 复用推挽输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIOB
    
    2.初始化SPI2,设置SPI2工作模式

      接下来我们要初始化 SPI2,设置 SPI2 为主机模式设置数据格式为 8 位,然设置 SCK 时钟极性及采样方式。并设置 SPI2 的时钟频率(最大 18Mhz),以及数据的格式(MSB 在前还是LSB 在前)。

      这在库函数中是通过 SPI_Init 函数来实现的。

    void SPI_Init(SPI_TypeDef* SPIx,SPI_InitTypeDef* SPI_InitStruct);
    

      第一个参数为SPI标号,这里使用的SPI2;第二个参数是定义SPI_InitTypeDef结构体指针

    typedef struct
    {
    uint16_t SPI_Direction; 
    // 设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式
    uint16_t SPI_Mode; 
    // 设置 SPI 的主从模式
    uint16_t SPI_DataSize; 
    // 为 8 位还是 16 位帧格式选择项
    uint16_t SPI_CPOL;
     // 设置时钟极性
    uint16_t SPI_CPHA; 
    // 设置时钟相位
    uint16_t SPI_NSS;   
    //设置 NSS 信号由硬件(NSS 管脚)还是软件控制
    uint16_t SPI_BaudRatePrescaler;  
    //设置 SPI 波特率预分频值
    uint16_t SPI_FirstBit;   
     //设置数据传输顺序是 MSB 位在前还是 LSB 位在前
    uint16_t SPI_CRCPolynomial;
     //设置 CRC 校验多项式,提高通信可靠性,大于 1 即可
    }SPI_InitTypeDef;

    第一个参数 SPI_Direction 是用来设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式,这里我们选择全双工模式 SPI_Direction_2Lines_FullDuplex。

    第二个参数 SPI_Mode 用来设置 SPI 的主从模式,这里我们设置为主机模式 SPI_Mode_Master,当然有需要你也可以选择为从机模式 SPI_Mode_Slave。

    第三个参数 SPI_DataSiz 为 8 位还是 16 位帧格式选择项,这里我们是 8 位传输,选择SPI_DataSize_8b。

    第四个参数 SPI_CPOL 用来设置时钟极性,我们设置串行同步时钟的空闲状态为高电平所以我们选择 SPI_CPOL_High。

    第五个参数 SPI_CPHA 用来设置时钟相位,也就是选择在串行同步时钟的第几个跳变沿(上升或下降)数据被采样,可以为第一个或者第二个条边沿采集,这里我们选择第二个跳变沿,所以选择 SPI_CPHA_2Edge

    第六个参数 SPI_NSS 设置 NSS 信号由硬件(NSS 管脚)还是软件控制,这里我们通过软件控制 NSS 关键,而不是硬件自动控制,所以选择 SPI_NSS_Soft。

    第七个参数 SPI_BaudRatePrescaler 很关键,就是设置 SPI 波特率预分频值也就是决定 SPI 的时钟的参数 , 从不分频道 256 分频 8 个可选值,初始化的时候我们选择 256 分频值SPI_BaudRatePrescaler_256,  传输速度为 36M/256=140.625KHz。

    第八个参数 SPI_FirstBit 设置数据传输顺序是 MSB 位在前还是 LSB 位在前, ,这里我们选择SPI_FirstBit_MSB 高位在前。

    第九个参数 SPI_CRCPolynomial 是用来设置 CRC 校验多项式,提高通信可靠性,大于 1 即可。

      设置好9个参数,初始化SPI外设,范例:

    SPI_InitTypeDef   SPI_InitStructure;
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;   //双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;    //主 SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;  // SPI 发送接收 8 位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//串行同步时钟的空闲状态为高电平 
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二个跳变沿数据被采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  //NSS 信号由软件控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;  //预分频 256
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;  //数据传输从 MSB 位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;  //CRC 值计算的多项式
    SPI_Init(SPI2, &SPI_InitStructure);   //根据指定的参数初始化外设 SPIx 寄存器
    
    3.使能SPI2

      初始化完成之后就是使能SPI2通信,使能SPI2通信后,就可以开始SPI通讯。

      使能SPI2的方法是:

    SPI_Cmd(SPI2,ENABLE);  //使能SPI外设
    
    4.SPI传输数据  

    固体库提供的发送数据函数原型为:

    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
    

      表示从SPIx数据寄存器写入数据Data从而实现发送。

    固体库提供的接收数据函数原型为:

    uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;
    

      表示从SPIx数据寄存器读出接收到的数据。

    5.查看SPI传输状态

      在 SPI 传输过程中,我们经常要判断数据是否传输完成发送区是否为空等状态,这是通过函数 SPI_I2S_GetFlagStatus 实现的,这个函数很简单就不详细讲解,判断发送是否完成的方法是:

    SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);
    

      W25Q64是华邦公司推出的大容量SPI,FLASH产品,W25Q64的容量是64Mb,该系列还有W25Q80/16/32等。W25Q64容量为64Mb也就是8M字节。

      W25Q64将8M的容量分为128个块(Block),每个块大小为64K字节,每个块又分16个扇区(Sector),每个扇区4K个字节。

      W25Q64的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们必须给W25Q64开辟一个至少4K的缓存区,这样对SRAM要求不高,要求芯片必须有4K以上SRAM才能很好的操作。

      W25Q64的擦写周期多达10W次,具有20年的数据保存期限,支持电压为2.7到3.6V,W25Q64支持标准的SPI,还支持双输出/四输出的SPI时钟可以到80MHz(双输出时钟相当于160MHz,四输出时相当于320Mhz)

    补充:

    1.  以下是SPI模块的初始化代码,配置成主机模式,访问SD Card/W25Q64/NRF24L01                         
    2.  SPI口初始化
    3.  这里针是对SPI2的初始化
    void SPI2_Init(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
          SPI_InitTypeDef SPI_InitStructure;
        
        RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 
        RCC_APB1PeriphClockCmd(    RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能     
     
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出 
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
    
         GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉
        
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        //设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;        //设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;        //串行同步时钟的空闲状态为高电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;        //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;        //定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;    //CRC值计算的多项式
        SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
     
        SPI_Cmd(SPI2, ENABLE); //使能SPI外设
        
        SPI2_ReadWriteByte(0xff);//启动传输        
        
    }
    
    //SPI 速度设置函数
    //SpeedSet:
    //SPI_BaudRatePrescaler_2 2分频 
    //SPI_BaudRatePrescaler_8 8分频 
    //SPI_BaudRatePrescaler_16 16分频 
    //SPI_BaudRatePrescaler_256 256分频 
      
    void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
    {
          assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
        SPI2->CR1&=0XFFC7;
        SPI2->CR1|=SPI_BaudRatePrescaler;    //设置SPI2速度 
        SPI_Cmd(SPI2,ENABLE); 
    
    } 
    
    
    //SPIx 读写一个字节
    //TxData:要写入的字节
    //返回值:读取到的字节
    u8 SPI2_ReadWriteByte(u8 TxData)
    {        
        u8 retry=0;                     
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
            {
            retry++;
            if(retry>200)return 0;
            }             
        SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
        retry=0;
    
        while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
            {
            retry++;
            if(retry>200)return 0;
            }                              
        return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据                     
    }
    

      

  • 相关阅读:
    Binary Tree Inorder Traversal
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Majority Element
    Excel Sheet Column Number
    Reverse Bits
    Happy Number
    House Robber
    Remove Linked List Elements
    Contains Duplicate
  • 原文地址:https://www.cnblogs.com/happying30/p/9474914.html
Copyright © 2020-2023  润新知