date
icon
password
博客链接
Pin
Pin
Hide-in-Web
Hide-in-Web
网址
type
slug
tags
category
bottom
bottom
Hide-in-Config
Hide-in-Config
comment
status
summary
🔥
这个页面是关于五种常见通信协议的笔记,包含 UART、RS232、RS485、IIC、SPI,不过没有 CAN 总线的。
还有一点需要说明的是,本笔记侧重于协议的介绍,不会设计代码,对于上述的课程我也跳过了代码和硬件操作的部分,只看了协议部分。
建议大家使用电脑来查看笔记内容,会有最好的显示效果。

前置知识

什么是全双工,什么是半双工,什么是单工?
全双工指的就是电话两端的人可以实时对骂,比如微信电话就是全双工通信;半双工指的是电话两端同时只能有一个人说话(回合制对骂🥺),比如对讲机就是半双工的。
单工指的是只能由 A 向 B 发送数据,A 只能作为发送机,B 只能作为接收机,就像是话筒,只能由话筒将声音传递给音响。
一般来说,如果通信协议里只有一根用于传递数据的线,那么它大概率就是半双工,如果有两根线那么就是全双工,单工的比较少。
什么是串行,什么是并行?
串行的结构如下:
notion image
并行的结构如下:
notion image
如果使用交通线路来理解,并行可以认为是八条道路,每条道路都有一辆车从 A 点同时开往 B 点;串行可以理解为只有一个车道,8 辆车依次从 A 点开往 B 点。
如果仅从交通道路的角度来想串行和并行的话,你一定会觉得如果能用并行肯定就用并行呀,这样数据传输更快,但实际情况是车道上的车在并行的时候更快,而数据在传输时采用并行的方式更快。为什么会如此呢?
如果采用并行的方式传输数据,为了避免竞争和冒险现象的出现(理解为为了让所有线上的数据都能同时抵达终点),一定要等到最慢的那根线上的数据也传输完毕才能开始下一轮传输,为了做到这一点,并行传输的数据需要设置一个周期,在每个周期内是能够保证所有数据传输完毕的。由于这个周期的存在,并行数据传输的速度上限就被确定了,因此单位时间能够传递的数据量也就被确定了。
而对于串行方式而言,由于数据是先后传递的,因此只要识别的灵敏度足够高,串行数据的传输速度可以做到非常快,不需要等待其他数据传输完成再开始下一轮。但在现实的车道中,为了保证安全,自然无法像数据传递那样只设一条线路,让所有的车都最大马力往前冲以加快速度。
采用串行方式比较多的另一个原因是并行方式下,数据的传递需要同时占用多条线路,这在要通信的设备数量比较多时是比较耗费资源的,比如有 10 个设备通信,并行的方式每个设备需要 8 根线,那么总共就需要 80 根,而串行就只需要 8 根。无论从资源角度还是管理的角度来看,8 根线都会比 80 根线要好。而且并行方式下线路之间还可能会发生串扰,降低数据可靠性。
💡
后面介绍的所有协议都是串行的,没有并行的。
波特率/比特率
波特率是通信这门课中涉及的知识点,指的是码元的传输速度,单位是 波特或 baud;比特率指的是比特的传输速度,单位是 bps(即 bit per second)。
那么码元是什么意思呢?
码元指的是传输的数据是以什么样的方式编码的,比方说,我传递的是二进制的数,那么就意味着采用二进制编码,1 秒钟传递 010010 这 6 位数据,总共就有 6 位码元与 6 位比特,此时波特率与比特率的数值是一样的,都是
如果传输的数据是以四进制的方式编码的,也就是说一个码元就是一个四进制数,此时若 1 秒钟内传递 0132010 这 6 位数据,由于数据的实际传输是采用高低电平来表示的,也就是说得以二进制方式传递,因此实际传输的 0132010 为 00 01 11 10 00 01 00 这 12 位数据,总共就有 6 位码元与 12 位比特。此时的波特率为 6 baud,而比特率为 12 bps。
如果你学习过通信原理,你会知道,波特率与比特率的关系为:
一般进制数是 2 的倍数。
但在实际的嵌入式应用中,二进制数使用的是最多的,因此有时候会将波特率与比特率混起来讲,从而让很多人摸不着头脑。在后面的部分中,无特殊说明,都将波特率当作是比特率来看待,因为实际应用中协议都是统一设置波特率的,没有设置比特率的。
奇偶校验
奇偶校验是校验中最简单的一种,在传输的数据末尾加上校验位,通过判断一串数据中 1 的个数是奇数个还是偶数个来确定传输的数据是否出错。
比方说,要采用奇校验的方式传输数据 1001 1000,其中 1 的个数为 3 个,刚好是奇数个,因此校验位就设置为 0,实际传输的数据为 1001 1000 0;
再比方说,要采用偶校验的方式传输数据 1001 1000,其中 1 的个数为 3 个,因此校验位就设置为 1,这样数据中 1 的个数就是 4 个了,为偶数,实际传输的数据为 1001 1000 1;
当接收方知晓传输方的校验方式时,比方说双方说好采用偶校验,那么如果接收方受到的数据为 1001 1000 1,其中 1 的个数为偶数个,那么就判断这个数据没有问题;如果接收方收到的数据为 1011 1000 1,其中 1 的个数为奇数个,那么就判断这个数据出现了错误,会将其舍弃。
奇偶校验虽然简单实用,但存在的问题是:
  1. 无法对数据进行纠错,数据发生错误时,接收方不知道数据是哪里错了,因此如果要重新接收只能要求发送方重新传送;
  1. 如果错误的数量为偶数个则无法判别数据传输是否出错了,比方说传输的数据为 1001 1000 1,采用偶校验,如果接收到的数据为 1111 1000 1,1 的个数仍为偶数,那么接收方就无法判断数据是否错了,仍会将其当作是正确的数据。
 
共模干扰与差模干扰
首先,讨论这两种干扰的前提是我们要分析两根信号线,两根信号线以一根地线为参考。
产生原因与特点:
共模干扰指的是两根信号线在受到雷电、电火花等外界的电磁干扰时,会同时产生幅度相同、相位相同(一般不会完全相等)的电压信号,由于地线的电压是不变的,因此相当于是两根信号线上的电压增大,会对后续电路造成影响。产生原因应该是外界的电场变化会产生磁场在信号线间磁耦合,最后感应出共模电压。
共模干扰是在信号线与地之间产生的,因为这种干扰是外界对电路的影响,输入线路与输出线路是同时感应出幅度、相位相近的信号。
notion image
差模干扰是在内部开关高频启停、负载切换等情形下引入的,会在输入线路与输出线路中产生幅度相同、相位相反(一般不会完全相同或相反)的电压信号。
差模干扰是在两根信号线之间产生的,因为这种干扰是电路内部的原因引起的。
notion image
如何消除:
一般共模干扰和差模干扰都是高频的信号。
共模干扰可以通过下面的电路结构来消除,中间使用的两个电容一般是安规 X 电容(下面右侧图)。
notion image
notion image
 
在上面的电路中,如果有共模信号通过,它们会同时通过电容流向地,而正常的信号不会通过电容。
差模干扰可以通过下面的电路结构来消除,使用的电容一般是安规 Y 电容(下面右侧图):
notion image
notion image
在上面的电路中,由于差模信号在两根信号线间是有压差的,因此干扰会从上面一根信号线通过 Y 电容流向下面一根信号线,避免差模干扰通过后续电路,但这不会阻碍共模干扰信号通过。
对于共模干扰信号,常见的还有使用共模扼流圈来抑制(可以参考这个视频: 共模电感是如何抑制共模信号的_哔哩哔哩_bilibili)。
共模扼流圈共有四个引脚,其中两个是输入口,两个是输出口。
当输入差模信号时,扼流圈内部的磁场相互抵消,差模信号正常通过,如下图所示:
notion image
电路图
电路图
当输入共模信号时,扼流圈内部的磁场相互增强,内部磁场的变化会阻碍电流的变化(楞次定律),从而抑制共模信号通向后续电路,如下图所示:
notion image
电路图
电路图
根据上面的原理,也能够作出差模扼流圈,只要把其中一个线圈的方向反转就行。不过虽然是这么说,好像市面上没有这么设计的,差模扼流圈基本都是两个引脚,需要两个分别接在输入通路和输出通路抑制差模信号。
什么是帧?
帧用于定义一个完整的数据集合单位,可以把他想象成是一篇文章。每篇文章都会有开头,有结尾,还有中间的正文部分,同样地,一帧数据也会有起始位、终止位,还会有数据部分。

UART

定义
UART 即 Universal Asynchronous Receiver Transmitter,通用异步收发器,是一种通用的串行、异步通信总线该总线有两条数据线,可以实现全双工的发送和接收在嵌入式系统中常用于主机与辅助设备之间的通信。
串口协议
notion image
USART 的串口协议中,规定数据位固定为 8 位,另外一定要包含一个起始位加在 8 位数据前面,停止位加在数据末尾。校验位是可有可无的。
串口协议中规定,在信道中没有数据传输(信道空闲)时,默认为高电平,同时,起始位固定为低电平。这样,在有数据传输过来时,信道就会先传来一个低电平,接收机才能反应过来后面有数据,准备好接收(接收机是通过空闲位与起始位之间的下降沿来判断是否接收数据的)。当数据传输完毕时,停止位固定为高电平,也方便后续进入空闲状态。
停止位的存在并不是多余的,停止位的意义就是起到缓冲作用,一方面将信道恢复为高电平,方便后续产生下降沿,另一方面也能避免前后两串数据挨得太紧,让接收机反应不过来。比如前一串数据的末尾是低电平,而起始位也是低电平,如果接收机尚未处理好前一串数据,那么就可能会将下一串数据的起始位忽略,等待下一个空闲位到起始位下降沿的到来。
数据的传输采用的是低位先行的原则。现在假设不设置校验位,那么发送方和接收方就会协商好不采用校验位,每串数据固定为 10 位(1 位起始位 + 8 位数据位 + 1 位停止位)。若需要传输的数据为 0101 0101,那么根据低位先行的原则,传输的数据就是 1010 1010,加上起始位和停止位,最终传输的数据就是 0 1010 1010 1
现在我们知道了串口数据的构成规则了,接下来就要弄清楚通信双方是如何达成共识——即传输的高低电平与数据位是如何一一对应的?
假如现在要传输的数据为 01 以及 0011,在电平的表现上都是先低电平而后高电平,如果只看波形,是无法区分出数据位数,因此需要利用时间来对数据位进行划分。比如 1 位数据传输 1 秒钟,那么 01 就需要 2 秒,0011 就需要 4 秒,这样就能够通过时间来将传输的电平与实际的数据关联起来了。
在实际中,波特率就是双方约定的“时间”,波特率为每秒传输的码元个数,即二进制数的位数,若双方共同约定传输的波特率为 9600,则每秒都传输 9600 位,也就是说传输 1 位数据的时间为 ,传输了 就说明传输了 10 位数据。在这个过程中,需要接收方和发送方共同“掐表”,发送方掐了 ,就说明已经传输了 10 位数据出去了;接收方收到起始位后掐了 ,就说明已经接收到 10 位数据了。
这种方式看似很完美,但会存在一个问题,由于数据传输不是同步的(没有专门的时钟线路来同步发送方和接收方的时钟),而是靠起始位来标定开始(即异步),当数据源源不断地从发送方传输给接收方时(即如果传输的数据位不是 8 位,而是 1000 或更多位),如果双方的时钟稍微有些偏差,比如 0.1%,就会出现数据错位、丢失的情况,因此规定每帧传输的数据固定为 1 个字节(一帧数据就是 1 个起始位 + 数据位+ 1 个停止位)。
硬件连接
notion image
注意连接的时候是交叉连接的,TXD 是发送端,RXD 是接收端。
UART 的问题
首先,抗干扰能力差。这个是我亲身体会过的,之前使用 stm32 与 FPGA 进行 UART 串口通信,当时传输的是数据包,没有加帧尾校验,结果在数据包很长(大概 100 字节)时另一方接收到的数据丢包率特别高,基本上发送的每个数据包都是错的,说明数据在传输过程中有很多被干扰舍弃了。
其次,UART 通信时一般直接使用处理器使用的电平,即 TTL 电平。比如 51单片机认为 5V 是高电平,而 stm32 认为 3.3V 是高电平,如果让它们二者直接进行 UART 通信,在没有转换电路与保护电路的情况下容易对芯片造成不可逆的影响。
再者,UART 器件没有规定连接器标准,因此不同设备之间在连接时需要考虑连接电路,比较麻烦。
RS232
RS232 全称为 Recommanded-Standard 232,即推荐标准 232。
近距离,异步,统一接口,负逻辑,电平转换芯片。
RS232 是为了解决 UART 问题而出现的一个标准,本质上还是利用 UART,但提高了传输距离。
RS232 最初有 25 个引脚,但后来缩减到了 9 个引脚,其中 TXD,RXD,GND 这三条线是 UART 通信的主要线路,而另外的 RTS/CTS、DTR/DSR、DCD/RI 等硬件流控信号主要在 老式调制解调器 或需要流控的工业应用里才会用到。
RS232 还统一了 UART 的连接器接口,结构如下所示:
notion image
长得有些像 VGA 接口,但 VGA 是模拟视频信号传输线,有专门的 VGA 协议,与 RS232 是不同的,而且 VGA 接口是 15 根线的。
RS232 采用 -3~-15V 表示逻辑 1,采用 3~15V 表示逻辑 0,较大的电压范围提升了传输的抗干扰能力。但细心的你一定发现,RS232 采用的是负逻辑,即负电压表示正逻辑,正电压表示负逻辑,为什么会这样呢?
上网搜索也基本没看到解释,AI 的解释是,负电压更加稳定,由于 UART 在信号空闲时是逻辑 1,因此为了让传输更加稳定就采用负电压表示信号的空闲状态。
经过上述的处理,UART 的传输距离也得到了增加,可以达到 15m。

由于 RS232 的电平标准与单片机等器件的 TTL 标准不同,因此需要通过电平转换芯片进行转换。
notion image
💡
注意,RS232 只规定了电气层面,意思就是只是对两个设备之间的通信方式进行了处理,不涉及设备内部的 UART 处理方式,因此在对设备进行软件编程时,UART 与 RS232 是没有区别的。
RS485
RS485 全称为 Recommended-Standard 485,也是一个推荐标准,本质上还是 UART 通信。
远距离,速度快,差分信号,半双工,点对多点。
RS485 相比于 RS232,能够提供更远距离的通信(大概在 1500米,是 RS232 的 100 倍),且抗干扰能力更强,更厉害的是,能够实现点对多点的通信,就是 A 可以选择与 B0~Bn 个设备进行串口通信(只需要两根线)。
由于 RS232 的两根信号线分别用来发送信号与接收信号,信号线中的电平是对地电平,因此容易受到共模干扰,传输距离有限。RS485 针对信号的传输方式做出了改进,RS485 虽然也是两根信号线,但与 RS232 不同的是,它采用的是半双工的形式传输的,传输的逻辑电平通过两根信号线的差分信号来确定,同一时刻只能发送信号或接收信号。
规定两条信号线中一条线为 H 线,另一条线为 L 线,最终接收到的电平为 H 线的电平与 L 线的电平作差,如果差值在 +2~+6V 之间,则定义为逻辑高电平,如果差值在 -2~-6V 之间,则定义为逻辑低电平。
notion image
notion image
实际的传输线采用的是双绞线,抑制共模干扰能力强。
💡
由于 RS485 采用的是半双工的通信,因此在写程序时就需要注意这一点,对 UART 通信代码稍做修改。
关于点对多点的通信,这个通信方式与 IIC 的通信是类似的,在后面说到 IIC 时会介绍。
notion image
💡
RS485 传输信号的速度比 RS232 快,因为 RS485 抗干扰能力强,可以采用高频信号传输,高频意味着每个比特的处理时间短,单位时间内可以处理更多比特。

IIC

出现背景
这个是过去一篇文档中让 AI 写的,直接粘贴过来了。
在上世纪七十年代末,微电子技术正飞速发展,电视、音响、收音机这些消费电子产品内部变得越来越复杂。一块电路板上塞满了各种功能的芯片:负责信号的,控制声音的,管理图像的。工程师们兴奋地把这些新功能集成进芯片里,但很快遇到了一个棘手的麻烦:
“连线灾难”来临了。 以前想让主处理器(CPU)和一个简单的存储器说说话还算容易,无非是多拉几根线。但现在不同了,芯片越来越多,每个芯片需要和主处理器沟通的信息量也在增加。工程师们无奈地看着电路板上布满了密密麻麻的并行线路(一个数据字节就需要8根数据线!),这还不包括地址线、控制线、电源线、地线…… 就像一个纠缠不清的毛线团。每增加一个芯片,布线工作就成倍复杂,电路板面积被迫加大,成本直线上升,抗干扰能力下降。更麻烦的是,每个芯片需要大量的引脚来接这些线,导致芯片体积变大、封装复杂、成本高昂。主处理器也需要许多宝贵的引脚来连接各个“手下”,这就成了“瓶颈”。
飞利浦的工程师们,特别是半导体部门(后来独立成了恩智浦 NXP)的一个小组,每天都在和这些“连线怪兽”搏斗。他们想:能不能用一种更简洁、更优雅的方式来让这些芯片“交谈”?能不能只用几根线就让它们和谐共处?
当时的其他串行方案要么速度太慢(像早期的UART主要连接终端设备),要么协议太复杂不适合小板内通信。工程师们需要一种专门为芯片间通信设计、高度集成化、低成本、低引脚占用的方案。这个需求极其迫切,飞利浦自家的彩电、录像机就是典型的“芯片扎堆”系统。
于是,在1982年,一个天才的想法在飞利浦内部诞生了,最初它被称为“Inter-Integrated Circuit” (最初内部可能简称 IIC 或类似) —— 这个名字清晰地道出了它的核心任务:让集成在同一个系统板上的不同芯片之间高效地对话。 后来,这个简称被正式规范为 I²C (读作 "I-squared-C"),其中“平方”表示“集成”(Integrated)的含义被强调了两遍。
它的设计非常聪明:
  1. 两条线搞定一切: 只用两根线——SDA (Serial Data Line) 传输数据,SCL (Serial Clock Line) 提供同步时钟。所有通信都在这两条线上完成。
  1. 地址识别: 每个连接到 I²C 总线上的芯片都有一个唯一的地址。主机(比如主处理器)想和谁说话,就在广播时先喊出这个地址,就像点名一样,只有被点名的芯片才会应答。
  1. 多主多从: 不仅可以一个主机控制多个从机,更妙的是(在某些设计中)允许多个主设备存在(比如一个主处理器和一个协处理器),它们通过一套仲裁机制来决定谁在什么时候控制总线。
  1. 开源漏极结构: 芯片通过一个精巧的开漏(或集电极开路)输出结构与总线相连,配合外部的上拉电阻(Pull-up Resistor)。这使得不同电压等级的芯片可以安全地连接到同一个总线上(只要电压较高一方能容忍较低电压),并且当一个芯片向总线写‘0’时是“强下拉”,而当它不主动拉低总线时,上拉电阻会让总线恢复成默认的‘1’(高电平)。这个结构保证了多设备共享总线时不会打架(只要多个设备同时发‘1’或者发‘0’,总线就是‘1’或‘0’;而当一个发‘1’(实际是释放总线)一个发‘0’,发‘0’的赢)。
  1. 协议分层: 通信格式定义清晰,包括起始信号、停止信号、数据位传输、应答信号(ACK/NACK)等,确保了可靠的数据传输。
I²C的出现,像是一把精巧的钥匙,打开了芯片间高效通信的大门。工程师们惊喜地发现:
  • 原来需要几十甚至上百根连接线的子系统,现在只需要两根线就搞定了!
  • 芯片需要的引脚数量急剧减少,很多低速外围芯片只需要4-8个引脚就能工作(包括电源)。
  • 电路板设计变得异常简单和清晰,成本大大降低,可靠性提高。
  • 在同一个系统中,轻松添加或移除新芯片(只要给个唯一地址)。
  • 由于协议相对简单,硬件和软件实现起来都很直接。
I²C 技术迅速被飞利浦推向市场(首个公开标准文件出现在1992年的版本2中),并很快风靡了整个电子行业
  • 它成为了连接微控制器(CPU)和周边器件的神经系统:EEPROM(存储配置信息)、实时时钟(RTC)、数字温度传感器、电压监控器、低速ADC/DAC、GPIO扩展器、LED控制器、小尺寸LCD屏驱动等等,几乎随处可见I²C的身影。
  • 它在消费电子领域如鱼得水,电视机、DVD播放器、机顶盒、数字摄像头内部,I²C总线悄无声息地协调着各个模块。
  • PC主板上也大量使用I²C来访问内存上的串行存在检测(SPD)信息、监控CPU/主板温度和风扇转速(通过SMBus,一个基于I²C的变种)。
  • 手机里用它来连接电池管理芯片、环境光传感器、指南针、指纹识别模块等。
  • 嵌入式系统工程师更是对它青睐有加,像树莓派这类开发板,I²C接口是最常用的扩展方式之一,无数的传感器模块通过简单的4线(VCC, GND, SDA, SCL)接口就能轻松挂上去。
  • 后续发展:为了适应更高速度的需求(尤其是在显示应用上),I²C标准也在不断演进,先后增加了高速模式 (Hs-mode, 最高 3.4Mbps), 超快速模式 (UFM, 最高 5Mbps)高速+ (Hs+)模式(高达10Mbps)等。衍生协议如PMBus(电源管理)、DDC(显示器数据通道)也基于I²C建立。
⭐ IIC 介绍及通信过程
IIC 的速度比 UART 的慢。
IIC 又称为是 I2C,是一种半双工的通信方式,它的特点是同步、短距离、点对多点(UART 是异步的通信方式)。主要由两根信号线进行通信,一根是 SDA(Serial Data),另一根是 SCL(Serial Clock),SDA 传输数据,SCL 传输时钟。
主要过程:
  1. 首先,系统内部会确定一个设备作为主机,主机设备发送起始信号给其他设备,告诉它们马上要开始 IIC 通信了;
  1. 其次,主机设备发送想要通信的从机设备的地址(七位)和数据传输方向(一位,告诉从机它作为发送机还是接收机);
    1. 比如,主机想要与地址为 0x3 的从机设备通信,且从机作为接收机,接收主机发来的数据,那么就会发送 0000 0110,其中高七位为从机设备的地址,最低位为传输方向(0 表示 主机 → 从机,1 表示 从机 → 主机);如果发送的是 0000 0111,那么从机就作为发送机,给主机发送数据。
  1. 对应地址的从机返回应答信号,告诉主机我准备好了;
  1. 主机发送一个字节数据或主机读取一个字节数据;
  1. 从机发送应答信号或主机发送应答信号;
  1. 重复第四步和第五步若干次;
  1. 主机发送停止信号终止通信。
💡
  1. 空闲状态下 SCL 和 SDA 都是高电平。
  1. IIC 传输的数据位都是高位先行的,与 UART 相反。
  1. IIC 通信时是以字节为单位传输的,传输完一个字节后会紧跟一个应答位,因此 IIC 的一帧数据就是 9 位。
起始信号和终止信号:
notion image
如上图所示,左侧为起始信号,当 SCL 为高电平时 SDA 为下降沿;右侧为终止信号,当 SCL 为高电平时 SDA 为上升沿。有一个特点是,SCL 是“迟到早退”,SDA 是“早出晚归”。
数据位读取:
图中 SDA 的两条线要分开来看,分别表示 SDA 为高电平和低电平的情况。
图中 SDA 的两条线要分开来看,分别表示 SDA 为高电平和低电平的情况。
在 SCL 上升沿来临前(在 SCL 的低电平),发送机需要完成 SDA 数据的发送操作;在 SCL 高电平期间,SDA 上的数据被成功读取;重复这个过程。
💡
SCL 只能由主机来控制,用于同步主机与从机的时钟。在 UART 通信中,由于异步的原因,如果主机与从机的时钟稍有偏差就会造成数据的错漏。但对 IIC 而言,是依靠主机发送的 SCL 时钟来同步的,因此不会有数据错漏的问题。
应答位:
notion image
图中展示的情况是主机向从机发送数据,但请不要被图中的两个 SDA 给误导了,SDA 线路只有一根,图中画出两个 SDA 的目的只是在于说明控制权。在发送 8 位数据时,控制权在主机,从机只能读取,因此从机的 “SDA 线” 都保持为高电平空闲状态,这只是在说明从机无权控制 SDA 线路而已。从机只有在最后一位应答位时控制 SDA。
在 8 位数据传输完成后,无论之前第 8 位数据是高电平还是低电平,发送机都会将其重置为高电平。如果接收机应答,接收机会将 SDA 电平拉低为低电平;反之,如果接收机不应答,则不对 SDA 作出反应。
主机与从机可能发生的不应答情况如下:
主机读取从机数据(也可以理解为从机发送数据给主机)的情况【此时主机发送应答或非应答信号】:
  1. 读完指定长度数据:主机读到期望的最后一个数据字节后,用 NACK 通知从机“我不再需要更多数据了”。
  1. 读操作中止:主机出于错误处理或其他逻辑决定不继续读后续字节。
主机发送数据给从机的情况【此时从机发送应答或非应答信号】:
  1. 地址不匹配:总线上没有任何从机匹配 Master 发出的从机地址。
  1. 寄存器/资源不可用:目标从机存在,但对应的寄存器地址超出范围或该资源此刻不可访问。
  1. 设备忙(Slave Busy):从机内部正忙(例如 EEPROM 正在写入内部存储),无法立即响应。
  1. 通信出错:诸如总线仲裁丢失、总线冲突等异常情形。
💡
应答位的发送是交叉的关系,主机写入从机,应答位就由从机发;主机读取从机(从机发送给主机),应答位就由主机发。
关于非应答的情况,其实就按照常理来想就行了:
首先秉持、坚定一个原则,主机是拥有数据读取、写入决定权的设备;其次,应答位的存在是让主机或从机知道应不应该继续发送数据。
然后,当主机读取从机数据时,数据最终是传递到主机的,因此主机要告诉从机应不应该继续发数据,主机接收到特定数量的数据后就会告诉从机不要继续发了,之后再发送停止位;或者,主机暂时不方便接收数据了,那么也要告诉从机不要继续发了,避免错过一些数据;
当主机写入从机时,是主机应该知道要不要继续发数据,应答位自然就是从机发了,当从机自己不方便读数据时,才会发出非应答位,否则,无论是主机发完规定数量的数据还是主机有事离开了,都不需要从机来应答,因为主机自己会去停止发送数据。
硬件配置上:
notion image
在硬件配置上,一般会在 SDA 与 SCL 的线路上配置一个上拉电阻,然后 CPU 内部配置为开漏输出模式,这样 SDA 与 SCL 就默认是高电平了。
默认高电平的好处是从机之间可以采取“线与”的策略,节省了 MOS 管的数量。所有的主机与从机内部只需要配置一个 MOS 管即可,MOS 管的一端接地,另一端连接 SDA 线路,当需要输出高电平时,主机或从机什么都不用做,MOS 管断开;当需要输出低电平时,将 MOS 管导通。由于所有的设备都连接在一条 SDA 线路上,但每次只有一个设备发送数据,因此“线与”能够保证线路轻易地输出低电平(只要参与通信的设备拉低,整条线路就都是低电平了)。
⭐ IIC 的常见时序
指定地址写(两个地址):
主机向从机写入数据。
notion image
上图中,S 表示的是起始位,在随后要发送的数据中,至少应包含 3 个字节。
  • 第一个字节,包含 7 位从机地址和对从机进行的操作(读还是写,0 表示写,1 表示读);
  • 第二个字节,从机寄存器地址。指定对从机地址中的哪个寄存器进行写操作(操作完成后,从机内的寄存器地址会自增 1);
  • 第三个字节,指定要写入的数据。
在每两个字节间,需要插入应答位 RA,在上一条目的讨论中,我们知道,主机向从机写入数据,最后是由从机来发送应答位的,而从机只有在地址不匹配、寄存器资源不可用、设备忙、通信出错时等情况时会不应答,因此在通信开始后从机基本上都会应答,一直到主机发送完数据后由主机发送停止位。
关于应答位:在应答位的 SCL 时钟上升沿来临前,主机将 SDA 拉高后瞬间从机将 SDA 拉低(从机拥有对 SDA 的短暂控制权),表示从机响应(不过图中没有这个尖峰,示波器没有捕捉到),之后一直到 SCL 下降沿来临前,SDA 信号都会保持低电平。SCL 下降沿来临后,从机释放 SDA(即放弃对 SDA 的短暂控制权,SDA 变为高电平),之后 SDA 重新由主机控制。
💡
来解释一下什么是 SCL 与 SDA 的控制权
首先,SCL 的控制权完全掌握在主机手中,主机想要让 SCL 变为高电平就变为高电平,想要让 SCL 变为低电平就变为低电平;
其次,SDA 的控制权要看目前的低电平是由谁引起的,如果当前的低电平是由主机引起的(比如主机发送数据给从机或主机发送应答位给从机),那么主机就拥有对 SDA 的控制权;如果当前的低电平是由从机引起的(比如从机发送应答位给主机或主机读取从机数据),那么从机就拥有对 SDA 的控制权。在 SDA 为高电平时,可以说双方都没有对 SDA 的控制权,也可以说双方都有这个控制权。
在最后一个 RA 中,由于从机成功接收到了主机发来的三字节数据,因此再次将 SDA 置低,等到 SCL 的下降沿来临时,从机释放 SDA,将控制权还给主机,前面这个过程与过去的两个 RA 响应一样;但在后面,主机拿到控制权后又将 SDA 拉低是为了后续触发停止条件(停止条件为在 SCL 为高电平器件 SDA 迎来上升沿)。
当前地址读(一个地址):
notion image
当前地址读指的是主机读取从机当前地址下(寄存器)的数据。
在这个过程中,主机会先后发送两个字节的数据:
第一个字节指示从机的地址以及对从机进行的操作;
第二个字节直接发送数据。
与指定地址读相比,当前地址读时,主机并未发送要操作的从机寄存器地址,因此默认操作寄存器指针当前指向的位置。
在前面提到过,每个从机内部都会有一个寄存器的指针,在每次主机对从机读或写后,寄存器指针都会自动指向下一个地址,因此在当前地址读操作结束后,寄存器指针也会向下移动。
指定地址读:
主机 从 从机 处读数据。
notion image
“指定地址读”的过程实际上可以拆分为两个阶段——“寻址”和“发送”。
“寻址”指的是主机先发送从机地址和操作、从机寄存器地址,从机响应后(可看作是指定地址写),知道主机在召唤自己,于是向主机发送地自身的地址和操作、数据(可看作是当前地址读)。
图中一共包含四个字节的数据,其中每两个字节间都会有应答周期 RA 存在。在图中第二个 RA 之后,还有一个 Sr 的周期,它表示的是“再起始”,将前后两个阶段(第一个阶段是主机写入从机,第二个阶段是从机写入主机)拼接起来。
当然,如果在第二个 RA 后加入停止位也是可以的,这样 Sr 的位置就更改为新的起始位,图中的两个阶段就变为了两个过程。不过这样做的话,有可能会出现主机更换的情形,SCL 的控制权移交给其他设备了。
 
IIC 的仲裁机制
IIC 的仲裁机制是为了避免多个设备同时成为主机并发起通信,造成冲突,实现仲裁的基础是“线与”。
在仲裁机制中,想要成为主机的所有设备先一同进行发送数据的过程,然后逐渐淘汰:
  1. 所有设备同时发送起始信号(SCL 置高电平,SDA 置低电平);
    1. 由于起始信号所有设备都是一样的,因此所有设备读取到的 SDA 均为低电平,仲裁继续;
  1. 所有设备开始进行从机地址的发送,每发送一位就读取当前 SDA 的状态,如果当前的 SDA 状态与发送的数据是一致的,则继续发送,否则,则仲裁失败,停止发送;
    1. 在前面我们曾说过,SDA 采用的是“线与”的逻辑,也就是说,当 SDA 连接的所有设备都发送高电平时,SDA 为高电平,只要有一个设备将 SDA 拉低(将 SDA 接地),那么 SDA 就是低电平,同时,该设备相当于获得了 SDA 的控制权。仲裁本质上就是利用这一个机制,看所有竞争主机的设备中同时间谁先发出低电平而其他设备为高电平。
      由于 IIC 是高位先行的原则,因此发送的从机地址也是从高位开始,聪明的你一定察觉到这本质上就是比较所有设备发送的从机地址的大小,从机地址小的主机获得控制权。如果有一部分设备的从机地址相同,那么就会进行读/写位的比较,再到后面数据的比较。
🌟
仲裁机制的好处就在于,即便最后某个主机胜出了,它先前所发送的所有数据也都是有效的。
💡
单看“通信过程”后可能还会有很多疑惑,再看“常见时序”疑惑应该能消除很多。

SPI

出现背景
SPI 出现得比 IIC 稍微早一些。
下面的内容是 AI 写的,挺有意思的。
从前,在一个电子元件的王国里,大家需要互相交流信息。可那时候,大家交流的方式很杂乱:有的喜欢一次发很多线来传递消息(比如并行总线),但这就像一群人拉着几十条电话线到处走,既麻烦又占地方。于是,国王——微处理器——觉得必须有一种更简洁的方式来沟通。
有一天,一个聪明的工匠发明了一种新的通信方法:只要四根线,就能让主设备和从设备快速说话。这四根线就是 SCLK(时钟)、MOSI(主发从收)、MISO(主收从发)、CS(片选)。这就像国王定好节拍(时钟),然后用一条管道告诉臣子消息(MOSI),臣子再用另一条管道回话(MISO),最后国王用片选信号点名:“喂,现在轮到你了!”
这种方式非常直接、快速,就叫做 SPI(Serial Peripheral Interface,串行外设接口)。SPI 一出场,就比同时代的 UART 更灵活。UART 像是两个人约好波特率、再互相写信的朋友,虽然简单,但要频繁对齐时钟。而 SPI 不用那么麻烦,国王直接带着时钟,臣子跟着拍子回答,速度快得多。
随着时间的推移,SPI 变得非常流行。存储器、传感器、显示屏,几乎所有小器件都想和国王建立 SPI 的联系。可问题来了:SPI 就像一个“点对点的对话”,国王每次只能和一个臣子说话,还要一根片选线点名。如果臣子太多,宫殿里到处都是片选线,场面乱成一锅粥。
于是,SPI 的亲戚们开始登场。有人发明了 I²C,它只用两根线,就能让很多臣子排队回答,仿佛一个大会议厅;不过它的速度没 SPI 那么快,而且协议也更复杂。SPI 依旧保留了自己的优势:简单、直接、快。即使后来出现了 USB、PCIe 这样更强大的通信方式,SPI 依旧在小型场景里顽强地生存,就像一个不显山露水却随处可见的老管家。
直到今天,在各种单片机和嵌入式系统里,人们仍能看到 SPI 的身影。它没有宏大的光环,也不像 USB 那样“全民皆知”,但只要你拆开一块电路板,八成会看到一群靠 SPI 与主控交谈的芯片。就像一个古老的故事,这种简洁又高效的方式已经深深刻进了电子王国的血脉里。
要不要我接着帮你讲讲 SPI 家族的“衍生故事”,比如双线 SPI、四线 SPI、甚至 QSPI(四倍速 SPI)是怎么出现的?
SPI 介绍
SPI 的全称为 Serial Peripheral Interface,即串行外设接口。
SPI 是高速的(相对于 IIC)、全双工、同步串行通信总线,与 IIC 类似,也是采用主从方式工作,这意味着它可以挂载多个设备。SPI 是高位先行的,且采用的是正逻辑(高电平表示逻辑 1,低电平表示逻辑 0)。
SPI 至少需要四根线路(如果要实现全双工),结构如下:
notion image
其中 SCLK 是时钟同步线;MOSI 全称为 Master Output Slave Input,为主机输出从机输入线;MISO 全称为 Master Input Slave Output,为主机输入从机输出线;CS 为 Chip Select,即 片选线,用于选择主机与哪个从机通信。
💡
前面说到,SPI 至少需要四根线,为什么是至少呢?
当主机要连接多个从机时,就需要使用多根线路作为 CS 片选信号,当从机上的 CS 接口为 0 时,表示从机被选中,当 CS 接口为 1 时,表示从机未被选中(一般都是低电平有效,不过老师说也会有特殊)。
主机连接多个从机的情形如下:
notion image
从图中可以看出,两根 CS 线分别连接了两个从机设备,如果要控制更多的从机,比如 8 个,那么似乎就需要 8 根 CS 线了,这样就耗费了主机太多的资源。我觉得,为了节省主机的资源,可以在中间使用一个译码器芯片进行转接,将主机的 CS 线连接到译码器上,将译码器输出连接到从机,这样就可以用更少的主机资源控制更多的从机了。
💡
SPI 是没有应答位的,因此一帧数据发送完后可以立即发送下一帧数据,没有起始位、停止位、应答位,这样数据传输的速率就会比较高,但会存在的一个问题是,无法确认对方是否收到了数据。
💡
SPI 是在上升沿的时候发送数据,在下降沿的时候接收数据,而 IIC 是在下降沿到来后的低电平期间发送数据,在上升沿到来后的高电平期间接收数据。
SPI 的四种模式
SPI 是通过极性(CPOL)和相位(CPHA)来决定数据何时接收与发送的,并以此分为四个模式。
CPOL 为 0 时,时钟最初为低电平;CPOL 为 1 时,时钟最初为高电平
CPHA 为 0 时,接收机是在第一个时钟边沿采样数据(采样数据即为读取数据);CPHA 为 1 时,接收机是在第二个时钟边沿采样数据。CPHA 为 0 时,假如第一个时钟边沿是上升沿,那么接收机后续就是通过时钟上升沿采样;CPHA 为 1 时,假如第二个时钟边沿为上升沿,那么接收机后续也是通过时钟上升沿采样。
模式一:CPOL 为 0,CPHA 为 0。
上升沿读取数据,下降沿发送数据。
在这个模式下,时钟最初为低电平,CPHA 表示在第一个时钟边沿采样,第一个时钟边沿为上升沿(因为时钟最初从低电平变为高电平肯定是上升沿),那么后续就都是通过上升沿来采样读取数据。
模式二:CPOL 为 0,CPHA 为 1。
上升沿发送数据,下降沿读取数据。
在这个模式下,时钟最初为低电平,CPHA 为 1 表示接收机在第二个时钟边沿采样数据,第二个时钟边沿肯定是下降沿。
模式三:CPOL 为 1,CPHA 为 0。
时钟初始为高电平,上升沿发送数据,下降沿读取数据。
模式四:CPOL 为 1,CPHA 为 1。
时钟初始时为高电平,上升沿读取数据,下降沿发送数据。
💡
在这里有一个注意点,在主机通过 CS 选中某个芯片后,第一个 MSB(最高位) 数据就已经提前发出去了,这个数据不需要等待时钟边沿。
💡
主机采用什么样的模式来输出数据是根据从机决定的,从机在出厂时就会将其设定为某种特定的工作模式,必须保证主机与从机的模式一致。
IIC 与 SPI 的对比
notion image
 
 
 
如果本篇内容对你有用,能否『请我吃根棒棒糖🍭 』🤠…
相关文章
无线网络技术
Lazy loaded image
DSP 应用技术笔记
Lazy loaded image
GCC & GDB 学习笔记
Lazy loaded image
数字图像处理笔记
Lazy loaded image
Git 学习笔记
Lazy loaded image
区块链的应用与技术笔记
Lazy loaded image
遥感数字图像处理笔记
Lazy loaded image
电磁场与电磁波笔记
Lazy loaded image
机器学习笔记(吴恩达)
Lazy loaded image
数字信号处理笔记
Lazy loaded image
通信电子线路笔记(高频电子线路)
Lazy loaded image
微机原理和系统设计笔记
Lazy loaded image
模拟电子技术笔记 无线网络技术
Loading...