×
单片机 > 单片机程序设计 > 详情

寒假学习之stm32(17)----SPI通信协议

发布时间:2020-08-26 发布时间:
|

背景知识介绍:

  1. wiki : http://wiki.csie.ncku.edu.tw/embedded/SPI#introduction

  2. 百度:http://baike.baidu.com/item/SPI 
    一定要看啊!!!

小小的摘要:

1. 通信模式:SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线(SDI,SDO,SCLK,CS)

MISO(master in slaver out) 主设备数据输入,从设备数据输出。
MOSI(master out slaver in) 主设备数据输出,从设备数据输入。
SCLK时钟信号,由主设备产生。
CS从设备片选信号,由主设备控制

2. 内部结构: 

3. 工作原理:

1. 硬件上为4根线。

2. 主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。

3. 串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。(具有环形通信的特点)

4. 外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。

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

我们可以看一下SPI的单从机模式的接线: 

  • 配置相关引脚的复用功能,使能SPIx时钟

    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

  • 初始化SPIx,设置SPIx工作模式

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

  • 使能SPIx

    void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

  • SPI传输数据

    void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); 
    uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;

  • 查看SPI传输状态

    SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);

  • 完整的配置过程:

    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最近接收的数据                     }


    关键字:stm32  SPI  通信协议 

    『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

    热门文章 更多
    stm32 总线矩阵介绍