SPI协议详解(图文并茂+超详细)

article/2025/8/26 23:49:40


加入技术交流群

领取资料

文章目录

  • 先说串口
  • SPI通讯协议
  • SPI特性
    • 时钟频率
    • 时钟极性 CKP/Clock Polarity
    • 时钟相位 CKE /Clock Phase (Edge)
    • 时钟配置总结
  • 模式编号
  • 多从机模式
  • 优缺点
    • SPI通讯的优势
    • SPI的缺点
  • 编程实现

先说串口

因为之前写过一篇UART,通用串行异步通讯协议,UART的相关资料

因为UART没有时钟信号,无法控制何时发送数据,也无法保证双发按照完全相同的速度接收数据。因此,双方以不同的速度进行数据接收和发送,就会出现问题。

如果要解决这个问题,UART为每个字节添加额外的起始位停止位,以帮助接收器在数据到达时进行同步;

双方还必须事先就传输速度达成共识(设置相同的波特率,例如每秒9600位)。

传输速率如果有微小差异不是问题,因为接收器会在每个字节的开头重新同步。相应的协议如下图所示;

串口传输的过程

如果您注意到上图中的11001010不等于0x53,这是一个细节。串口协议通常会首先发送最低有效位,因此最小位在最左边LSB。低四位字节实际上是0011 = 0x3,高四位字节是0101 = 0x5

异步串行工作得很好,但是在每个字节发送的时候都需要额外的起始位停止位以及在发送和接收数据所需的复杂硬件方面都有很多开销。

不难发现,如果接收端和发送端设置的速度都不一致,那么接收到的数据将是垃圾(乱码)。

下面开始讲一下SPI协议,会有哪些优点。

SPI通讯协议

于是我们想有没有更好一点的串行通讯方式;相比较于UARTSPI的工作方式略有不同。

SPI是一个同步的数据总线,也就是说它是用单独的数据线一个单独的时钟信号来保证发送端和接收端的完美同步

时钟是一个振荡信号,它告诉接收端在确切的时机对数据线上的信号进行采样。

产生时钟的一侧称为主机,另一侧称为从机。总是只有一个主机(一般来说可以是微控制器/MCU),但是可以有多个从机(后面详细介绍);

数据的采集时机可能是时钟信号上升沿(从低到高)或下降沿(从高到低)。

具体要看对SPI的配置;

整体的传输大概可以分为以下几个过程:

  • 主机先将NSS信号拉低,这样保证开始接收数据;

  • 接收端检测到时钟的边沿信号时,它将立即读取数据线上的信号,这样就得到了一位数据(1bit);

    由于时钟是随数据一起发送的,因此指定数据的传输速度并不重要,尽管设备将具有可以运行的最高速度(稍后我们将讨论选择合适的时钟边沿和速度)。

  • 主机发送到从机时:主机产生相应的时钟信号,然后数据一位一位地将从MOSI信号线上进行发送到从机;

  • 主机接收从机数据:如果从机需要将数据发送回主机,则主机将继续生成预定数量的时钟信号,并且从机会将数据通过MISO信号线发送;

具体如下图所示;

SPI的时序

注意,SPI是“全双工”(具有单独的发送和接收线路),因此可以在同一时间发送和接收数据,另外SPI的接收硬件可以是一个简单的移位寄存器。这比异步串行通信所需的完整UART要简单得多,并且更加便宜;

SPI特性

SPI总线包括4条逻辑线,定义如下:

  • MISOMaster input slave output 主机输入,从机输出(数据来自从机);

  • MOSIMaster output slave input 主机输出,从机输入(数据来自主机);

  • SCLK Serial Clock 串行时钟信号,由主机产生发送给从机;

  • SSSlave Select 片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。

其他制造商可能会遵循其他命名规则,但是最终他们指的相同的含义。以下是一些常用术语;

  • MISO也可以是SIMODOUTDOSDOSO(在主机端);

  • MOSI也可以是SOMIDINDISDISI(在主机端);

  • NSS也可以是CECSSSEL;

  • SCLK也可以是SCK;

本文将按照以下命名进行讲解[MISO, MOSI, SCK,NSS]

下图显示了单个主机和单个从机之间的典型SPI连接。

主从连接

时钟频率

SPI总线上的主机必须在通信开始时候配置并生成相应的时钟信号。在每个SPI时钟周期内,都会发生全双工数据传输

主机在MOSI线上发送一位数据,从机读取它,而从机在MISO线上发送一位数据,主机读取它。

就算只进行单向的数据传输,也要保持这样的顺序。这就意味着无论接收任何数据,必须实际发送一些东西!在这种情况下,我们称其为虚拟数据;

从理论上讲,只要实际可行,时钟速率就可以是您想要的任何速率,当然这个速率受限于每个系统能提供多大的系统时钟频率,以及最大的SPI传输速率。

时钟极性 CKP/Clock Polarity

除了配置串行时钟速率(频率)外,SPI主设备还需要配置时钟极性

根据硬件制造商的命名规则不同,时钟极性通常写为CKPCPOL。时钟极性和相位共同决定读取数据的方式,比如信号上升沿读取数据还是信号下降沿读取数据;

CKP可以配置为1或0。这意味着您可以根据需要将时钟的默认状态(IDLE)设置为高或低。极性反转可以通过简单的逻辑逆变器实现。您必须参考设备的数据手册才能正确设置CKP和CKE。

  • CKP = 0:时钟空闲IDLE为低电平 0
  • CKP = 1:时钟空闲IDLE为高电平1

时钟相位 CKE /Clock Phase (Edge)

除配置串行时钟速率和极性外,SPI主设备还应配置时钟相位(或边沿)。根据硬件制造商的不同,时钟相位通常写为CKECPHA

顾名思义,时钟相位/边沿,也就是采集数据时是在时钟信号的具体相位或者边沿;

  • CKE = 0:在时钟信号SCK的第一个跳变沿采样;
  • CKE = 1:在时钟信号SCK的第二个跳变沿采样;

时钟配置总结

综上几种情况,下图总结了所有时钟配置组合,并突出显示了实际采样数据的时刻;

其中黑色线为采样数据的时刻;

蓝色线为SCK时钟信号;

具体如下图所示;

模式编号

SPI的时钟极性和相位的配置通常称为 SPI模式,所有可能的模式都遵循以下约定;具体如下表所示;

SPI ModeCPOLCPHA
0 [00]00
1 [01]01
2 [10]10
3 [11]11

除此之外,我们还应该仔细检查微控制器数据手册中包含的模式表,以确保一切正常。

多从机模式

前面说到SPI总线必须有一个主机,可以有多个从机,那么具体连接到SPI总线的方法有以下两种:

第一种方法:多NSS

  1. 通常,每个从机都需要一条单独的SS线。
  2. 如果要和特定的从机进行通讯,可以将相应的NSS信号线拉低,并保持其他NSS信号线的状态为高电平;如果同时将两个NSS信号线拉低,则可能会出现乱码,因为从机可能都试图在同一条MISO线上传输数据,最终导致接收数据乱码。

具体连接方式如下图所示;

多NSS连接

第二种方法:菊花链

菊花链

在数字通信世界中,在设备信号(总线信号或中断信号)以串行的方式从一 个设备依次传到下一个设备,不断循环直到数据到达目标设备的方式被称为菊花链

  1. 菊花链的最大缺点是因为是信号串行传输,所以一旦数据链路中的某设备发生故障的时候,它下面优先级较低的设备就不可能得到服务了;
  2. 另一方面,距离主机越远的从机,获得服务的优先级越低,所以需要安排好从机的优先级,并且设置总线检测器,如果某个从机超时,则对该从机进行短路,防止单个从机损坏造成整个链路崩溃的情况;

具体的连接如下图所示;

菊花链连接

其中红线加粗为数据的流向;

所以最终的数据流向图可以表示为:

数据流图

SCK为时钟信号,8clks表示8个边沿信号;

其中D为数据,X为无效数据;

所以不难发现,菊花链模式充分使用了SPI其移位寄存器的功能,整个链充当通信移位寄存器,每个从机在下一个时钟周期将输入数据复制到输出。

优缺点

SPI通讯的优势

使SPI作为串行通信接口脱颖而出的原因很多;

  • 全双工串行通信;
  • 高速数据传输速率。
  • 简单的软件配置;
  • 极其灵活的数据传输,不限于8位,它可以是任意大小的字;
  • 非常简单的硬件结构。从站不需要唯一地址(与I2C不同)。从机使用主机时钟,不需要精密时钟振荡器/晶振(与UART不同)。不需要收发器(与CAN不同)。

SPI的缺点

  • 没有硬件从机应答信号(主机可能在不知情的情况下无处发送);
  • 通常仅支持一个主设备;
  • 需要更多的引脚(与I2C不同);
  • 没有定义硬件级别的错误检查协议;
  • 与RS-232和CAN总线相比,只能支持非常短的距离;

编程实现

下面是通过STM32的cubemx自动生成的HAL库代码,比较简单,截取了其中一部分,具体如下;

static void MX_SPI1_Init(void)
{hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;				//主机模式hspi1.Init.Direction = SPI_DIRECTION_2LINES;	//全双工hspi1.Init.DataSize = SPI_DATASIZE_8BIT;		//数据位为8位hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;		//CPOL=0hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;			//CPHA为数据线的第一个变化沿hspi1.Init.NSS = SPI_NSS_SOFT;					//软件控制NSShspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//2分频,32M/2=16MHzhspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;			//最高位先发送hspi1.Init.TIMode = SPI_TIMODE_DISABLE;			//TIMODE模式关闭hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC关闭hspi1.Init.CRCPolynomial = 10;					//默认值,无效if (HAL_SPI_Init(&hspi1) != HAL_OK)				//初始化{_Error_Handler(__FILE__, __LINE__);}
}//发送数据
HAL_StatusTypeDef  
HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
//接收数据
HAL_StatusTypeDef  
HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);

http://chatgpt.dhexx.cn/article/InhSMHaC.shtml

相关文章

Xms Xmx Xss 释义

Xms 是指设定程序启动时占用内存大小。一般来讲,大点,程序会启动的快一点,但是也可能会导致机器暂时间变慢。 Xmx 是指设定程序运行期间最大可占用的内存大小。如果程序运行需要占用更多的内存,超出了这个设置值,就会…

JVM中的Xms和Xmx

JVM内存参数 -Xms和-Xmx 参考资料:(1) JVM常用内存参数配置 (2)深入理解Java虚拟机 -Xms和-Xmx (1)这两个参数老是搞混,特地记一下。-Xms 为JVM启动时申请的初始Heap值,默认为操作系统物理内存的1/64但小于1G。默认当…

通过两个小例子,更快了解-Xms -Xmx

我们偶尔就会遇到OutOfMemoryError,面试的时候总是能够被问道,可明明背好的面试题临时又不会了,答出来也很生硬,自己都想让自己快点“回家等通知”,那我们就通过下面的两个例子了解一下吧。 开发环境:ide…

程序员都需要会的JVM调优总结 -Xms -Xmx -Xmn -Xss,附idea配置实战(程序员必学)

目录 1.堆大小设置 2.JVM回收器和其他参数 3.JVM常见配置汇总 4.JVM在idea配置实战 5.JVM优化总结 1.堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制&#x…

Xms Xmx size 调整java虚拟机堆大小

-Xms 设置堆空间(年轻代)的初始内存大小,等价于 -XX:InitialHeapSize -Xmx 设置堆空间(老年代)的最大内存大小,等价于 -XX:MaxHeapSize 一旦堆区中的内存大小超过“-Xmx”所指定的最大内存时&#xff0c…

xms应用框架 - 基于.netcore

xms应用框架 - 基于.netcore 背景一、xms是什么二、能干什么三、目标四、框架介绍1、元数据管理2、组织架构3、授权体系4、高度可视化配置5、业务扩展6、流程7、二次开发 五、多图鉴赏六、源码地址 背景 鄙人经过多年开发,数百个项目“打磨(折磨)”,各种…

JVM -XMX与XMS是什么

XMS : JVM初始分配的堆内存XMX : JVM最大允许分配的堆内存,按需分配堆内存分配: 默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制; 空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。 因此服务器一般设置-Xms、-…

xms跨平台基础框架 - 基于.netcore

背景 鄙人经过多年开发,数百个项目“打磨(折磨)”,各种国内外框架平台都有涉及,没有一款称心顺手的,原因有三,一是设计反人类,二是不开源根本无法突破框架限制,三是即使开源也是阉割版&#xff…

C语言常见问题(3):Although the value stored to ‘ret‘ is used in the enclosing expression

就是这个ret返回值是在if里面表达式里赋值的,其他地方没有调用这个ret,相当于这个ret是个多余的!

DVWA靶场XSS(DOM/Reflected/Stored)/XSS+CSRF

目录 一、XSS (DOM) 1.Low 2.Medium 3.High 4.Impossible 二、XSS (Reflected) 1.Low 2.Medium 3.High 4.Impossible 三、XSS (Stored) 1.Low 2.Medium 3.High 4.Impossible 四、XSS(Stored)CSRF组合实验 1.直接访问修改密码URL 2.使用链接访问构造网页修改密码…

DVWA靶机-存储型XSS漏洞(Stored)

DVWA靶机-存储型XSS漏洞(Stored) 前章: DVWA靶机-暴力破解(Brute Force) && DVWA靶机的四个安全等级 DVWA靶机-命令注入漏洞(Command Injection) DVWA靶机-文件包含漏洞(File Inclusion) DVWA靶机-文件上传漏洞(File uploads) DVWA靶机-跨站请求伪造(…

DVWA-XSS(Stored)注入-Low-Medium-Hight

Low 1、进来这里可以看到&#xff0c;好像是有两个入口&#xff0c;先随便填个数据试试水&#xff0c;勒特 payload: <script>alert(1)</script> 2、直接提交&#xff0c;简单拿下。 Medium 1、继续尝试刚才的入口&#xff0c;勒特。 payload: <script>ale…

Solr---string类型的docValues属性、stored属性

描述&#xff1a; 使用solr6.0的默认配置后&#xff0c;多数的字段使用string类型&#xff0c;通过stored设置为false来减少存储大小&#xff0c;然而却没有效果&#xff0c;还是会存储并在查询时返回。 问题&#xff1a; 在managed-schema文件内发现&#xff0c;fieldType为s…

@available 修饰类成员变量报错Stored properties cannot be marked potentially unavailable

在不方便升级插件的情况下&#xff0c;可以手动修改这个问题

mysql routines是什么_MySQL入门:Stored Routines 的变数与流程 - Break易站

1 宣告与使用变数 在Stored routines中,除了可以宣告需要的参数外,如果需要处理比较复杂的资料,你也可以宣告「区域变数、local variables」。下列是宣告区域变数的语法与位置: 下列是几种宣告区域变数的范例: 宣告需要的区域变数后,你就可以在stored routines中使用它们…

Dvwa_XSS (Stored)

&#xff08;实验基础&#xff1a;有php语言和html语言基础&#xff09; 1、low 在Name里构造恶意脚本&#xff0c;写完10个字符后发现在输输不进去&#xff0c;此时按ctrlu&#xff08;火狐&#xff0c;Microsoft Edge&#xff0c;谷歌这三款浏览器都可用此快捷方式打开网页源…

DVWA-XSS (Stored)

目录 简介安全级别&#xff1a;Low安全级别&#xff1a;Medium安全级别&#xff1a;High安全级别&#xff1a;Impossible 简介 存储型XSS 长期存储于服务器端&#xff1b; 每次用户访问都会执行脚本代码&#xff1b; 安全级别&#xff1a;Low 查看源码 <?phpif( isse…

Oracle中的存储过程【Stored Procedure】和存储函数【Stored Function】

一、存储过程 1.1、存储过程的介绍 存储过程&#xff08;Stored Procedure&#xff09;是在大型数据库系统中&#xff0c;一组为了完成特定功能的SQL 语句集&#xff0c;经编译后直接存储在数据库中&#xff0c;用户调用指定存储过程的名字和传递对应的参数&#xff08;如果该…

DVWA指点迷津-XSS(Stored)

XSS(Stored) 特点 又名“存储型XSS”。攻击者的“恶意语句”会存储在服务器端数据库&#xff0c;具有很强的稳定性。每次前端调用数据库内容&#xff0c;则会触发语句。一般出现在留言板、上传资料等与数据库有交互的模块。相比反射型XSS&#xff0c;该类型的XSS带来的危害更…

XSS(Stored)

XSS(Stored) 前言 看了一个web的安全视频&#xff0c;里面有说说有的web漏洞都是输入输出的控制问题&#xff0c;虽然感觉说的太笼统了。但确实没什么毛病。sql注入来说&#xff0c;对用户的输入做好处理&#xff0c;对服务端的输出做好处理&#xff0c;对于我这样的菜鸡来说…