IIC协议长文详解-解惑版

2024-08-20 15:30:17 浏览数 (2)

嵌入式的世界里面有几个经典的协议:IIC,SPI,UART,CAN,1-WIRE,这些协议都是低速的,而且而是必须要掌握的内容,经常在使用和面试中出现。

现在应该是使用不成问题,但是细节里面的诸多细节要考虑,而且在每次使用的时候在看时序图时仍有若干疑惑的地方,协议除了传感器和MCU之间的通讯,其本身也可以传输数据,最终想实现的效果是可以在两个MCU之间使用协议来传输自己的数据包。ElectronBot-数字舵机篇,就好像这篇文章里面写的一样,自己封装,自己定义。这样的优点就是若干个MCU可以组合在一起,真正的形成一种MCU传感器网络。当然看起来很美好,但是可能实现起来由于各种原因可能会鸽。

但是无伤大雅,一些疑惑是肯定要解的。

51单片机模拟IIC以及引脚模式

佳能 EF 镜头 SPI详细协议

MCP3421-18bit ADC 调试,不过这个ADC写的是真不错

Seeed-XIAO-ESP32-C3-ADS1115测试

ADS1115-16Bit ADC 调试.上

Ti.ADS1115-15Bit差分ADC,TI的ADC也是补足了一些疑惑

这也是是之前写的,感觉还是有点不求甚解了。

本来也想上示波器的,但是在家里面没带。

这次呢会使用一个ST家的传感器(原因是便宜易得):

VL53L0X集成了领先的SPAD阵列(单光子雪崩二极管),并内嵌意法半导体第二代FlightSense™专利技术。

VL53L0X的940 nm VCSEL发射器(垂直腔面发射激光器)完全不为人眼所见,加上内置的物理红外滤光片,使其测距距离更长,对环境光的免疫性更强,对盖片的光学串扰表现出更好的稳定性。

NXP现在是IIC的协议的标准文档

而且各家呢,因为想变得有差异性,也会起一些自己的名字,但是大体上是换汤不换药的。就是IIC这个名字和SDA,SCL上面有改动。

这个是一个传感器的拓扑图

以前问,IIC到底是几根线,其实应该是一个2线的协议,这里就不加电源和中断线了。

SDA 和 SCL 都是双向线路都通过一个电流源或上拉电阻连接到正的电源电压,当总线空闲时这两条线路都是高电平连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能。

I2C 总线上数据的传输速率在标准模式下可达 100kbit/s 在快速模式下可达 400kbit/s 在高速模式下可达4Mbit/s 连接到总线的接口数量只由总线电容是 400pF 的限制决定。

下面的这个图就是全文最精华的图,数据究竟是什么时候传的?

看绿色的框,永远都是时钟小于数据

数据的有效性在时钟的HIGH时段,SDA线上的数据必须是稳定的

只有当SCL线上的时钟信号为LOW时,数据线的HIGH或LOW状态才能改变(见图上)。每传输一个数据位产生一个时钟脉冲。

也就是另一个疑惑,时序图里面这个互相交叉的线是什么意思,它在数据传输上的意思是,这个地方,进行了高低电平的变换,1是高,0是低,在时序上的意思是,在时钟信号为LOW时,数据可以进行变化。

这个是MCP3421的时序图

可以看到交叉是时钟的LOW,在数据上的意思是,处于data和ACK的位置,自然是有不同的状态。

我再换个说法重复一次上面的内容:

I2C总线进行数据传送时,在SCL的每个时钟脉冲期间传输一个数据位,时钟信号SCL为高电平期间,数据线SDA上的数据必须保持稳定,只有在时钟线SCL上的信号为低电平期间,数据线SDA上的高电平或低电平状态才允许变化,因为当SCL是高电平时,数据线SDA的变化被规定为控制命令(START或STOP,也就是前面的起始信号和停止信号)。

数据有效传输在scl信号的高电平期间,sda数据线保持稳定,在scl为低电平时允许sda数据线变化。

数据传输必须带响应,相关的响应SCL时钟脉冲由主机产生,在响应的时钟脉冲期间,发送器释放 SDA 线(输出高阻态使SDA线被上拉电阻拉高)。在响应的时钟脉冲期间,接收器必须将 SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。必须考虑建立和保持时间。

我觉得是应该是讲明白了,以前这就是个疑惑没有人告诉我。

接下来就是开始和停止:

启动和停止条件所有事务都以START (S)开始,并以STOP (P)终止(参见图上)。SDA线上的HIGH到LOW转换(SCL为HIGH)定义了START条件。

SCL为HIGH时,SDA线上的LOW到HIGH转换定义了一个停止条件。

这里的细节我觉得知道这些就可以了,在SDA拉低以后,这个通讯资源就相当于是独占了。

下面说传输的数据格式:

这里也给一个中文的翻译

byte组织:SDA上的数据传输是以8bit即一个字节为单位传输的,每一次传输的字节数没有限制,每传输完一个字节后必须跟随一个应答位。

以01001001(0X49)为例,其时序图如下:

放在SDA线路上的每个字节必须是8位长。每次传输可以传输的字节数不受限制。每个字节后面必须跟一个确认位。数据首先以最高有效位(MSB)传输。

如果目标不能接收或传输另一个完整的数据字节,直到它执行了一些其他功能,例如服务内部中断,它可以保持时钟线SCL LOW以迫使控制器进入等待状态。然后,当目标准备好接收另一个字节数据并释放时钟线SCL时,数据传输继续进行。

看懂了吗?这就是一次传多个字节的奥秘,在时钟线上,拉低向MCU说还没有搞完,在准备了,好了以后就把线拉高,开始。

说说ACK,NACK信号:

确认发生在每个字节之后。确认位允许接收方通知发送方该字节已成功接收,并且可以发送另一个字节。控制器产生所有时钟脉冲,包括确认第九时钟脉冲。

确认信号的定义如下:在确认时钟脉冲期间,发射机释放SDA线,因此接收器可以将SDA线拉低,并在该时钟脉冲的高电平期间保持稳定低电平

就是这个图

设置和保持时间也必须考虑在内。当SDA在第9个时钟脉冲期间保持高电平时,这被定义为不确认信号。

然后控制器可以生成一个STOP条件来中止传输,或者一个重复的START条件来开始新的传输。

也就是说这个ack信号会影响之后的数据传输,也好理解,都没有收到之后的发送都是无用功,就不发了。可以重新发,也可以停掉。

有五个条件会导致NACK的产生:

1. 总线上不存在具有传输地址的接收器,因此没有设备响应确认。

2. 接收器无法接收或发送,因为它正在执行一些实时功能,还没有准备好开始与控制器通信。

3. 在传输过程中,接收方接收到它不理解的数据或命令。

4. 在传输过程中,接收方不能再接收任何数据字节。

5. 控制器-接收器必须向目标发送器发出传输结束的信号。

下面说时钟:

时钟同步两个控制器可以同时在空闲总线上开始传输,并且必须有一种方法来决定哪一个控制总线并完成传输。这是通过时钟同步和仲裁完成的。

在单控制器系统中,不需要时钟同步和仲裁。时钟同步是使用I2C接口到SCL线的有线与连接来执行的。

这意味着SCL线上的HIGH到LOW转换导致相关控制器开始计数其LOW周期,一旦控制器时钟已变为LOW,它将SCL线保持在该状态,直到时钟达到HIGH状态(见图上)。

然而,如果另一个时钟仍在其LOW周期内,则该时钟的LOW到HIGH转换可能不会改变SCL线的状态。因此,SCL线由具有最长低电平周期的控制器保持低电平。低周期较短的控制器在此期间进入高等待状态。

这个是我没有看到过的东西,就是两个时钟信号对协议信号的影响,不过就记住我上面的黑色部分就好。

当所有相关的控制器都计算出它们的LOW周期时,时钟线被释放并变为HIGH。然后,控制器时钟和SCL线的状态之间没有区别,并且所有控制器开始计数它们的HIGH周期。第一个完成其HIGH周期的控制器再次将SCL线拉至LOW。这样,就会生成一个同步的SCL时钟,其LOW周期由时钟LOW周期最长的控制器决定,HIGH周期由时钟HIGH周期最短的控制器决定。

一个IIC的信号周期的长短由两个MCU时钟信号来决定。

这里的多传感器数据冲突我就不讲了,目前好像还没有用到。

接下来说数据传输,和上面有点一样:

数据传输遵循图上所示的格式,第二个字节有看头

这个是MSB先行

在START条件(S)之后,发送一个目标地址。这个地址有7位长,后面跟着第8位数据方向位(R/W)——“0”表示传输(WRITE),“1”表示数据请求(READ)

由控制器产生的停止条件(P)。但是,如果控制器仍然希望在总线上进行通信,它可以生成重复的START条件(Sr),并在不首先生成STOP条件的情况下处理另一个目标。在这样的传输中,读/写格式的各种组合是可能的。

接了个电话,思路都没有了,扑街。。。

可能的数据传输格式有:

a,其实是A上面有一个横杠,就是不响应的意思,下面丢失了。产生这个信号以后,主机发出了停止信号。

控制器-发射机发送到目标-接收机。传输方向没有改变。目标接收方确认每个字节。

叨叨两句吧,就是主机一直发数据,传感器就应答收到了,像极了被骂的的我,是是是,对对对。

控制器在第一个字节之后立即读取目标。在第一次确认的时刻,控制-发送者成为控制-接收者,目标-接收者成为目标-发送者。这个第一个确认仍然由目标生成。控制器生成后续确认。STOP条件由控制器生成,控制器在STOP条件之前发送一个不确认(a)。

这个呢就是读取传感器的值,疯狂的拿,必要时候会说,拿到了。

组合格式。在传输过程中改变方向时,START条件和目标地址都是重复的,但是R/W位颠倒了。如果控制器-接收器发送一个重复的START条件,它在重复的START条件之前发送一个nottacknowledge (a)。

复合格式:传输改变方向的时侯,起始条件和从机地址都会被重复 但 R/ W 位取反,如果主机接收器发送一个重复起始条件,它之前应该发送了一个不响应信号 A。相当于是没搭理,信号断了,传感器主动的找MCU。复合格式可以用于例如控制一个串行存储器在第一个数据字节期间 要写内部存储器的位置在重复起始条件和从机地址后数据可被传输。

注:1. 例如,可以使用组合格式来控制串行存储器。必须在写入第一个数据字节期间写入内部存储器位置。重复START条件和目标地址后,即可传输数据。

2. 所有关于先前访问的内存位置的自动递增或递减的决定,等等,都是由设备的设计者做出的。

3. 每个字节后面跟着一个确认位,由序列中的A或A块表示。

4. pc总线兼容设备必须在接收到START或重复START条件时重置其总线逻辑,以便它们都预期目标的发送地址,即使这些START条件没有按照正确的格式定位。

5. START条件紧跟着STOP条件(无效消息)是一种非法格式。然而,许多设备被设计为在这种条件下正常运行。

6. 连接到总线的每个设备都可以通过唯一的地址寻址。通常存在一个简单的控制器/目标关系,但也可能有多个相同的目标可以同时接收和响应,例如在组广播中。

说说寻址:I2C总线的寻址过程是通常在起始条件后的第一个字节决定了主机选择哪一个从机例外的情况是可以寻址所有器件的广播呼叫地址使用这个地址时 理论上所有器件都会发出一个响应但是也可以使器件忽略这个地址广播呼叫地址的第二个字节定义了要采取的行动。

总有人不回答,妈的。

从机地址由一个固定和一个可编程的部分构成由于很可能在一个系统中有几个同样的器件从机地址的可编程部分使最大数量的这些器件可以连接到I2C总线上器件可编程地址位的数量由它可使用的管脚决定

例如:如果器件有 4 个固定的和 3 个可编程的地址位那么相同的总线上共可以连接8个相同的器件。

原来这些都是找过飞利浦买的

总结了I2C总线系统特性的规范要求,包括了强制和可选部分 Table 2 i2c总线协议特性的要求 M = 强制; O = 可选; n/a = 不适用

听累没有?估计没有几个看到这里的。

来看一个真实的协议信号

IIC的输入输出结构采用的是开漏的结构。开漏结构不能够自主得到高电平,所以需要通过外部上拉电阻Rp来的实现IIC通信过程中的高电平。Rp的大小取决于IIC不同模式时的灌电流大小。

下面两个图是描述IIC获得高低电平的情景。因为一条IIC总线上面可能会同时连接上多个设备,如果IIC使用的是推挽输出的话容易引起短路。

IIC设备可以通过控制N-MOS管的开关来控制输出信号的电平高低。当MOS管G极为低电平时MOS管截止IIC总线上面由于有上拉电阻的存在而为高电平;当MOS管G极为高电平时MOS管导通,IIC总线相当于直接接地为低电平。

IIC的输入是通过TTL肖特基触发器将数据传输到输入数据寄存器当中,再提供给处理器处理。

由于种类的设备都有可能连接到IIC总线上面,比如说CMOS、NMOS等,所以IIC的高电平和低电平的标准是不一定的。高电平和低电平的值分别为0.7VDD和0.3VDD。

IIC的总线连接可以接受多主机的模式,也就是说一条IIC总线上面可以有多个设备可以作为主机来使用,但是在一次数据的传输过程中只能有一个设备作为主机。一条IIC总线上面谁是主机取决于总线上面的时钟和数据信号由谁控制。

如果两个MCU同时发起开始信号时(都试图成为主机),这时候IIC的仲裁机制会发挥作用来判定谁成为主机。

IIC的仲裁机制得益于其开漏的输入输出结构。例如如图所示,当SCL线上挂载的多个设备,其中的MCU2的SCL输出低电平,那么这条IIC总线SCL就会被MCU2拉低,这也就是“与”的特性。

IIC上的仲裁主要是由两部分组成SCL时钟同步、SDA线仲裁。

如图所示CLK1和CLK2都是连接在一条SCL线上的设备同时产生的时钟信号,由于IIC总线存在“与”的特性,所以两个设备高电平相同的部分形成了SCL最终的时钟,也就是说同一条IIC总线上面的时钟都是相同的。

那突然就理解了上面文章里面的时钟是什么意思。

同样SDA仲裁也是基于“与”的特性。如图所示当两个设备同时发出开始信号想要传送数据时,在第一个和第二个周期内DATA1和DATA2的数据都是相同的,然后两者继续传送数据,当在第三个时钟周期时DATA2与SDA的数据不一致,这个时候设备2就会停止发送数据,转而启动接收模式。这样SDA的数据就会与DATA1的数据保持一致,并且设备2停止发送数据也不会影响SDA的数据。

所示是示波器采集的IIC信号,得到这一段IIC包含的信息,主机向地址为0XA0 的设备写入0X0C。

感谢梦源得文章,通了这次。

OKOK,看传感器吧,不想写了。

最大是400kHz

有中断脚

XSHUT是可以控制功耗的引脚

上电和启动顺序有两个选项可用于设备上电/启动。

选项1:XSHUT引脚连接并从主机控制。此选项有助于优化功耗,因为VL53LOX可以在不使用时完全断电,然后通过主机GPIO(使用XSHUT引脚)唤醒。

HW待机模式定义为AVDD存在且XSHUT处于低电平的时间段。

选项2:XSHUT引脚不受主机控制,通过上拉电阻连接到AVDD。如果XSHUT引脚不受控制,则上电顺序如图所示。在这种情况下,设备在FW启动后自动进入SW STANDBY,不进入HW STANDBY。

SW是待机时刻。

也是IIC的接口,看时序图吧,应该很好懂了

信息被封装在8位数据包(字节)中,后面总是跟着一个确认位,Ac表示VL53LOX确认,Am表示主确认(主机总线主)。

内部数据是在SCL上升沿采样SDA产生的。在SCL的高峰期,外部数据必须是稳定的。

例外情况是SDA下降或上升时的启动(S)或停止(P)条件,而SCL较高。消息包含一系列字节,前面是开始条件,后面是停止或重复开始(另一个开始条件,但没有前面的停止条件),然后是另一个消息。第一个字节包含设备地址(Ox52),还指定了数据方向。如果最低有效位很低(即Ox52),则消息是主向从机写。如果设置了Isb(即Ox53),则消息是从从机读取的主消息。

地址,MSB先行

写,Ac是传感器收到

当数据被从机接收时,它被一点一点地写入串行/并行寄存器。从服务器接收到每个数据字节后,将生成一个确认,然后将数据存储在当前索引寻址的内部寄存器中。

在读取消息期间,当前索引所寻址的寄存器的内容在设备地址字节后面的字节中读出。该寄存器的内容被并行加载到串行/并行寄存器中,并通过SCL的下降沿从设备中进行时钟输出。

在每个字节的末尾,在读和写消息序列中,接收设备(即,用于写的VL53LOX和用于读的主机)发出确认。

消息只能由总线主机在读取操作期间读取完整字节后,通过发出停止条件或通过负确认(即不将SDA线拉低)来终止。

该接口还支持自动增量索引。传输完第一个数据字节后,索引自动加1。因此,主服务器可以连续地向从服务器发送数据字节,直到从服务器无法提供确认或者主服务器以停止条件终止写通信。如果使用了自动增量特性,主机就不必发送地址索引来伴随数据字节。

顺序写入

顺序读

32bit寄存器实列

这个是比较奇怪的,API的文档不在数据手册里面。

写不动了。。。太多了。

代码语言:javascript复制
https://dreamsourcelab.cn/articles/i2c/
代码语言:javascript复制
https://github.com/liuyunli/UM10204-I2C-bus-specification-and-user-manual/blob/master/I2C 总线规范和使用说明.md
代码语言:javascript复制
https://sumcu.suda.edu.cn/_upload/article/files/74/e5/d4eb93de45808d71ad8aad542ede/a3cb5873-aaf4-4af0-9e5f-521793fbba46.pdf
代码语言:javascript复制
https://www.eet-china.com/mp/a155259.html
代码语言:javascript复制
https://www.nxp.com/docs/en/user-gue/UM10204.pdf
代码语言:javascript复制
https://zhuanlan.zhihu.com/p/503219395

0 人点赞