模拟I2C通讯之时序图整理

引言

       前面介绍了I2C通讯的概念、原理以及协议,然后在介绍了支持I2C协议的一款EEPROM芯片M24C02的相关知识后,接下来我们再来整理一下STM32使用I2C通讯与M24C02芯片进行数据传递所需要理解的一些操作时序图


一、I2C通讯协议相关时序

1、起始和停止信号

I2C通讯时进行数据传递前我们先会有一个起始信号,同时数据传递结束后会有一个停止信号。

       由上述时序图可知,一开始设备不会占用总线即总线空闲,默认高阻态,同时总线外边连上拉电阻接到电源,所以总线呈现高电平。此时我们想进行数据传递了,所以设备将会占用总线,此时在保证时钟线SCL为高电平情况下,使数据信号线SDA产生下降沿信号,也就是高电平向低电平跳变的信号,表示一个起始信号,意味着该设备要占用总线了。

       接着,中间就是数据传递的一些时序,传递结束后会产生一个停止信号表示结束,同理是时钟线SCL处于高电平的情况下,数据信号线SDA产生一个上升沿信号,即低电平向高电平跳变的信号,就表示停止信号,此时数据总线释放,又出现高阻态,输出1呈现高电平,这就意味着数据传递结束了。

通俗简单的理解记忆:

       开始数据传递相当于将跳进一个坑(下降沿),然后中间是数据传递产生的一些时序,最后数据传递结束后出坑(上升沿)。

2、数据的有效性

      知道数据传递的开始和结束,就要继续讨论中的数据传递,此时我们关注的就是数据传递的有效性,这里也会涉及到操作的时序图。

        传递数据时,首先我们要保持数据信号线上电平的稳定,同时时钟线必须是要处于高电平状态。只有当时钟线变成低电平状态时,数据线SDA上才能发生电平转换。换句话说,我们数据信号线SDA产生的数据信号,也就是传递过来的1或者0要先保持住,然后SCL线出现的时钟信号为高电平的时候SDA线上的电平要保持稳定,当时钟线SCL线上的电平从高电平跳变至低电平时,SDA线上才能去做电平信号的翻转。因此我们说数据信号线上信号的翻转必须要在SCL时钟信号是低电平的时候才能进行。

3、响应与非响应

接着是响应的时序操作图。

       I2C协议规定,当接收到一个数据之后需要有一个应答ACK,因为I2C通讯是一种单线半双工的通讯方式,所以为了保证数据传输的正确性,我们接受一个数据以后必须要有一个响应。

       由上图可知,我们主设备会控制时钟信号,另外的数据信号线上的信号就不一定是主设备了,要看我们数据收发的关系。

       首先,发送器控制数据线SDA,最初数据总线空闲保持高电平,然后发来一个信号使SDA线接收低电平信号发生跳变,表示数据总线被发送器占用而不在空闲,也就是一个起始信号。而此时接收器不用做什么,所以继续保持空闲的高阻态,即继续维持一个高电平状态,不会占用数据总线。

       接着,发送器就会开始发送数据,数据发送结束后,就会把数据总线拉高,表示数据发送结束的停止信号。此时发送器释放数据总线,将数据总线的使用权交给了接收器,这就是一种根据协议的规定去轮流占用和释放的感觉。

       然后,此时发送器释放了数据总线,如果接收器收到一字节数据,就会开始占用数据总线,然后直接对数据总线进行一个拉低的操作,也就意味着数据总线由空闲转变为占用了,此时数据总线的使用权就彻底相当于交给了接收器。

      最后,到下一个时钟周期高电平时,对数据总线上的信号做数据采样就会获取到一个低电平0,这就相当于接收方发出的的应答信号ACK;相反,如果这时候接收方没有接收到数据,然后没有占用数据总线,也就是数据总线仍然保持空闲的高电平的话,此时数据采用到的就会还是一个高电平1,就相当于接收方没有发出应答信号,这就是一个非应答的响应信号NACK了。

       此时大家可能可以想到,按照这种时序,我们进行软件模拟I2C通讯时,就是使用PB10、PB11去按照I2C协议规定输出特定电平就行。对GPIO做配置的话,首先肯定是配置时钟,然后配置工作模式时怎么配置呢?首先肯定是一种输出模式,因为配成输出模式时IDR寄存器仍然是可以进行读取的,所以配置成输出模式是没有问题的;然后这里会配置成开漏输出,因为I2C通讯用的总线的形式,然后外接上拉电阻再施加一个电源直接拉到高电平,而开漏输出对应的原理上就是两个mos管,其中PMOS关断、只有NMOS管正常工作,默认情况下时接地可以很好的输出低电平0;然后要输出1的话,关闭NMOS管时相当于一个悬空状态,此时呈现的是高阻态,所以我们外部会有一个上拉电阻接到电源拉到高电平就行了。这样就能很好的匹配我们这里I2C通讯进行的时序操作了。即总线空闲时,相当于关闭NMOS管,通过外接的上拉电阻拉到高电平;总线占用时,相当于NMOS管正常工作接地,直接置为低电平。

二、M24C02读写操作相关时序

1、写入一个字节时序

首先我们讨论写入一个字节的操作时序图

        如上图。首先涉及到一个M24C02芯片上的【WC】端口,前面讲过这是一个写保护引脚,低电平有效,即此时可以进行写操作。当然,我们板子上将这里直接接地,表示一直都可以对其进行写入操作了。

       其次,我们不管时钟,再来看【Byte Write】部分,这就是写入一个字节的核心操作时序。写入数据,首先要发出一起始信号start,然后就是传输一个字节的设备地址码,其中7位是设备地址,紧跟着一位读写方向位来表示发出的读写信号。这里是写入,所以读写信号是给的一个低电平,然后我们传递一个字节过去了,由于这是主设备向从设备发送,所以此时从设备要给一个低电平的应答反馈给主设备,表示接收到了。

        接着,主设备就会继续发送第二个字节。第二个字节传输的就是写入的数据所存放的内部地址,相当于我们既然要写入数据,就一定要先指明存放数据的地址。传输一个字节的内部地址后,同理从机给主机STM32一个低电平应答反馈,然后继续接着就是传递一个字节的实打实的数据【Data in】了,最后一样要有一个低电平的应答信号ACK。

       值得注意的是,作写入操作的时候,正常情况下每一次写入周期都是5ms,也就是说我们每次写入后要经过5ms后才能做其他事情。

       因为此时我们就写入一个字节的数据,所以接下来就直接发出停止信号Stop,即数据总线电平拉高,产生一个上升沿信号即可。

       这就是完整的主机向M24C02芯片写入一个字节的数据的完整过程。当然需要注意的是,写入一个字节的数据不表示这个过程只传输一个字节的数据,根据这个时序操作我们显然可以发现,除了传输真的一字节数据前还需要传递设备地址以及内部地址等东西。

       所以,I2C通讯时,其底层的硬件简单、线也少,同时底层需要的硬件电路的支持也少,但是其协议相对复杂,加之其是单线半双工,所以显然其传输速率也上不去,因此I2C通讯也是一种低速的通讯方式,好在其比较简单稳定。

2、读取一个字节时序

接着看看读取一个字节的操作时序,读取的话会相对特殊一些。

       首先,一样是先发出Start信号,然后开始传输一个设备地址码,然后需要注意的是这里给的读写方向位。我们思考,要读取,就首先我们需要知道对应的数据地址,但是目前我们并不知道,所以直接给读取信号的话,他就不知道之后应该从哪个地址开始读取数据了。所以实际上在E2PROM中进行随机地址的读取时,里面会有一个缓冲器,也叫地址计数器,他会直接指向当前所在的内部地址,然后每当我读取一次,这个计数器就会像指针一样移动一次。当然,这样的话实现起来就会和正常能想到的不太一样了。

       因此,这里读取一个字节的方式实际上是采取了一种“假写真读”的方式进行:即先写入、在读取。

        如上图时序,首先进行“假写”发出起始信号,然后传输设备地址码并且所带的读写方向位置于低电平的写入,然后传进去一个字节地址,但是此时我们不再传递后面的数据,表示这是一个假写入,目的是让EEPROM中进行随机地址读取时的地址计数器指向当前这个字节地址,本质上就相当于是将内部地址给到地址计数器方便进行读取。

       接着,从设备应答ACK响应后,我们再开始“真读”:所以发出起始信号,然后传递设备地址码,此时的读写方向位置高电平即读取,这时候数据总线的占用权就交给从设备,从设备应答响应后,就会开始从地址计数器指向的内部地址开始读取数据到【Data out】了。

       最后,由于此时是从设备读取后主设备要接收,因此当从设备读取结束后主设备理应给一个响应表示收到了,然后又由于此时只是读取一个字节的数据,所以此时的响应应该是主设备表示“我接受完了,不用再发了”,这就是区别于前面应答响应的另一种响应方式——非应答响应NACK了。所以这里主设备就会给从设备一个高电平不应答的反馈,然后主设备给Stop停止信号就可以了。

       换句话说,非应答响应就相当于主设备将收回数据总线的占有权。因为主设备收到后不应答,此时从设备就不在读取数据给主设备,那么这时候数据总线就会空闲下来而不再被从设备占用,此时主设备就会开始占用数据总线发出一个停止信号来结束读取数据的操作了。

3、写入多字节时序

写入多字节操作与写入单字节时序类似操作。但值得注意的是:

       一次性写入多个字节,也叫页写入(Page Write)。AT24C02每页只有16个字节,每次只能写入单独的一个页中,所以一次性最多只能写入16个字节。当一次性写入超过16个字节的时候,则超过的部分会重新从这页的首地址重新写入。(就相当于多出的字节会从该页最前面开始继续覆盖写入,导致之前的数据被覆盖)

       首先也是发出起始信号,然后传递设备地址码开始写入,然后从设备收到后给出应答。接着主设备继续传递字节地址,然后从设备再应答。最后就是主设备不断写入字节,同时从设备一直应答,直到应答后主设备发出停止信号才会结束。

        可见,对于写入多字节操作时,我们编写代码可以直接借助循环语句即可实现。值得注意的是,在进行多字节写入的时序操作时其实不会限制写入字节长度,但是EEPROM中进行页写入时会对每一页写入的字节数进行一定的限制,故我们在编写程序时需要注意一下。

4、读取多字节时序

       这里读取多字节时序和前面读取单字节时序也很类似。不过这里读出多个字节的时候没有限制,可以读出任意多个。

       首先也是先进行假写操作,主设备先发出起始信号,然后传递设备地址码,读写方向位置低电平写入,从设备应答后传递内部地址使地址计数器指向该地址,从设备继续发出应答。接着进行真读,主设备发出起始信号然后传递设备地址码,附带的高电平读取信号,从设备应答后,数据总线使用权交给从设备,从设备就开始从计数器指向的地址开始进行数据的读取。由于此时要进行多字节读取,所以主设备一直进行应答响应,使从设备持续读取数据给到主设备,直到主设备给出非应答响应NACK,从设备才停止读取数据。最后从设备释放总线,主设备占用数据总线发出停止信号结束多字节数据的读取操作。

三、M24C02手册中的读写操作描述

        上面已经将后面软件模拟I2C案例可能进行的时序操作介绍完毕,现在我们再简单介绍以下M24C02芯片手册中提供的读写操作描述。下面图片来自M24C02-w芯片手册

        这里,大家自己看看手册中的介绍就行。它的写入操作相对比较简单,这里稍微说说其读操作的描述。上图可以发现,这里其实关于读操作是分了三类,分别是【随机地址读取】、【当前地址读取】、【连续读取】。

1、【随机地址读取】:就是进行假写真读操作,通过假写让地址计数器指向指定的内部地址,然后去进行读操作。

2、【当前地址读取】:直接进行读取操作,地址计数器会直接从当前所指向的地址开始进行读操作。

3、【连续读取】:这里细分成【连续随机地址读取】和【连续当前地址读取】。就是通过两种方式去连续进行读取多个字节数据的操作。


以上便是本次文章的所有内容,欢迎各位朋友在评论区讨论,本人也是一名正在学习的小白,愿大家共同努力,一起进步吧!

鉴于笔者能力有限,难免出现一些纰漏和不足,望大家在评论区批评指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值