你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32之SPI通讯应用

[复制链接]
gaosmile 发布时间:2020-6-17 12:41
        上一章我们讲到了IIC通讯,这一章来说一说SPI通信,同样的很多模块也用到了SPI通信,比如0.96寸的OLED模块。玩过单片机的小伙伴都知道OLED有4针的也有7针的,4针的就是IIC通信,7针的就是SPI通信。
一、 SPI 简介
  SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32 也有 SPI 接口。SPI通讯使用 3 条总线及片选线,3条总线分别为 SCK、MOSI、MISO、SS。
微信图片_20200617124107.png
  (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。
  (4) SS( Slave Select):片选信号线,也称为 NSS、CS。当有多个SPI 从设备与 SPI 主机STM32相连时,设备的其它信号线 SCK、MOSI及 MISO同时并联到相同的 SPI总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。

二、 具体代码编写1.SPI引脚初始化
  我们使用 STM32 的 SPI1 的主模式,第一步就要是能 SPI1 的时钟,SPI1 的时钟通过 APB2ENR 的第12位来设置。其次要设置 SPI1 的相关引脚为复用输出,这样才会连接到 SPI1 上否则这些 IO 口还是默认的状态,也就是标准输入输出口。这里我们使用的是 PA5、PA6、PA7 这 3 个,所以设置这三个为复用 IO。
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 函数来实现的。
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 芯片的数据手册可了解各种它定义的各种指令的功能及指令格式。这里我就不过多的将写了。
如果觉得文章对你有帮助,欢迎转发、分享给你的朋友,感谢您的支持!如需转载请联系我!
收藏 2 评论0 发布时间:2020-6-17 12:41

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版