zoukankan      html  css  js  c++  java
  • stm32之SPI

    1.SPI是一种高速全双工串行同步通信总线,在软件设计过程中,使用SPI总线必须有一个主机主要是指在数据传输时, 空闲时就不必强调主机和从机。 SPI 可以有多主机模式。

    (1)接口
      MOSI:数据线, Master Output Slave Input 主机输出, 从机输入
      MISO:数据线, Master Input Slave Output 主机输入, 从机输出
      /SS: 从器件使能信号, 由主器件控制,是片选线,一般不用
      4 线 SPI 接口: SCLK MOSI MISO CS
      3 线 SPI 接口: SCLK MOSI MISO 

     2.SPI接口如何连接

      CPOL=0, 串行同步时钟的空闲状态为低电平
        CPOL=1, 串行同步时钟的空闲状态为 高电平。

     时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。
          CPHA=0, 在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;
       CPHA=1, 在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。 

    3.SPI特征

    ● 3 线全双工同步传输
    ● 带或不带第三根双向数据线的双线单工同步传输
    ● 8 或 16 位传输帧格式选择
    ● 主或从操作
    ● 支持多主模式
    ● 8 个主模式波特率预分频系数(最大为 fPCLK/2)
    ● 从模式频率 (最大为 fPCLK/2)
    ● 主模式和从模式的快速通信
    ● 主模式和从模式下均可以由软件或硬件进行 NSS 管理: 主/从操作模式的动态改变
    ● 可编程的时钟极性和相位
    ● 可编程的数据顺序, MSB 在前或 LSB 在前
    ● 可触发中断的专用发送和接收标志
    ● SPI 总线忙状态标志
    ● 支持可靠通信的硬件 CRC
    ─ 在发送模式下, CRC 值可以被作为最后一个字节发送
    ─ 在全双工模式中对接收到的最后一个字节自动进行 CRC 校验
    ● 可触发中断的主模式故障、 过载以及 CRC 错误标志
    ● 支持 DMA 功能的 1 字节发送和接收缓冲器: 产生发送和接受请求
    4.SPI结构框图通常 SPI 通过 4 个引脚与外部器件相连:

    ● MISO: 主设备输入/从设备输出引脚。 该引脚在从模式下发送数据, 在主模式下接收数据。
    ● MOSI: 主设备输出/从设备输入引脚。 该引脚在主模式下发送数据, 在从模式下接收数据。
    ● SCK: 串口时钟, 作为主设备的输出, 从设备的输入
    ● NSS: 从设备选择。 这是一个可选的引脚, 用来选择主/从设备。 它的功能是用来作为“ 片选引脚” , 让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。 
    .NSS管理
    NSS输入又分为硬件输入和软件控制输入两种模式:
    软件模式:
      对于SPI主机来说, 需要设置SPI_CR1寄存器的SSM为1和SSI位为1,SSM为1是为了使能软件管理。 NSS有内部和外部引脚。 这时候, 外部引脚留作他用( 可以用来作为GPIO驱动从设备的片选信号) 。
     内部 NSS引脚电平则通过SPI_CRL寄存器的SSI位来驱动。 SSI位为1是为了使NSS内电平为高电平。
    要保持MSTR和SPE位为1, 也就是说要保持主机模式,只有NSS接到高电平信号时, 这两位才能保持置1.也就是说对于STM32的SPI, 要保持为主机状态, 内部输入的NSS电平必须为高。
      对于SPI 从机来说:
    如果从机选择STM32的一个SPI, 譬如主机选为SPI1, 从机选为SPI2, 则要按照以下操作手册说, NSS引脚在完成字节传输之前必须连接到一个低电平信号。 在软件模式下, 则需要设置SPI_CR1寄存器的SSM为1( 软件管理使能) 和SSI位为0 

    硬件模式:
      对于主机, 我们的NSS可以直接接到高电平, 对于从机, NSS接低就可以。 
    4.如何配置 SPI
    A. 从模式配置:
      1) 设置 DFF 位以定义数据帧格式为 8 位或 16 位。
      2) 选择 CPOL 和 CPHA 位来定义数据传输和串行时钟之间的相位关系(见图 212)。 为保证正确的数据传输, 从设备和主设备的 CPOL 和 CPHA 位必须配置成相同的方式。
      3) 帧格式(SPI_CR1 寄存器中的 LSBFIRST 位定义的” MSB 在前” 还是” LSB 在前” )必须与主设备相同
      4) 硬件模式下(参考从选择(NSS)脚管理部分), 在完整的数据帧(8 位或 16 位)传输过程中,NSS 引脚必须为低电平。 在 NSS 软件模式下, 设置 SPI_CR1 寄存器中的 SSM 位并清除 SSI 位。
      5) 清除 MSTR 位、 设置 SPE 位(SPI_CR1 寄存器), 使相应引脚工作于 SPI 模式下。在这个配置中, MOSI 引脚是数据输入, MISO 引脚是数据输出。
    B. 主模式配置
      1) 通过 SPI_CR1 寄存器的 BR[2:0]位定义串行时钟波特率。
      2) 选择 CPOL 和 CPHA 位, 定义数据传输和串行时钟间的相位关系(见图 212)。
      3) 设置 DFF 位来定义 8 位或 16 位数据帧格式。
      4) 配置 SPI_CR1 寄存器的 LSBFIRST 位定义帧格式。
      5) 如果需要 NSS 引脚工作在输入模式, 硬件模式下, 在整个数据帧传输期间应把 NSS脚连接到高电平; 在软件模式下, 需设置 SPI_CR1 寄存器的 SSM 位和 SSI 位。 如果 NSS引脚工作在输出模式, 则只需设置 SSOE 位。

      6) 必须设置 MSTR 位和 SPE 位(只当 NSS 脚被连到高电平, 这些位才能保持置位)。在这个配置中, MOSI 引脚是数据输出, 而 MISO 引脚是数据输入。

      1 #include "main.h"
      2 /*********************
      3 函数名称:SPI_Init
      4 函数功能:SPI初始化
      5 函数参数:无
      6 函数返回值:无
      7 备注:配置spi为主模式
      8       CS--PB0---通用推挽输出
      9             MISO--PA6---主机输入--浮空输入
     10             MOSI--PA7---主机输出--复用推挽输出
     11             SCLK--PA5---主机输出--复用推挽输出
     12 **********************/
     13 void SPI_Config(void)
     14 {
     15 #if reg_progream
     16     //1.时钟使能PA PB SPI1
     17     RCC->APB2ENR |=(1<<2)|(1<<3)|(1<<12);
     18     //2. CS  PB0  通用推挽输出
     19     GPIOB->CRL &=~(0xf<<0);
     20     GPIOB->CRL|=(3<<0);
     21     //MISO  PA6  浮空输入
     22     GPIOA->CRL &=~(0xfff<<20);
     23     GPIOA->CRL |=(4<<24);
     24     //SCLK  PA5  主机输出--复用推挽输出
     25     GPIOA->CRL |=(0xb<<20);
     26     //MOSI  PA7  主机输出--复用推挽输出
     27     GPIOA->CRL |=(0xb<<28);
     28 /***********SPI配置***************/
     29     //串行波特率--/2
     30     SPI1->CR1 &=~(0x7<<3);
     31     //CPOL -1  CPHA -1
     32     SPI1->CR1 |=(1<<0);
     33     SPI1->CR1 |=(1<<1);
     34     //使用八位数据帧格式
     35   SPI1->CR1 &=~(1<<11);
     36     //高位在前
     37     SPI1->CR1 &=~(1<<7);
     38     //先开启LSB,SSI=1,启用软件从设备管理
     39     SPI1->CR1 |=(1<<8);
     40     SPI1->CR1 |=(1<<9);
     41     //SSOE
     42     SPI1->CR2 |=(1<<2);
     43     //配置为主设备
     44     SPI1->CR1 |=(1<<2);
     45     //SPI使能
     46     SPI1->CR1 |=(1<<6);
     47     //双线模式
     48     SPI1->CR1 &=~(1<<15);
     49     //全双工
     50     SPI1->CR1 &=~(1<<10);
     51     //
     52 #else
     53         GPIO_InitTypeDef GPIO_InitStruct;
     54     SPI_InitTypeDef  SPI_InitStruct;
     55     //使能时钟  PA  PB  SPI1
     56     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_SPI1,ENABLE);
     57     //CS     PB0  通用推挽输出
     58     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
     59     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
     60     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
     61     GPIO_Init(GPIOB,&GPIO_InitStruct);
     62     //MISO   PA6  浮空输入
     63     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     64     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
     65     GPIO_Init(GPIOA,&GPIO_InitStruct);
     66     //MOSI   PA7  复用推挽输出    SCLK   PA5  复用推挽输出
     67     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
     68     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
     69     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;
     70     GPIO_Init(GPIOA,&GPIO_InitStruct);
     71     
     72     SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//串行时钟波特率 fclk/2
     73     SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;//时钟极性:高
     74     SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;//第2个跳边沿采样
     75     SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;//数据帧:8位
     76     SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
     77     SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;//软件管理
     78     SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线双向全双工
     79     SPI_InitStruct.SPI_Mode = SPI_Mode_Master;//主机
     80 //    SPI_InitStruct.SPI_CRCPolynomial = 7;//CRC多项式复位值
     81     SPI_Init(SPI1,&SPI_InitStruct);
     82     SPI_Cmd(SPI1,ENABLE);//开启SPI
     83     
     84 #endif
     85 }
     86 //接收
     87 uint8_t SPI_ReadWrite(u8 data)
     88 {
     89 #if  reg_progream
     90     //发送数据  
     91     while(!(SPI3->SR &(1<<1)));//为1,为空
     92     SPI1->DR = data;
     93     //等待接收到数据
     94     while((SPI1->SR &(1<<0))==0);
     95     //保存数据
     96     return SPI1->DR;  //数据寄存器
     97 #else
     98     while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE))==RESET)
     99     SPI_I2S_SendData(SPI1,data);
    100     while((SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE))==RESET)
    101     return SPI_I2S_ReceiveData(SPI1);
    102 #endif
    103 }
    SPI程序配置



  • 相关阅读:
    URAL 1998 The old Padawan 二分
    URAL 1997 Those are not the droids you're looking for 二分图最大匹配
    URAL 1995 Illegal spices 贪心构造
    URAL 1993 This cheeseburger you don't need 模拟题
    URAL 1992 CVS
    URAL 1991 The battle near the swamp 水题
    Codeforces Beta Round #92 (Div. 1 Only) A. Prime Permutation 暴力
    Codeforces Beta Round #7 D. Palindrome Degree hash
    Codeforces Beta Round #7 C. Line Exgcd
    Codeforces Beta Round #7 B. Memory Manager 模拟题
  • 原文地址:https://www.cnblogs.com/juan-4-14/p/12734816.html
Copyright © 2011-2022 走看看