草庐IT

SPI总线协议基本原理及相关配置

木秋木 2023-07-18 原文

单片机应用中,最常用的通信协议主要有三个,即USART、IIC和SPI。关于前两个的介绍在之前文章学习过,这次介绍一下第三个通信协议——SPI。

 

SPI(Serial Peripheral Interface Bus)由摩托罗拉公司开发,它是高速全双工同步串 行通信协议。SPI 支持一主多从,这点类似于 IIC,但是又与 IIC 选通从设备的方式不同, IIC 是通过发送从机地址来选通从机,而 SPI 则是通过拉低连接到从机的 NSS 引脚对从机进行选通的。SPI 一般应用由四个引脚组成(一主一从):

⚫ SCLK(Serial Clock):串行时钟,由主机发出

⚫ MOSI(Master Output,Slave Input):主机输出从机输入信号,由主机发出

⚫ MISO(Master Input,Slave Output):主机输入从机输出信号,由从机发出

⚫ NSS(Slave Selected):选择信号,由主机发出,一般是低电位有效

SPI与IIC主要的区别:

SPI是高速(高达30Mbps)远距离全双工同步串行同行的,IIC是低速(最大4Mbps)近距离半双工同步串行通行的,
■相同点
1、均采用串行,同步的方式
2、均采用TTL电平,传输距离和应用场景类似
3、均采用主从方式工作
■不同点
1、IIC为半双工,SPI为全双工(MOSI,MISO同时收发)
2、IIC有应答机制,SP1无应答机制
3、IC通过向总线广播从机地址来寻址,SP1通过向对应从机发送使能信号来寻址

4、IIC总线读写时序比较固定统一,设备驱动编写方便;而SPI则需要根据不同的设备的datasheet来实现读写,相对要复杂一些。

SPI特点:

1、SPI的寻址方式是主设备向从设备的片选线上发送使能信号,表示选中该从设备,注意如果 在单片机的接口当中只有一个NSS接口,因此是只能够连接一个外部设备的,如果我们要连接多个外设就需要通过利用单片机中的其它IO口来模拟NSS接口。因此在接多个设备的情况下就要占用多个IO口了,这也是SPI通信的一个缺点,这一点就不如IIC的寻址方式。
2、SPI总线在进行数据传输时,先发高位,后发低位(这一点跟USART有区别),而且发完一个字节不用应答。

3、时钟线在上升沿或者下降沿是发送数据,然后在下降沿或者上升沿接收数据

SPI主从连接示意图

         图中可以看出虽然 SPI 也是串行通信协议,但是主机所占用的引脚依然比 IIC 和 UART 的多,而且主机引脚数量会随着从机数量的增加而增加(增加对从机的选通部分)。

        主机在通过 MOSI 数据线发送数据的同时,从机也会通过 MISO 将数据传输给主机(收发 同时进行),它们以虚拟环形拓扑连接。数据通常先移出最高位,在时钟边沿,主机和从机 均移出一位,然后在传输线上输出给对方(改变数据)。在下一个时钟沿,主从设备的接收 器都从传输线接受该位,并设置为移位寄存器的新的最低有效位(采样数据)。在完成这样 一个移出-移入的周期后,主机和从机就交换了寄存器中的一位,传输可能会持续任意数量的时钟周期。传输完成后,主设备会停止时钟信号,并拉高 NSS 选通线。下图是 SPI 通信时序:

 SPI通信时序图

 SPI 是一种非常灵活的通信协议,我们可以配置它的时钟极性、时钟相位、一次传输的 数据位数等。我们依次来看一下:

⚫ 时钟极性(CPOL) 时钟极性用于设置时钟在空闲时的电平状态,CPOL 为 1 则时钟空闲时为高电平,CPOL 为 0,时钟空闲时为低电平,如下图。这就直接导致了第一个信号沿是下降沿还是上升沿, 通常 CPOL 和时钟相位(CPHA)配合使用。

⚫ 时钟相位(CPHA) 时钟相位用于设置在第几个时钟沿发生时对数据线进行采样,当 CPHA=1 时表示在第二 个时钟沿对数据线进行采样,当 CPHA 为 0 时,在第一个时钟沿对数据进行采样,如下图:

 另外在图中可以看到,CPOL 和 CPHA 的组合能够产生 4 中不同的工作模式,以适应不同 的使用场景。具体的模式由具体的芯片手册参考设置,一般建议 CPOL=CPHA=0,CPOL=CPHA=1。

SPI 内部结构框图:

 STM32 的 SPI 外设包含两种通信协议,第一个是 SPI 协议,第二个是 I2S 协议,他们通过 SPI_I2S 配置寄存器(SPI_I2S_CFGR)的 11 位 I2SMOD 进行选择。SPI 接口默认工作在 SPI 方式,可以通过软件把功能从 SPI 模式切换到 I2S 模式。在小容量和中容量产品上,不支持 I2S 音频协议。因为 STM32 将 SPI 和 I2S 合并到了一起,因此我们在使用 SPI 时要先设置该寄存器的 位 11 来指定使用 SPI 功能。 但是这些配置已经在固件库中定义好了,我们直接利用固件库中对应SPI函数库或者I2S函数库即可。

SPI 固件库:

ST 固件库主要使用 SPI_TypeDef 这个结构体类型来管理 SPI 外设。通过配置这个结构体来实现对 SPI 外 设的配置,并调用固件库提供接口函数中的初始化函数,实现将配置参数写入 STM32 寄存器中。SPI 外设的 接口函数如下所示:

配置 SPI 步骤如下:

1. 初始化 SCK、MOSI 引脚为复用推挽输出,初始化 MISO 引脚为浮空输入;

2. 初始化 NSS 引脚为推挽输出并默认拉高(使用软件 NSS 情况下);

3. 配置 SPI 初始化结构体,内容包括:主/从模式,高/低位在前,数据帧位数(8 位/16 位),配置时钟极性(CPOL)、时钟相位(CPHA)、软件 NSS、时钟分频值等。

SPI初始化配置:

void SPI2_Init(void){ //SPI2初始化
	SPI_InitTypeDef  SPI_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);//使能SPI_2时钟

	GPIO_InitStructure.GPIO_Pin = SPI2_MISO;  //SPI2的MISO(PB14)为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = SPI2_MOSI | SPI2_SCK;	//SPI2的MOSI(PB15)和SCLK(PB13)为复用推免输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = SPI2_NSS;	 //SPI2的NSS(PB12)为推免输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(SPI2PORT,&GPIO_InitStructure);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//双线输入输出全双工模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置为SPI的主机模式(SCK主动产生时钟)
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//SPI数据大小:发送8位帧数据结构;8位还是16位需要根据需要根据具体的芯片手册参考来确定
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//空闲状态时SCK的状态,High为高电平,Low为低电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//时钟相位,1表示在SCK的奇数沿边采样,2表示偶数沿边采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS由软件控件片选,只是针对点对点通信的情况下,如果是连接了多个设备,就要使用硬件模式,在通信之前手动选择哪一个设备通信。
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//时钟的预分频值(0~256),保证总线的稳定性,如果总线稳定性不好就可以相对应加大预分频值
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB高位在前
	SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC较验和的多项式,例如CH376芯片没有校验功能
	SPI_Init(SPI2,&SPI_InitStructure); //初始化SPI2的配置项
	SPI_Cmd(SPI2,ENABLE); //使能SPI2  
}

 接收发送函数:

//SPI2数据发+收程序(主要用于发送)
u8 SPI2_SendByte(u8 Byte){ //通过SPI2口发送1个数据,同时接收1个数据
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET); //如果发送寄存器数据没有发送完,循环等待
	SPI_I2S_SendData(SPI2,Byte);  //往发送寄存器写入要发送的数据
	while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET); //如果接受寄存器没有收到数据,循环
	return SPI_I2S_ReceiveData(SPI2);
}

有关SPI总线协议基本原理及相关配置的更多相关文章

  1. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  4. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  5. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  6. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  7. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  8. 神州数码无线产品(AC+AP)配置 - 2

    注意:本文主要掌握DCN自研无线产品的基本配置方法和注意事项,能够进行一般的项目实施、调试与运维AP基本配置命令AP登录用户名和密码均为:adminAP默认IP地址为:192.168.1.10AP默认情况下DHCP开启AP静态地址配置:setmanagementstatic-ip192.168.10.1AP开启/关闭DHCP功能:setmanagementdhcp-statusup/downAP设置默认网关:setstatic-ip-routegeteway192.168.10.254查看AP基本信息:getsystemgetmanagementgetmanaged-apgetrouteAP配

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. hadoop安装之保姆级教程(二)之YARN的配置 - 2

    1.1.1 YARN的介绍 为克服Hadoop1.0中HDFS和MapReduce存在的各种问题⽽提出的,针对Hadoop1.0中的MapReduce在扩展性和多框架⽀持⽅⾯的不⾜,提出了全新的资源管理框架YARN. ApacheYARN(YetanotherResourceNegotiator的缩写)是Hadoop集群的资源管理系统,负责为计算程序提供服务器计算资源,相当于⼀个分布式的操作系统平台,⽽MapReduce等计算程序则相当于运⾏于操作系统之上的应⽤程序。 YARN被引⼊Hadoop2,最初是为了改善MapReduce的实现,但是因为具有⾜够的通⽤性,同样可以⽀持其他的分布式计算模

随机推荐