• 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程序配置



  • 相关阅读:
    C#编写的windows程序随系统启动
    CentOS 6.0修改ssh远程连接端口
    C# 控件缩写大全+命名规范+示例
    记录点滴
    C++封装,继承,多态,友元
    策略模式
    OpenGL入门
    C++四种类型转换
    观察者模式Observer Pattern
    双向链表std::list和单向链表std::forward_list
  • 原文地址:https://www.cnblogs.com/juan-4-14/p/12734816.html
Copyright © 2020-2023  润新知