SPI协议以及STM32SPI的架构和特性

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省了空间,提供方便,主要应用在EEPROM,FLASH,实时时钟,AD转换器还有数字信号处理直接。

SPI接口一般使用四根线:

MISO,主设备数据输入,从设备数据输出

MOSI,主设备数据输出,从设备数据输入

SCLK,时钟信号,由主设备产生

CS,从设备片选信号,由主设备控制

SPI接口框图

SPI工作原理

①硬件为四根线

②主机和从机都有一个串行移位寄存器,主机通过SPI的串行移位寄存器写入一个字节发送一次传输。

③串行移位寄存器通过MOSI信号线将字节发送给从机,从机将自己的串行移位寄存器的内容通过MISO返回给主机,这样两个移位寄存器的内容被交换。

④外设的读写操作同步完成,只进行写操作,则忽略读操作;主机只进行从机的读操作,则主机须发送一个空字节给从机引发传输

SPI特征

从设备引脚管理(NSS)

①软件模式: 可以设置SPI_CR1寄存器的SSM位来使能这种模式,在这种模式下NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1的SSI位来驱动。

②硬件模式:第一种情况:NSS输出使能,当STM32工作为SPI模式的时,NSS输出已经通过SPI_CR2寄存器的SSOE位使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS引脚相连并配置为硬件NSS的SPI设备,将自动变成从的SPI设备。            

                      第二种情况:NSS输出被关闭:允许操作于多主环境。

时钟信号的相位和极性

①SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系,CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态下保持低电平;如果CPOL被置‘1’,SCK引脚在空闲状态保持高电平。     如果CPHA(时钟相位)位被置‘1’,SCK时钟的第二个边沿(0为下降沿,1为上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。    如果CPHA位被清0,SCK时钟的第一个边沿(0为下降沿,1为上升沿)进行数据位采集,数据在第一个时钟边沿被锁存。 CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。

CPHA=1:

CPHA=0:

 

SPI接口原理

①数据帧格式 根据SPI_CR1寄存器的LSBFIRST位,输出数据可以选择MSB(高位)先或者LSB(低位)先。 根据SPI_CR1寄存器的DFF位,可以选择数据帧是8位或者16位,对发送和接收都有效。

②状态标志 通过三个标志可以完全监控SPI总线的状态

发送缓存器空闲标志(TXE) 此标志为1的时候,表示发送缓冲寄存器为空,可以写入下一个待发送数据进入缓冲器中,当写入SPI_DR(数据寄存器)时,TXE标志被清除。

接收缓冲器非空(RXNE) 此标志为1表明接收缓冲器中包含有效数据,读SPI数据寄存器可以清楚此标志

忙BUSY标志 BSY标志由硬件设置与清楚,此标志表明SPI通信层的状态

 

SPI中断

SPI引脚配置

SPI配置:

#include "stm32f10x.h"
#include "spi.h"

void SPI2_Init(void)
{

    GPIO_InitTypeDef GPIO_InitStruct;
	SPI_InitTypeDef  SPI_InitStruct;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
	

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStruct);
    GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
	

    SPI_InitStruct.SPI_Direction =SPI_Direction_2Lines_FullDuplex;//SPI设置为双线双向全双工
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;    //设置为主模式
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;//设置SPI数据大小为8位
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;      //设置SPI默认时钟悬空为高电平
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;     //设置SPI数据捕获在第二个时钟沿
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;        //设置SPI NSS引脚由软件管理
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//设置波特率预分频值为256
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//设置SPI模式为从高位传输
	SPI_InitStruct.SPI_CRCPolynomial = 7;//设置SPI_CRC值计算的多项式
    SPI_Init(SPI2,&SPI_InitStruct);
    SPI_Cmd(SPI2, ENABLE );  //使能SPI2外设                                                                                                                       
}
//SPI2读写一个字节
u8 SPI_ReadWriteByte(u8 dat)
{
   u8 t;
   while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET)//等待发送缓存器为空
	{
	    t++;
		if(t>=200)
		{	
		 return 0;//超时返回错误标志
		}
	  	
	
	}
	 SPI_I2S_SendData(SPI2,dat);
	while( SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//等待接收
  {
	   t++;
		if(t>=200)
		{
		  return 0;//超时返回错误标志
		}
	  	
	}
  return  SPI_I2S_ReceiveData(SPI2);
	
}
//设置SPI波特率
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler )
{
  SPI_Cmd(SPI2,DISABLE);//修改波特率前需禁用SPI
  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
  SPI2->CR1 &= 0XFFC7;//将SPI控制寄存器1(CR1)的BR[2:0]3、4、5位清零,其他位不变这三位控制波特率预分频系数
  SPI2->CR1 |= SPI_BaudRatePrescaler;//将新的预分频值写入CR1的BR位
  SPI_Cmd(SPI2, ENABLE );

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值