STM32的SPI接口详解

目录

1.SPI简介

2.SPI工作原理

3.SPI时序

[3.1 CPOL(Clock Polarity,时钟极性):](#3.1 CPOL(Clock Polarity,时钟极性):)

[3.2 CPHA(Clock Phase,时钟相位):](#3.2 CPHA(Clock Phase,时钟相位):)

[3.3 四种工作模式](#3.3 四种工作模式)

4.相关代码

4.1使能片选信号

4.2使能通讯线

4.3初始化SPI

4.4设置SPI速度

4.5读写数据


1.SPI简介

STM32 的**SPI(Serial Peripheral Interface)**是一个串行外设接口,它允许STM32微控制器与其他设备(如传感器、存储器等)进行高速、全双工、同步的串行通信。通常包含SCK(串行时钟)、MOSI(主设备输出/从设备输入)、MISO(主设备输入/从设备输出)和NSS(片选信号)这4条线,支持多个从设备连接到一个主设备上。

2.SPI工作原理

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

主机和从机都存在一个移位寄存器 ,主机将要传输的数据保存到移位寄存器上,然后通过MOSI发送到从机的移位寄存器上,从机同时也将自己移位寄存器保存的数据通过MISO发送到主机的移位寄存器中,这样就完成了一次主机和从机的数据交换**,如果是进行写操作,主机只要无视从机返回的数据就可以了,如果是进行读操作,那么主机就要发送对应字节的空字节来推动从机的数据传输**。

3.SPI时序

SPI通过CS片选设备以后开启数据传输,数据传输根据主机CPHA(Clock Phase,时钟相位)和CPOL(Clock Polarity,时钟极性)配置的不同衍生出了不同的工作模式。

3.1 CPOL(Clock Polarity,时钟极性):

CPOL决定了SPI通信中空闲状态的时钟电平。

当CPOL=0时 ,空闲状态下SCK(Serial Clock,串行时钟)为低电平。
当CPOL=1时,空闲状态下SCK为高电平。

3.2 CPHA(Clock Phase,时钟相位):

CPHA决定了数据是在SCK的第一个边沿还是第二个边沿被采样。

当CPHA=0时 ,数据在SCK的第一个边沿被采样(对于MOSI是上升沿,对于MISO可能是下降沿,取决于具体实现)。
当CPHA=1时,数据在SCK的第二个边沿被采样(对于MOSI是下降沿,对于MISO可能是上升沿)。

CPHA的选择影响数据传输的时序和稳定性。

3.3 四种工作模式

通过CPOL和CPHA的不同值组合,可以实现SPI的四种模式:

模式1 (CPOL=0, CPHA=0):空闲时SCK为低电平,数据在SCK的第一个上升沿被主设备发送,并在第一个下降沿被从设备接收。
模式2 (CPOL=0, CPHA=1):空闲时SCK为低电平,数据在SCK的第二个上升沿被采样。
模式3 (CPOL=1, CPHA=0):空闲时SCK为高电平,数据在SCK的第一个下降沿被主设备发送,并在第一个上升沿被从设备接收。
模式4(CPOL=1, CPHA=1):空闲时SCK为高电平,数据在SCK的第二个下降沿被采样。

4.相关代码

本文基于STM32F429的HAL库为例讲解一下相关代码。

4.1使能片选信号

cpp 复制代码
#define	W25QXX_CS 		PFout(6)  		//W25QXX的片选信号


GPIO_InitTypeDef GPIO_Initure;
    
 __HAL_RCC_GPIOF_CLK_ENABLE();           //使能GPIOF时钟
    
//PF6
GPIO_Initure.Pin=GPIO_PIN_6;            //PF6
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST;     //快速         
HAL_GPIO_Init(GPIOF,&GPIO_Initure);     //初始化
    
W25QXX_CS=1;			                //SPI 不选中

使能GPIO_PF6为SPI的**片选信号,**默认拉高不选中。

4.2使能通讯线

cpp 复制代码
 GPIO_InitTypeDef GPIO_Initure;
    
 __HAL_RCC_GPIOF_CLK_ENABLE();       //使能GPIOF时钟
 __HAL_RCC_SPI5_CLK_ENABLE();        //使能SPI5时钟
    
 //PF7,8,9
 GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
 GPIO_Initure.Mode=GPIO_MODE_AF_PP;              //复用推挽输出
 GPIO_Initure.Pull=GPIO_PULLUP;                  //上拉
 GPIO_Initure.Speed=GPIO_SPEED_FAST;             //快速            
 GPIO_Initure.Alternate=GPIO_AF5_SPI5;           //复用为SPI5
 HAL_GPIO_Init(GPIOF,&GPIO_Initure);

使能SPI5,GPIO_F7/F8/F9推挽输出,默认上拉,快速,复用为SPI5。

4.3初始化SPI

cpp 复制代码
void SPI5_Init(void)
{
    SPI5_Handler.Instance=SPI5;                         //SP5
    SPI5_Handler.Init.Mode=SPI_MODE_MASTER;             //设置SPI工作模式,设置为主模式
    SPI5_Handler.Init.Direction=SPI_DIRECTION_2LINES;   //设置SPI单向或者双向的数据模式:SPI设置为双线模式
    SPI5_Handler.Init.DataSize=SPI_DATASIZE_8BIT;       //设置SPI的数据大小:SPI发送接收8位帧结构
    SPI5_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH;    //串行同步时钟的空闲状态为高电平
    SPI5_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;         //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
    SPI5_Handler.Init.NSS=SPI_NSS_SOFT;                 //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    SPI5_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;//定义波特率预分频的值:波特率预分频值为256
    SPI5_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI5_Handler.Init.TIMode=SPI_TIMODE_DISABLE;        //关闭TI模式
    SPI5_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
    SPI5_Handler.Init.CRCPolynomial=7;                  //CRC值计算的多项式
    HAL_SPI_Init(&SPI5_Handler);//初始化
    
    __HAL_SPI_ENABLE(&SPI5_Handler);                    //使能SPI5
	
    SPI5_ReadWriteByte(0Xff);                           //启动传输
}

设置SPI为主机工作模式,双线模式,空闲状态为高电平,数据为8位帧结构,二个跳变沿(上升或下降)数据被采样,片选信号由软件控制,数据传输从MSB位开始,关闭硬件CRC校验,最后启动传输。

我们把 SPI5 的频率设置成了最低的256 分频,后面我们可以随时通过函数SPI5_SetSpeed 来设置 SPI5 的速度。

4.4设置SPI速度

cpp 复制代码
void SPI5_SetSpeed(u8 SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
    __HAL_SPI_DISABLE(&SPI5_Handler);            //关闭SPI
    SPI5_Handler.Instance->CR1&=0XFFC7;          //位3-5清零,用来设置波特率
    SPI5_Handler.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
    __HAL_SPI_ENABLE(&SPI5_Handler);             //使能SPI
    
}

SPI_BaudRatePrescaler可以设置 2/4/8/16/32/64/128/256分频,例如STM32F429的APB1为90MHz,设置2分频就是45MHz。

4.5读写数据

cpp 复制代码
void read(){

    W25QXX_CS=0;//拉低片选信号      
    SPI5_ReadWriteByte(0XFF);
    W25QXX_CS=1; //拉高片选信号      
}

u8 SPI5_ReadWriteByte(u8 TxData)
{
    u8 Rxdata;
    HAL_SPI_TransmitReceive(&SPI5_Handler,&TxData,&Rxdata,1, 1000);       
 	return Rxdata;          		    //返回收到的数据		
}

读写数据都是用SPI5_ReadWriteByte这个函数,不同的是,如果是写入数据,不用管接收到的从机数据是什么,如果是读取数据,则可以发送0XFF,读取从机返回的对应数据

相关推荐
scilwb5 小时前
RoboCon考核题——scilwb
单片机
点灯小铭6 小时前
基于STM32单片机智能RFID刷卡汽车位锁桩设计
stm32·单片机·汽车·毕业设计·课程设计
TDengine (老段)7 小时前
TDengine IDMP 高级功能(4. 元素引用)
大数据·数据库·人工智能·物联网·数据分析·时序数据库·tdengine
bai5459367 小时前
STM32 软件I2C读写MPU6050
stm32·单片机·嵌入式硬件
逼子格9 小时前
AT89C52单片机介绍
单片机·嵌入式硬件·51单片机·硬件工程师·硬件工程师真题·at89c52·器件手册
David WangYang12 小时前
基于 IOT 的安全系统,带有使用 ESP8266 的语音消息
物联网·安全·语音识别
竹照煜_ysn14 小时前
STM32——软硬件I2C
stm32·嵌入式硬件·mongodb
Wallace Zhang15 小时前
STM32 - Embedded IDE - GCC - 显著减少固件的体积
stm32·单片机·嵌入式硬件
fengfuyao9851 天前
STM32如何定位HardFault错误,一种实用方法
stm32·单片机·嵌入式硬件
爱学习的颖颖1 天前
EXTI外部中断的执行逻辑|以对射式红外传感器计次为例
单片机·嵌入式硬件·exti中断