SPI协议

SPI是串行外围设备接口,是一种高速的、全双工的、同步的通信总线,可以同时发出和接收串行数据,可以作为主机或者丛机工作,提供频率可编程时钟,发送结束中断标志,写冲突保护,总线竞争保护等。

(一)物理层

在点对点的通信中,SPI接口不需要进行寻址操作,在多个期间的系统总,每个从器件需要独立的使能信号
在这里插入图片描述

SPI的接口方式

SPI的接口方式有两种,包括五线制和四线制

  • 五线制:
    MOSI(DO):作为主器件时为数据输出,作为从器件时为数据输入
    MISO(DI):作为主器件时为数据输入,作为从器件时为输入输出
    SCLK:时钟信号线,由主器件产生
    NSS(CS):从器件使能信号,由主器件控制,低电平有效
    GND:公共地线

  • 四线制:
    MOSI:作为主器件时为数据输出,作为从器件时为数据输入
    SCLK:时钟信号线,由主器件产生
    NSS(CS):从器件使能信号,由主器件控制,低电平有效
    GND:公共地线

SPI引脚说明

1)MOSI:主设备输出,从设备输入,数据从 主设备到从设备
因为SPI是全双工通信总线,即主机和从机都可以同时收发数据,所以需要两条线负责从 主机到从机和从 从机到主机的传输,而MOSI就是负责主机向从医发送数据的。

数据输出通过MOSI发出,数据在时钟的上升沿或者下降沿时改变,在紧接着的下降沿或上升沿被读取

2)MISO:主设备输入,从设备输出,数据从 从设备到主设备

3)SCLK时钟信号,由主设备产生
SCLK提供时钟脉冲,可以统一主机和从机之间的数据传输,只有在有效的时钟信号下才能正常传输数据,如果不同设备支持的最高传输速率不同时,在传输过程中传输频率受限于低速一方

4)NSS(CS)从设备片选信号,由主设备控制
不同于IC,如果和其他设备通讯,不需要寻址操作,只需要通过片选信号就能和从机通信。NSS可以控制芯片是否被选中,也就是说只有片选信号为预先规定的使能信号的时候,对芯片操作有效。

  1. 为主机选择对应的从机进行传输数据,每个主机与从机之间的NSS总线互不相干
  2. SPI规定通信以NSS信号线拉低为开始,拉高为结束
  3. 从设备的NSS脚可以由主设备的一个标准IO引脚来驱动,一旦被使能,NSS引脚也可以作为输出引脚,并且在SPI处于主模式的时候拉低
  4. 所有的SPI设备,如果它们的NSS引脚连接到主设备的NSS引脚,则会被检测到低电平
  5. 如果设备被设备为NSS硬件模式,就会自动进入到从设备状态
  6. 当配置为主设备、NSS配置为输入引脚(MSTR=1,SSOE=0时,如果NSS被拉低,则这个SPI设备进入主模式失败状态:即MSTR位被自动清除,此设备进入从模式
  7. 主机和从机都有一个串行移位寄存器,主机通过向它的 SPI 串行寄存器写入一个字节来发起一次传输。寄存器通过 MOSI 信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过 MISO 信号线返回给主机。

5)从选择NSS脚管理:

  • 软件NSS模式:可以通过设备SPI_CR1寄存器的SSM位来使能这种模式,在这种模式下的NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1位来驱动
  • 硬件NSS模式,分两种情况:① NSS输出被使能:当一个主SPI,并且其NSS输出设备已经通过SPI_CR2寄存器的SSOE位使能,这个时候NSS引脚被拉低,所有的NSS引脚与这个主SPI的NSS引脚相连并配置为硬件NSS的SPI设备,将自动变成从SPI设备;② 当一个SPI设备需要发送广播数据的时候,它必须要拉低NSS信号,来通知所有的其他设备它是主设备;如果他不能拉低NSS,就意味着总线上有另外的一个主设备在通信,会产生硬件失败错误Hard Fault。

(二)协议层

SPI协议层规定了传输过程中的起始信号和停止信号,数据有效性、时钟同步、通讯模式,。所有的运作都是基于SCK时钟线的,SCK为低电平的时候表示无效。

在这里插入图片描述
1)起始信号和停止信号
SPI通讯的起始和终止由NSS信号线控制,当NSS为低电平的时候表示起始信号,为高电平的时候表示停止信号
2)数据有效性:
SPI中使用MOSI和MISO来进行全双工的传输数据,SCK来同步数据传输,即MOSI和MISO同时工作,在时钟信号线SCK为有效的时候对MOSI和MISO进行采样,采到的信息为传输信息。
SPI中的数据在采样是在SCK的上升或者下降沿的时候进行的,如图的数据是在SCK下降沿的时候进行采样的。
3)通讯模式
主要依靠总线空闲的时候SCK的时钟状态和数据采样时刻来进行区别
4)SPI总线工作方式
SPI有四种传输方式,上升沿、下降沿、前沿、后沿,SPI只有主模式和从模式之分,没有读和写的说法
5)时钟极性CPOL和时钟相位CPHA
SPI_CR寄存器的CPOL和CPHA为,能够组合成四种可能的时序关系。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

- 在改变CPOL/CPHA位之前,必须清楚SPE位将SPI禁止
- 主和从必须配置相同的时序模式
- SCK的空闲状态必须和SPI_CR1寄存器指定的极性一致,也就是CPOL为1的时候,空闲的时候应该上拉
SCK为高电平;CPOL为0的时候,空闲的时候应该下拉SCK为低电平

在这里插入图片描述

SPI数据传输

  • SPI通讯协议规定传输的数据为8位。传输顺序是高位在前,低位在后;
  • SPI是一个数据交换协议,主机给从机发送一个信息,那么从机就会返回一个信息给主机,也就是说,当主机读从机的时候,需要先发一个数据给从机,从机才会发数据回来给主机。
  • SPI是一个同步的数据总线,也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和接收端的完美同步。时钟的作用就是告诉接收端在确切的时机对数据线上的信号进行采样。

数据传输的过程:

  1. 主机先将NSS信号拉低,这保证开始接收数据
  2. 当接收端检测到时钟的边缘信号的时候,会立即读取数据线上的信号,这样得到了一位数据
  3. 主机发送到从机时,主机立即产生时钟信号,然后数据一位一位地从MOSI信号线上发送到从机
  4. 主机接收从机信号时,如果从机需要将数据发送回主机,主机将继续生成预定数量的时钟信号,并且从机会将数据通过MISO信号发送。

在这里插入图片描述

数据控制逻辑

在这里插入图片描述

初始化代码

要初始化SPI2,设置SPI2位主机模式,设置数据格式为8位,设置SCK时钟极性以及采样方式,设置SPI2的时钟频率最大为18MHz,设置数据的格式

1)设置SPI的通讯方向

SPI_Direction
=SPI_Direction_2Lines_FullDuplex//双向全双工
=SPI_Direction_2Lines_RxOnly//双向只接收
=SPI_Direction_1Lines_Rx//单向只接收
=SPI_Direction_1Line_Tx//单向只发送

2)设置SPI的主机模式

SPI_Mode
=SPI_Mode_Master//主机模式
=SPI_Mode_Slave//从机模式

3)SPI通讯的数据帧

SPI_DataSize
=SPI_DataSize_8b//SPI发送接收8位帧结构
=SPI_DataSize_16b//SPI发送接收16位帧结构

4)配置时钟极性CPOL和时钟相位CPHA
具体可以查看上面协议层

SPI_CPOL
SPI_CPHA

5)设置NSS引脚的使用模式

SPI2_NSS
=SPI2_NSS_Hard//硬件模式
=SPI2_NSS_Soft//软件模式

6)设置波特率分频因子

SPI_BaudRatePrescaler=
SPI_BaudRatePrescaler_2 //2分频
SPI_BaudRatePrescaler_8 //8分频
SPI_BaudRatePrescaler_16 //16分频
SPI_BaudRatePrescaler_256 //256分频

7)设置数据位高低位

SPI_FirstBit
=SPI_FirstBit_MSB//高位数据在前
=SPI_FirstBit_LSB//低位数据在前

8)CRC值计算的多项式

SPI_InitStructure.SPI_CRCPolynomial=7;//CRC计算多项式

全部代码

#include "spi.h"
// 初始化SPI2,设置SPI2为主机模式
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_Pin13|GPIO_Pin14|GPIO_Pin15;
	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.SPI2_NSS=SPI_NSS_Soft;//NSS信号由硬件NSS管脚还是软件SSI管理:内部NSS信号有SSI位控制
	SPI_InitStructure.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_Cmd(SPI2,ENABLE);//使能SPI外设
	SPI2_ReadWriteByte(0xff)//启动传输
	
}
//SPI速度设置函数
//SPI_BaudRatePrescaler_2 2分频
//SPI_BaudRatePrescaler_8 8分频
//SPI_BaudRatePrescaler_16 16分频
//SPI_BaudRatePrescaler_256 256分频
void SPI2_SetSpeed(u8 SPI_BuadRatePrescaler){
	assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
	SPI2->CR1&=0xFFC7;
	SPI2->CR1|=SPI2_BaudRatePrescaler;
	SPI_Cmd(SPI2,ENABLE);
}

读取写入的字节

  1. 发送数据前要等待发送缓冲区为空,靠TXE标志判断
  2. 开始的while循环是等待发送缓冲区为空,同时等待接收缓冲区是否有数据,RXNE标志来判断,把接收缓冲区的数据作为返回值返回。
  3. 由于发送和接收是同时进行的,而且要接收一个数据必须在有效的SCK下,而只有发送数据才能产生有效的SCK,所以接收数据的函数在发送数据的函数的基础上,将发送的数据设置为Dummy_Byte假数据来骗取有效的SCK
//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;
	}
	SPI_I2S_SendData(SPI2,TxData);//通过外设SPIx发送一个数据
	retry=0;
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET){//检查指定的SPI标志位,看接收缓存是否为空
		retry++;
		if(retry>200) return;
	}
	return SPI_I2S_ReceiveData(SPI2);//返回通过SPIx最近接收的数据
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32是一种微控制器系列,其中的SPI(串行外设接口)是一种通信接口,可以实现与外部设备的高速通信。下面是一个关于STM32 SPI2程序的简要说明。 STM32 SPI2程序的目的是实现与外部设备之间的数据传输。首先,我们需要在初始化阶段配置SPI2的各种参数,如数据位大小、极性、相位等等。这些参数可以根据具体外设的需求进行设置。 接下来是数据传输的流程。首先,我们通过SPI2的发送寄存器将要发送的数据写入。然后,等待发送完成的标志位被置位,表示数据已经成功发送。在此期间,我们还可以通过SPI2的接收寄存器读取接收到的数据,可以根据用户的需求选择是否接收数据。 对于非阻塞模式的SPI2程序,我们可以利用中断来异步地处理数据传输。在初始化阶段,我们需要配置相应的中断触发条件,并编写中断处理函数。当触发指定的中断条件时,中断处理函数会被自动调用,我们可以在其中进行数据的发送和接收操作。 对于阻塞模式的SPI2程序,我们使用轮询的方式进行数据传输。在发送数据时,我们直接等待发送完成的标志位被置位;在接收数据时,我们通过检查接收缓冲区是否有数据来判断是否接收到了数据。 总结来说,STM32 SPI2程序是一个用于与外部设备进行数据传输的程序。它需要在初始化阶段配置SPI2的参数,并在数据传输阶段进行发送和接收的操作。无论是使用中断异步方式还是使用轮询方式,都需要合理地处理数据的发送和接收过程,以保证数据的可靠传输。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值