欢迎光临,嵌入式开源博客

STM32 SPI接口的简单实现

 

通常SPI通过4个引脚与外部器件相连:

● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。

● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。

● SCK:串口时钟,作为主设备的输出,从设备的输入

●NSS:从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用来作为“片选引脚”,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。从设备的NSS引脚可以由主设备的一个标准I/O引脚来驱动。一旦被使能(SSOE位),NSS引脚也可以作为输出引脚,并在SPI处于主模式时拉低;此时,所有的SPI设备,如果它们的NSS引脚连接到主设备的NSS引脚,则会检测到低电平,如果它们被设置为NSS硬件模式,就会自动进入从设备状态。当配置为主设备、NSS配置为输入引脚(MSTR=1,SSOE=0)时,如果NSS被拉低,则这个SPI设备进入主模式失败状态:即MSTR位被自动清除,此设备进入从模式。

 

时钟信号的相位和极性

SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态保持低电平;如果CPOL被置’1’,SCK引脚在空闲状态保持高电平。

如果CPHA(时钟相位)位被置’1’,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0’,SCK时钟的第一边沿(CPOL位为’0’时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位采样,数据在第一个时钟边沿被锁存。

CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
图212显示了SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK脚、MISO脚、MOSI脚直接连接的主或从时序图。

 

3373759070854139230

CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
上图显示了SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK脚、MISO脚、MOSI脚直接连接的主或从时序图。
注意:

1. 在改变CPOL/CPHA位之前,必须清除SPE位将SPI禁止。
2. 主和从必须配置成相同的时序模式。
3.SCK的空闲状态必须和SPI_CR1寄存器指定的极性一致(CPOL为’1’时,空闲时应上拉SCK为高电平;CPOL为’0’时,空闲时应下拉SCK为低电平)。
4. 数据帧格式(8位或16位)由SPI_CR1寄存器的DFF位选择,并且决定发送/接收的数据长度。

 我只要知道主机和从机的CPOL和CPHA位要一致就够了。

 

有2种NSS模式:
●软件NSS模式:可以通过设置SPI_CR1寄存器的SSM位来使能这种模式。在这种模式下NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1的SSI位来驱动
● 硬件NSS模式,分两种情况:
─NSS输出被使能:当STM32F10xxx工作为主SPI,并且NSS输出已经通过SPI_CR2寄存器的SSOE位使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS引脚相连并配置为硬件NSS的SPI设备,将自动变成从SPI设备。当一个SPI设备需要发送广播数据,它必须拉低NSS信号,以通知所有其它的设备它是主设备;如果它不能拉低NSS,这意味着总线上有另外一个主设备在通信,这时将产生一个硬件失败错误(HardFault)。
─ NSS输出被关闭:允许操作于多主环境。
//我们用软件NSS主从的转换都可借助库来实现

 

数据帧格式
根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB在先。
根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式对发送和/或接收都有效。
配置一个SPI 这里选SPI2

如下:

 

SPI_InitTypeDef  SPI_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
SPI_Cmd(SPI2, DISABLE);            //必须先禁能,才能改变MODE
SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex;  //两线全双工
SPI_InitStructure.SPI_Mode =SPI_Mode_Master;       //主
SPI_InitStructure.SPI_DataSize =SPI_DataSize_8b;      //8位
SPI_InitStructure.SPI_CPOL =SPI_CPOL_High;        //CPOL=1时钟悬空高
SPI_InitStructure.SPI_CPHA =SPI_CPHA_1Edge;       //CPHA=1 数据捕获第2个
SPI_InitStructure.SPI_NSS =SPI_NSS_Soft;        //软件NSS
SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_2;  //2分频
SPI_InitStructure.SPI_FirstBit =SPI_FirstBit_MSB;      //高位在前
SPI_InitStructure.SPI_CRCPolynomial =7;        //CRC7

SPI_Init(SPI2,&SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);

//spi的配置结束了可以使用了。

 

也可用 函数SPI_StructInit 把SPI_InitStruct中的每一个参数按缺省值填入

3266798579704652579

1398086209323335046

_____________________________________________________________________________________

 

发送缓冲器空闲标志(TXE)【3.0 SPI_I2S_FLAG_TXE】
此标志为’1’时表明发送缓冲器为空,可以写下一个待发送的数据进入缓冲器中。当写入SPI_DR时,TXE标志被清除。
接收缓冲器非空(RXNE)【3.0 SPI_I2S_FLAG_RXNE】
此标志为’1’时表明在接收缓冲器中包含有效的接收数据。读SPI数据寄存器可以清除此标志。

 

注意在2.0的库中函数 SPI_SendData SPI_ReceiveDataSPI_GetFlagStatus 等在3.0的库中 变为

SPI_I2S_SendData  SPI_I2S_ReceiveData  SPI_I2S_GetFlagStatus

 

写一个发送/接受函数

 

static u8 SPIByte(u8 byte)

{
 
while((SPI2->SR &SPI_I2S_FLAG_TXE)==RESET);
 //while((SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE))==RESET);
  

SPI2->DR = byte;
 //SPI_I2S_SendData(SPI2,byte);
 

while((SPI2->SR &SPI_I2S_FLAG_RXNE)==RESET);

//while((SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE))==RESET);
return(SPI2->DR);

 //returnSPI_I2S_ReceiveData(SPI2);读寄存器用硬件清除标志位。
 //SPI_I2S_ClearFlag(SPI2,SPI_I2S_FLAG_RXNE) ;直接软件清除标志位。
}

 

 

这里有两种写法直接操作寄存器与用库函数,相对来说直接操作寄存器应该更直观一些。

赞(0) 打赏
未经允许不得转载:Huangea Blog 嵌入式博客 » STM32 SPI接口的简单实现
分享到: 更多 (0)

评论 3

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    又来看你了

    运气不好怎么转运4年前 (2014-11-03)回复
  2. #2

    现在越来越多的人们都喜欢带小叶紫檀手串,其主要原因就是小叶紫檀手串非常的美观、上档次。听木物语小叶紫檀http://www.muhush.com/

    鉴别紫檀手串4年前 (2014-11-10)回复
  3. #3

    支持一下

    起重机配件4年前 (2015-04-07)回复

一个很有意思的网站

留言板友链

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏