zoukankan      html  css  js  c++  java
  • 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最近接收的数据                     
    }
    

      

  • 相关阅读:
    不成熟打地鼠游戏
    代码
    简单的JS功能
    json取数据问题
    ojdbc14.jar 与ojdbc6.jar的区别
    IIS6.0开启gzip压缩
    column 'XXXX' in field list is ambiguous
    Struts bean:define标签用法
    hibernate 学习笔记
    The content of element type "strutsconfig" must match "(displayname?,descr
  • 原文地址:https://www.cnblogs.com/happying30/p/9474914.html
Copyright © 2011-2022 走看看