赞
踩
SPI是串行外围设备接口,是一种高速的、全双工的、同步的通信总线,可以同时发出和接收串行数据,可以作为主机或者丛机工作,提供频率可编程时钟,发送结束中断标志,写冲突保护,总线竞争保护等。
在点对点的通信中,SPI接口不需要进行寻址操作,在多个期间的系统总,每个从器件需要独立的使能信号

SPI的接口方式有两种,包括五线制和四线制
五线制:
MOSI(DO):作为主器件时为数据输出,作为从器件时为数据输入
MISO(DI):作为主器件时为数据输入,作为从器件时为输入输出
SCLK:时钟信号线,由主器件产生
NSS(CS):从器件使能信号,由主器件控制,低电平有效
GND:公共地线
四线制:
MOSI:作为主器件时为数据输出,作为从器件时为数据输入
SCLK:时钟信号线,由主器件产生
NSS(CS):从器件使能信号,由主器件控制,低电平有效
GND:公共地线
1)MOSI:主设备输出,从设备输入,数据从 主设备到从设备
因为SPI是全双工通信总线,即主机和从机都可以同时收发数据,所以需要两条线负责从 主机到从机和从 从机到主机的传输,而MOSI就是负责主机向从医发送数据的。
数据输出通过MOSI发出,数据在时钟的上升沿或者下降沿时改变,在紧接着的下降沿或上升沿被读取
2)MISO:主设备输入,从设备输出,数据从 从设备到主设备
3)SCLK时钟信号,由主设备产生
SCLK提供时钟脉冲,可以统一主机和从机之间的数据传输,只有在有效的时钟信号下才能正常传输数据,如果不同设备支持的最高传输速率不同时,在传输过程中传输频率受限于低速一方
4)NSS(CS)从设备片选信号,由主设备控制
不同于IC,如果和其他设备通讯,不需要寻址操作,只需要通过片选信号就能和从机通信。NSS可以控制芯片是否被选中,也就是说只有片选信号为预先规定的使能信号的时候,对芯片操作有效。
5)从选择NSS脚管理:
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为低电平

数据传输的过程:


要初始化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); }
//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最近接收的数据 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。