STM32- SPI

文章目录

  • STM32- SPI
  • 1. SPI概述
  • 1.1 SPI概念
  • 1.2 SPI工作原理
  • 1.3 SPI时序
  • 1.4 工作模式
  • 2 代码配置
  • 1. SPI概述

    1.1 SPI概念

    SPI(Serial Peripheral Interface,串行外围设备接口),是一种高速的、全双工、同步的通信总线,有四根通信线:

    SCK(Serial Clock):时钟信号,由主设备产生

    MOSI(Master Output/ Slave Input):主机数据输出,从机输入

    MISO(Master Input Slave Output):主机数据输入,从机输出

    SS(Slave Select):从机片选信号,由主机产生

    特点:① 总线上允许连接多个能作主机的设备,但在任一时刻只允许有一个设备作为主机。② 总线的时钟线 SCK 由主机控制。

    1.2 SPI工作原理

  • 字节交换:主机的串行移位寄存器通过 MOSI 信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过 MISO 信号线返回给主机,(高位先行)。
  • 数据采集(移入数据):在SCK下降沿或上升沿(看具体配置)时,主机移出的高位通过MOSI信号线传到从机的地位,从机的低位通过MISO信号线传到主机地位。每个时钟周期传输一位。
  • 波特率发送器:产出时钟信号,由主机产生。
  • 1.3 SPI时序

  • 起始条件:SS从高电平切换到低电平
  • 终止条件:SS从低电平切换到高电平
  • 从机在被选中的状态中,SS 要始终保持为低电平
  • 1.4 工作模式

  • CPOL/CKP(Clock Polarity,时钟极性):时钟信号在空闲状态下的电平。当CPOL=1,时钟信号为高电平;当CPOL = 0,时钟空闲状态为低电平 。
  • CPHA/ CKE(Clock Phase,时钟相位):数据的采样时刻。当CPHA = 0 时,在时钟信号的第一个边沿进行数据采样;当CPHA =1 时,在时钟信号的第二个边沿进行数据采样。
  • 工作模式 CPOL SPHA SCK空闲电平 采样边沿 采样时刻
    0(00) 0 0 上升沿 第一个边沿
    1(01) 0 1 下降沿 第二个边沿
    2(10) 1 0 下降沿 第一个边沿
    3(11) 1 1 上升沿 第二个边沿

    工作模式0:空闲状态的时钟信号为低电平,且在第一个边沿时刻进行数据移入,所以只能是上升沿移入数据(从空闲低电平转为高电平),在第二个边沿移出数据。

    工作模式1:空闲状态的时钟信号为低电平,且在第二个边沿时刻进行数据移入,所以只能是下降沿移入数据(第二个边沿只能是下降了),第一个边沿移出数据。

    工作模式2:空闲状态的时钟信号为高电平,且在第一个边沿时刻进行数据移入,所以只能是下降沿移入数据(从空闲高电平转为低电平),第二个边沿移出数据。

    工作模式3:空闲状态的时钟信号为高电平,且在第二个边沿时刻进行数据移入,所以只能是上升沿移入数据(第二个边沿只能是上升了),第一个边沿移出数据。

    2 代码配置

    软件SPI代码设置

    // 看引脚定义图
    void MySPI_W_SS(uint8_t Value)
    {
    	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)Value);
    }
    void MySPI_W_SCK(uint8_t Value)
    {
    	GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)Value);
    }
    void MySPI_W_MOSI(uint8_t Value)
    {
    	GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)Value);
    }
    uint8_t MySPI_R_MISO_Byte(void)
    {
    	return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);
    }
    void MySPI_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//主机输出引脚位推挽输出
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//主机输入引脚为上拉输入
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	MySPI_W_SS(1);
    	MySPI_W_SCK(0);
    	
    }
    void MySPI_Start(void)
    {
    	MySPI_W_SS(0);
    }
    void MySPI_Stop(void)
    {
    	MySPI_W_SS(1);
    }
    uint8_t MySPI_SwapData(uint8_t ReturnData)//模式0,有点类似与I2C的接受字节取高位
    {
    	uint8_t i,ReceiveData = 0x00;
    	for(i=0;i<8;i++)
    	{
    		MySPI_W_MOSI(ReturnData & (0x80 >> i));//取特定位
    		MySPI_W_SCK(1);
    		if(MySPI_R_MISO_Byte() == 1){ReceiveData |= (0x80 >> i);}//高位先行
    		MySPI_W_SCK(0);
    	}
    	return ReceiveData;
    }
    
    

    硬件SPI初始化

     
    void MySPI_Init(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	SPI_InitTypeDef SPI_InitStructure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
     
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//主机输出引脚位推挽输出
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//主机输入引脚为上拉输入
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5 | GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_128;
    	SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;//第一个边沿开始采样,CPHA=0
    	SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;//设置SCK空闲低电平
    	SPI_InitStructure.SPI_CRCPolynomial=7;
    	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8为数据帧
    	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双线全双工
    	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;
    	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//设置设备为主机
    	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;
    	SPI_Init(SPI1,&SPI_InitStructure);
    	
    	SPI_Cmd(SPI1,ENABLE);
    	
    	MySPI_W_SS(1);//默认设置SCK为高电平,不选择为从机
     
    }
    
    uint8_t MySPI_SwapData(uint8_t ReturnData)//模式0
    {
    	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) != SET);//TXE会在写入数据后自动清除
    	SPI_I2S_SendData(SPI1,ReturnData);//数据转移到移位寄存器
    	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);//RXNE会在读取数据后自动清除
    	return SPI_I2S_ReceiveData(SPI1);
    }
    

    作者:Archie 占

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32-SPI

    发表回复