zoukankan      html  css  js  c++  java
  • STM32技术--SPI通信

    SPI

    一、SPI简介

      SPI(Serial Peripheral Interface )是串行外围接口设备,是一种高速的,全双工,同步的通信总线,并且在芯片上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是处于这种简单易用的特性,现在越来越多的芯片集成了这种协议。

      SPI 是一个环形总线结构,由 ss(cs)、 sck、 sdi、 sdo 构成,其时序其实很简单,主要是在 sck 的控制下,两个双向移位寄存器进行数据交换。

    因为是全双工同步通信,所以在传输数据时,左边主机的数据从移位寄存器进入MOSI线上进入右边的从机,并存入最低位,同时从机的最高位通过MISO传输到主机的最低位,当第二位数据进行发送时,最低位的数据会向左移一位并将新数据存入最低位。

    二、通信协议

    1、物理层

     motorola公司  首先提出的全双工三线同步串行外围接口,采用主从模式( Master Slave)架构;支持多 slave 模式应用,一般仅支持单Master(单主机模式)。

     管脚

      三线SPI:SCLK(时钟线),MISO(主机接收从机发送),MOSI(主机发送从机接收)

      四线SPI:CS(片选线),SCLK,MISO,MOSI

      片选:被选,确定该设备处于何种工作模式

       连接方式

      

    2、数据链路层
     SPI采用位协议,------高位在前,低位在后

     SPI有四种工作模式,SPI0 SPI1 SPI2 SPI3

               SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协

    议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)
    能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如
    果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 SPI 主模块和与之通信的外设音时钟相位和极性应该一致。
    SPI 时序图详解---SPI 接口在模式 下输出第一位数据的时刻

        

    三、STM32中SPI控制器

    数量:2个  SPI1  SPI2

    特性:全双工同步通信

                8/16是传输帧选择

                主从结构

                8个主模式波特率预分频系数

                主模式和从模式下均可以由软件或硬件进行NSS管理

                可编程的时钟极性和相位

                 可编程的数据顺序, MSB在前或LSB在前

    四、配置工作模式

    1、NSS管理

          SPI可以工作为主机模式和从机模式,可以通过软件模式和硬件模式进行管理。

      SPI的NSS引脚分为内部引脚和外部引脚,当内部引脚检测到高电平的时候,设备会工作在主机模式,检测到低电平,工作在从机模式。

     先说软件模式,软件模式可以通过SPI_CR1寄存器的SSM为进行设置,当SSM位为1时,SPI的模式管理为软件管理模式,且当SSI位为1时(SSI位仅在SSM位为1时有效),内部的NSS会被驱动为高电平,该设备就设置为主机模式且外部NSS引脚会输出一个低电平信号,当其他的设备检测到低电平信号时,会自动进入从机模式。

    硬件模式:

      

           NSS输出使能通过CR2的SSOE位进行控制,一旦该位被使能,NSS引脚作为一个输出引脚,若SPI工作为主机模式,NSS会输出一个低电平,当其他设备的NSS引脚接到主设备的引脚,会检测到一个低电平,并会自动进入从设备状态。当配置为主模式,NSS配置为输入引脚,(MSTR=1,SSOE=0)时,如果NSS被拉低,则配置为主模式水白,会自动进入从工作模式。

           若向通过硬件管理工作模式,只需将需要配置为主模式的NSS引脚接高电平,从模式的NSS接低电平即可。

      更详细的NSS工作模式介绍见:https://blog.csdn.net/andylauren/article/details/52259703

    五、SPI配置过程

    1、查看原理图确定引脚,以及各个引脚的工作模式

     

    这里spi的四个引脚分别对应pa4,pa5,pa6,pa7,SPI作为主机,MOSI,cs,clk应给配置为输出模式,miso配置为输入。

    所以为了将SPI的功能复用到IO扣上,pa5,pa7要用作复用推挽输出。(pa4为什么配置为通用推挽输出现在我还没弄明白,等明白了再改回来)

    2、确定spi的时钟相位以及时钟极性等工作模式

     因为时钟相位和时钟极性可以配置出4种spi的模式,而spi的工作模式与数据的采集以及输出有关,所以我们这里要根据外设来确当spi的工作模式。

    复制代码
    #include "spi.h"
    
    void SPI_Config(void)
    {
        /*
            pa4        sf cs            通用推挽输出
            pa5        sc clk        复用推挽输出
            pa6        miso            浮空输入
            pa7        mosi            复用推挽输出
        */
        //GPIO
        GPIO_InitTypeDef GPIOInitStruct;
        //SPI
        SPI_InitTypeDef SPIInitStruct;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1,ENABLE);
        //pa4 通用推挽输出
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_4;
        GPIOInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIOInitStruct);
        //pa5 pa7 复用推挽输出
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
        GPIO_Init(GPIOA,&GPIOInitStruct);
        //pa6 浮空输入
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_6;
        GPIO_Init(GPIOA,&GPIOInitStruct);
        
        //SPI
        SPIInitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;            //分频
        SPIInitStruct.SPI_CPHA = SPI_CPHA_1Edge;                                                        //时钟相位
        SPIInitStruct.SPI_CPOL = SPI_CPOL_Low;                                                            //时钟极性
        SPIInitStruct.SPI_DataSize = SPI_DataSize_8b;                                                //数据宽度
        SPIInitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;            //全双工
        SPIInitStruct.SPI_FirstBit = SPI_FirstBit_MSB;                                            //高位在前
        SPIInitStruct.SPI_Mode = SPI_Mode_Master;                                                        //主机
        SPIInitStruct.SPI_NSS = SPI_NSS_Soft;                                                                //软件模式
        SPI_Init(SPI1,&SPIInitStruct);
        //使能SPI
        SPI_Cmd(SPI1,ENABLE);
        
    }
  • 相关阅读:
    字节流、字符流
    ArrayList、LinkedList、Vector 的区别。
    Java 为每个原始类型提供了哪些包装类型:
    int 和 Integer 有什么区别
    怎样自动把报表插入到 word 文档中
    web 报表中电子图章 / 水印的轻松实现
    玩转报表排名
    报表设计技巧之隔行异色
    单据类报表的制作
    轻松 get 报表模糊查询技能
  • 原文地址:https://www.cnblogs.com/laoxiongzhijia/p/14429811.html
Copyright © 2011-2022 走看看