IIC通信过程时序全面分析

IIC通信过程时序全面分析

IIC通信全过程分析+代码

IIC介绍IIC基本规则启动信号停止信号发送数据接收数据发送应答信号接收应答信号代码总结提醒事项!!!与IIC相关的错误

IIC介绍

IIC是一种半双工、同步通信协议,一般用于单主机与多从机之间的通讯。IIC有两条通讯线路,一条是SCL,即时钟信号线,另一条是SDA,即数据信号线。主机与从机之间通过SCL与SDA之间产生的组合变化时序,分析出当前主机或从机想要做的动作,从而进行接下来的相应的操作。 注意:不论是对于主机还是从机而言,这个分析信号变化的过程不需要我们来做,在IIC通信中的硬件其内部有对应的硬件电路来自动实现分析时序的功能,而对于我们程序员而言,我们需要做的只是模拟时序的产生,从而实现想要的动作。

上面这段话对于接下来理解以及实现IIC通信的全过程至关重要!!!现在如果还没办法理解的话就先接着往下看。

下图是一个24C02芯片,是一个使用IIC通信的经典芯片,WE引脚是写使能,默认使能,不需要管,其中需要使用到的只有SCL与SDA对应的引脚。

众所周知,IIC主要实现的信号动作有六个,分别是:启动信号、停止信号、向总线发送数据、从总线接收数据、向从设备发送应答信号、等待接收从设备的应答信号。 接下来一一介绍这些信号所对应的时序。

IIC基本规则

在介绍具体信号时序前,我们要先说明几个IIC中最基本也是最重要的几个规则。

第一个规则就是SCL为高电平期间,SDA的电平不能发生改变!(启动和停止信号除外) 第二个规则就是在没有进行操作的时候,必须保持SCL为低电平,SDA为高电平状态

其中第一条规则是由于IIC自身的通信协议所规定的,不需要做额外的说明,但是第二条是我自己总结的,或者说是我自己创造的一条规则,可以让你很好地在不知道SCL和SDA到底该为何状态时做出判断。上面两条同样如果你只是初学IIC,那么可能看起来不是很好理解,那么这里还是暂时有个印象即可,后边讲完之后你应该就懂了。

启动信号

关键:SCL高电平期间,SDA由高到低 启动信号十分简单,就是在SCL为高电平期间,SDA由高到低变化,即可向总线上的从设备发出启动信号。这里具体的操作顺序是这样的:

拉低SCL拉高SDA拉高SCL拉低SDA延迟一段时间拉低SCL拉高SDA

前两个步骤是为了使两条信号线保持合法状态,因为SCL为高电平期间不可随意对SDA进行操作,不然可能会误触发起始或停止信号。最后两个步骤同样是为了使两条信号线保持合法状态,这里的合法状态就是前面提到的第二个规则。注意,以上SCL和SDA的变化顺序必须严格执行,任何一个小错误都可能导致IIC中的时序不对从而导致错误的结果。

停止信号

关键:SCL为高电平期间,SDA由低到高 停止信号与启动信号正好相反,具体操作顺序如下:

拉低SCL拉低SDA拉高SCL拉高SDA延迟一段时间拉低SCL

发送数据

发送数据分为两种情况,发送0和发送1,其区别主要就是SDA状态的不同,发送0,SDA则为低电平,发送1,SDA则为高电平,发送0的具体操作顺序如下(发送1位):

拉低SCL拉低SDA拉高SCL延迟一段时间拉低SCL拉高SDA

发送1的具体操作顺序如下(发送1位):

拉低SCL拉低SDA拉高SDA拉高SCL延迟一段时间拉低SCL

一般情况下我们都是一次发送一个字节,8位,因此在程序中我们不是严格按照上面的顺序写代码的,而是采用循环的方式发送。

接收数据

接收数据同样分为接收数据0和1,起始从下面的图和上面的图可以看到,他们俩是一样的,但是和上面不太一样的地方是,因为我们是要接收数据而不是发送数据,所以,现在我们不能操作SDA数据线,只需要操作SCL信号线即可。 接收1位数据时的具体操作顺序如下:

拉低SCL拉高SCL延迟一段时间检测SDA的状态,如果SDA此时为低电平,则接收为0,否则接收为1拉低SCL

在读出8位数据之后,我们同样要使SCL和SDA恢复为合法状态,因为前面的操作中已经把SCL拉低了,因此最后只需要将SDA拉高即可。

发送应答信号

首先需要解释一下什么是应答信号,在IIC中,要求是这样的,除了开始和结束信号,设备不需要应答,其余所所有操作均需要从设备应答,表示我已经受到你发送的数据信号了。这里的从设备不一定是非主机,也可能主机也在某次通信中作为从设备出现,此时就需要主机进行应答了。具体在什么时候产生应答信号呢?也就是每次信号产生后,就会发生应答。对于应答,分为两种类型,应答0或应答1,这里应答0是有效应答,应答1是无效应答,为什么这里应答0是有效应答,而应答1是无效应答呢?因为在IIC总线中,SCL和SDA线路都是接上拉电阻了的,因此默认状态就是高电平,也就是说,如果从设备什么都不做,此时数据线的状态就是高电平,而如果从设备将数据线拉低,则说明从设备是存在的,所以这里应答0是有效应答。 我们接着来看怎么产生有效应答(应答0)与无效应答(应答1). 应答0的具体操作顺序如下:

拉低SCL拉低SDA拉高SCL延迟一段时间拉低SCL拉高SDA

应答1的具体操作顺序如下:

拉低SCL拉高SDA拉高SCL延迟一段时间拉低SCL

但是无效应答没什么作用,我们一般不使用无效应答,所以在代码中我们只实现有效应答0;

接收应答信号

作为主机,我们不仅需要产生应答,还需要接收判断从机是否应答,同样的,接收应答也分为接收应答0和接收应答1,由于是作为接收端,因此我们不需要操作SDA线。 接收应答的具体操作顺序如下:

拉低SCL拉高SDA拉高SCL延迟一段时间检测此时SDA的状态,如果是低电平,则从机应答,否则从机未应答拉低SCL拉高SDA

代码

IIC的具体代码如下

#include

#define IIC_TIME 1

// 根据你的板子进行选择下面的两个引脚

sbit SCL=P2^1;

sbit SDA=P2^0;

// 所有阶段结束时保持SCL低电平 SDA高电平

void IIC_Start()

{

SCL=0;

SDA=1;

SCL=1;

SDA=0;

Delay(IIC_TIME);

SCL=0;

SDA=1;

}

void IIC_Stop()

{

SCL=0;

SDA=0;

SCL=1;

SDA=1;

Delay(IIC_TIME);

SCL=0;

}

void IIC_Ack()

{

SCL=0;

SDA=0;

SCL=1;

Delay(IIC_TIME);

SCL=0;

SDA=1;

}

unsigned char IIC_WaitAck()

{

unsigned char ack;

SCL=0;

SDA=1;

SCL=1;

Delay(IIC_TIME);

if(SDA)

ack=1;

else

ack=0;

SCL=0;

SDA=1;

return ack;

}

void IIC_WriteByte(unsigned char Byte)

{

unsigned char i;

for(i=0;i<8;i++)

{

SCL=0;

if(Byte&(0x80>>i))

SDA=1;

else

SDA=0;

SCL=1;

Delay(IIC_TIME);

}

SCL=0;

SDA=1;

}

unsigned char IIC_ReadByte()

{

unsigned char Byte=0x00,i;

for(i=0;i<8;i++)

{

SCL=0;

//Delay(IIC_TIME); 视情况添加该行 建议添加该行

SCL=1;

Delay(IIC_TIME);

if(SDA)

Byte|=(0x80>>i);

}

SCL=0;

SDA=1;

return Byte;

}

你可以自己尝试使用上面的函数去实现24C02的数据读取和写入的具体过程!!!

总结

IIC协议的应用十分广泛,学习好掌握IIC通信协议是在学习单片机的路上必须掌握的基本技能,相信你在仔细阅读完本篇文章后,能够对IIC的通信原理及过程的掌握更上一个台阶!如果还有什么疑问,欢迎在评论区留言~

提醒事项!!!与IIC相关的错误

1.AT24C02相关问题 博主在使用IIC对AT24C02芯片进行测试的过程中发现,有些板子对于上述代码可能无法读取数据,例如博主使用的其中一块板子STC8A8K64S4A12,读出的数据全都是第一位的数据,例如在0x00处存储的0xAA数据,读取时读到的都是第一位的1,经过测试发现,出现这一问题的原因在于读取数据时序中,SCL=0;到SCL=1;这一过程可能执行太快了,导致AT24C02没有有效接收到SCL的时序,因此需要在这两行代码之间增加一段延时,即可正确读取。 但是上述问题对于另一块板子却并没有出现(STC89C52RC),因此具体是否添加延时可以看你的实际情况。不过建议的是将这一段延时加上。并且吸取这个经验,我们同样可以在IIC_WriteByte()中的SCL时序变化之间添加一个延时,防止出现同样类似的问题。具体可以参考蓝桥杯官方的iic代码,他所给的代码中在读写操作的时候,每一次对SCL变化时都进行了延时。 2.PCF8591相关问题 在直接使用蓝桥杯官方给出的代码,使用PCF进行AD转换时发现,数据始终不正确!!!找了半天问题也没找到在哪儿,最后忽然猜测会不会是延时太短导致的?因此增加了蓝桥杯官方所给代码的延时,修改后如下,然后就发现ADC转换没有问题了!!!

#define DELAY_TIME 50

其实通过上面两个问题,可以总结出,有时候IIC相关的问题并不一定就是时序的问题,还很有可能是延时的问题,这个结论应该同样适用于SPI等其他通信协议。 3.IIC应答0还是1相关问题 在使用IIC_SendAck(ack);函数时,一定不要随意设置ack的值,首先ack只能为0或者1,即对应SDA的低电平和高电平,其中ack=0表示应答信号,ack=1表示非应答信号,这里ack应该设为1的时候一定不能设为0,否则会导致IIC设备时许发生错乱,从而导致下一次读取出来的数据发生混乱!!!具体来说,比如在AT24C02的读字节函数中,最后需要IIC_SendAck(ack);此时这里的ack应该等一1,而不能是0,否则下一次读取出来的数据将会有问题!!!

相关推荐

爬行动物
bst365老牌体育

爬行动物

📅 08-03 👁️ 2563
C 语言实例 - 将字符串写入文件
365bet官网网投

C 语言实例 - 将字符串写入文件

📅 10-24 👁️ 8323
适合边上班边考公务员5大职业推荐!
365bet官网网投

适合边上班边考公务员5大职业推荐!

📅 08-29 👁️ 8807