STM32第十章-SPI通信应用

  上一章咱们讲到了IIC通信,这一章来讲一说SPI通讯,一样的不少模块也用到了SPI通讯,好比0.96寸的OLED模块。玩过单片机的小伙伴都知道OLED有4针的也有7针的,4针的就是IIC通讯,7针的就是SPI通讯。缓存

1、 SPI 简介

  SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通讯总线,而且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今愈来愈多的芯片集成了这种通讯协议,STM32 也有 SPI 接口。SPI通信使用 3 条总线及片选线,3条总线分别为 SCK、MOSI、MISO、SS。markdown

在这里插入图片描述

  (1) SCK (Serial Clock):时钟信号线,用于通信数据同步。它由通信主机STM32产生,决定了通信的速率,不一样的设备支持的最高时钟频率不同,如STM32的SPI 时钟频率最大为fpclk /2,两个设备之间通信时,通信速率受限于低速设备。函数

  (2) MOSI (Master Output, Slave Input):主设备STM32输出/从设备输入引脚。STM32的数据从这条信号线输出,从机由这条信号线读入STM32发送的数据,即这条线上数据的方向为STM32到从机。布局

  (3) MISO(Master Input,,Slave Output):主设备STM32输入/从设备输出引脚。STM32从这条信号线读入数据,从机的数据由这条信号线输出到STM32,即在这条线上数据的方向为从机到STM32。spa

  (4) SS( Slave Select):片选信号线,也称为 NSS、CS。当有多个SPI 从设备与 SPI 主机STM32相连时,设备的其它信号线 SCK、MOSI及 MISO同时并联到相同的 SPI总线上,即不管有多少个从设备,都共同只使用这 3 条总线;而每一个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中经过设备地址来寻址、选中总线上的某个设备并与其进行通信;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通信。因此SPI通信以 NSS 线置低电平为开始信号,以 NSS 线被拉高做为结束信号。3d

2、 具体代码编写

1.SPI引脚初始化

  咱们使用 STM32 的 SPI1 的主模式,第一步就要是能 SPI1 的时钟,SPI1 的时钟经过 APB2ENR 的第12位来设置。其次要设置 SPI1 的相关引脚为复用输出,这样才会链接到 SPI1 上不然这些 IO 口仍是默认的状态,也就是标准输入输出口。这里咱们使用的是 PA五、PA六、PA7 这 3 个,因此设置这三个为复用 IO。code

void SPI1_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;    
RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);	
GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
}
复制代码

2.设置SPI1工做模式

  接下来咱们要初始化 SPI1,这在库函数中是经过 SPI_Init 函数来实现的,和STM32的其余外设同样一样须要配置这些参数,使用中咱们不须要关心这些具体的设置。设置 SPI1 为主机模式,设置数据格式为 8 位,然设置 SCK 时钟极性及采样方式。并设置 SPI1 的时钟频率(最大 18Mhz),以及数据的格式(MSB 在前仍是LSB 在前)。这在库函数中是经过 SPI_Init 函数来实现的。orm

SPI_InitTypeDef  SPI_InitStructure;
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(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 
复制代码

3.使能SPI1

初始化完成以后接下来是要使能 SPI1 通讯了,在使能 SPI1 以后,咱们就能够开始 SPI 通信了。接口

SPI_Cmd(SPI1, ENABLE); //使能SPI外设
复制代码

4.使用SPI读写一个字节

u8 SPI1_ReadWriteByte(u8 TxData) {		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)//检查指定的SPI标志位设置与否:发送缓存空标志位
	{
		retry++;
		if(retry>200)return 0;
	}			  
	SPI_I2S_SendData(SPI1, TxData);//经过外设SPIx发送一个数据
	retry=0;
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
	{
		retry++;
		if(retry>200)return 0;
	}	  						    
	return SPI_I2S_ReceiveData(SPI1); //返回经过SPIx最近接收的数据 
}
复制代码

  本函数中不包含 SPI 起始和中止信号,只是收发的主要过程,因此在调用本函数先后要作好起始和中止信号的操做;事件

  循环调用库函数SPI_I2S_GetFlagStatus 检测事件,若检测到事件,则进入通信的下一阶段,若未检测到事件则停留在此处一直检测,当检测200次都还没等待到事件则认为通信失败,退出通信;

  经过检测TXE标志,获取发送缓冲区的状态,若发送缓冲区为空,则表示可能存在的上一个数据已经发送完毕;等待至发送缓冲区为空后,调用库函数 SPI_I2S_SendData 把要发送的数据“TxData”写入到 SPI的数据寄存器 DR,写入 SPI数据寄存器的数据会存储到发送缓冲区,由 SPI外设发送出去;

  写入完毕后经过循环200次等待RXNE 事件,即接收缓冲区非空事件。因为 SPI 双线全双工模式下MOSI 与 MISO 数据传输是同步的,当接收缓冲区非空时,表示上面的数据发送完毕,且接收缓冲区也收到新的数据;

  等待至接收缓冲区非空时,经过调用库函数 SPI_I2S_ReceiveData 读取 SPI 的数据寄存器 DR,就能够获取接收缓冲区中的新数据了。代码中使用关键字“return”把接收到的这个数据做为SPI_SendByte 函数的返回值。

  以上的步骤咱们就搞定了SPI 的基本收发单元,还须要了解如何对FLASH 芯片进行读写。FLASH 芯片自定义了不少指令,咱们经过控制 STM32 利用 SPI 总线向 FLASH 芯片发送指令,FLASH芯片收到后就会执行相应的操做。而这些指令,对主机端(STM32)来讲,只是它遵照最基本的 SPI 通信协议发送出的数据,但在设备端(FLASH 芯片)把这些数据解释成不一样的意义,因此才成为指令。查看FLASH 芯片的数据手册可了解各类它定义的各类指令的功能及指令格式。这里我就不过多的将写了。

相关文章
相关标签/搜索