IIC原理超详细讲解---值得一看

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

   SCL=1; //首先把时钟线拉高

   delay\_us(4);//延时函数

   SDA=1; //在SCL为高的情况下把SDA拉高

   delay\_us(4); //延时函数

}


#### 开始信号:


**SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。**


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104124610.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


代码表示:



//产生IIC起始信号
//1.先拉高SDA,再拉高SCL,空闲状态
//2.拉低SDA
void IIC_Start() //启动信号

{
SDA=1; //确保SDA线为高电平
delay_us(5);
SCL=1; //确保SCL高电平
delay_us(5);
SDA=0; //在SCL为高时拉低SDA线,即为起始信号
delay_us(5);
SCL=0; //钳住I2C总线,准备发送或接收数据

}


#### 停止信号


**停止信号:SCL保持高电平。SDA由低电平变为高电平。**


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407161528542.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)



//产生IIC停止信号
//1.先拉低SDA,再拉低SCL
//2.拉高SCL
//3.拉高SDA
//4.停止接收数据
void IIC_Stop(void)
{

IIC_SCL=0;
IIC_SDA=0;    //STOP:当SCL高时,数据由低变高
delay\_us(4);
IIC_SCL=1; 
IIC_SDA=1;    //发送I2C总线结束信号
delay\_us(4);							   	

}


在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104137162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


#### 数据有效性


**IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。**


**SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。**


也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407162837546.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


![img](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWFnZXMwLmNuYmxvZ3MuY29tL2Jsb2cvNTg0Mjk3LzIwMTUwMS8xMDE0MzQ1Mjc1MDc1MTUucG5n?x-oss-process=image/format,png)


#### 应答信号


每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,


**应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答**


* **应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;**
* **应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。**


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200407171913110.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


\*\*每发送一个字节(8个bit)\*\*在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。


**应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,**


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104200168.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)



//主机产生应答信号ACK
//1.先拉低SCL,再拉低SDA
//2.拉高SCL
//3.拉低SCL## 标题
void I2C_Ack(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA数据可以发生改变
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}

//主机不产生应答信号NACK
//1.先拉低SCL,再拉高SDA
//2.拉高SCL
//3.拉低SCL
void I2C_NAck(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA数据可以发生改变
IIC_SDA=1; //拉高SDA,不产生应答信号
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}


等待应答信号:



//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
char IIC_Wait_Ack(void)
{
u8 ucErrTime=0;

IIC_SDA=1;delay\_us(1);	   
IIC_SCL=1;delay\_us(1);	 
while(IIC_SDA)
{
	ucErrTime++;
	if(ucErrTime>250)
	{
		IIC\_Stop();
		return 1;
	}
}
IIC_SCL=0;//时钟输出0 
return 0;  

}


#### IIC数据传送


#### 数据传送格式


**SDA线上的数据在SCL时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。**


**当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成** ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。


![img](https://imgconvert.csdnimg.cn/aHR0cDovL3d3dy5lbWJlZGRlZGxpbnV4Lm9yZy5jbi91cGxvYWRzL2FsbGltZy8xMzAzMTcvMTIxOTQ1Mi5wbmc?x-oss-process=image/format,png)


**IIC写数据:**


![img](https://imgconvert.csdnimg.cn/aHR0cDovL3d3dy5lbWJlZGRlZGxpbnV4Lm9yZy5jbi91cGxvYWRzL2FsbGltZy8xMzAzMTcvMTIxOTQ1My5wbmc?x-oss-process=image/format,png)


多数从设备的地址为7位或者10位,一般都用七位。  
 **八位设备地址=7位从机地址+读/写地址,**


再给地址添加一个方向位位用来表示接下来数据传输的方向,


* 0表示主设备向从设备(write)写数据,
* 1表示主设备向从设备(read)读数据


IIC的每一帧数据由9bit组成,


如果是**发送数据**,则包含 **8bit数据+1bit ACK,**


如果是**设备地址数据**,则**8bit包含7bit设备地址 1bit方向**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411151616581.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)



> 
> **在起始信号后必须传送一个从机的地址(7位) 1~7位为7位接收器件地址,第8位为读写位,用“0”表示主机发送数据(W),“1”表示主机接收数据 (R), 第9位为ACK应答位,紧接着的为第一个数据字节,然后是一位应答位,后面继续第2个数据字节。**
> 
> 
> 


**IIC发送一个字节数据:**



//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答

//IIC_SCL=0;
//在SCL上升沿时准备好数据,进行传送数据时,拉高拉低SDA,因为传输一个字节,一个SCL脉冲里传输一个位。
//数据传输过程中,数据传输保持稳定(在SCL高电平期间,SDA一直保持稳定,没有跳变)
//只有当SCL被拉低后,SDA才能被改变
//总结:在SCL为高电平期间,发送数据,发送8次数据,数据为1,SDA被拉高,数据为0,SDA被拉低。
//传输期间保持传输稳定,所以数据线仅可以在时钟SCL为低电平时改变。
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后数据左移一位
//如果某位为1,则SDA为1,否则相反
if(txd&0x80)
IIC_SDA=1;
else
IIC_SDA=0;
txd<<=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
或者:
//IIC_SDA=txd&0x80; //获取最高位
//获取数据的最高位,然后右移7位,假设为 1000 0000 右移7位为 0000 0001
// 假设为 0000 0000 右移7位为 0000 0000
//如果某位为1,则SDA为1,否则相反
IIC_SDA=((txd&0x80)>>7);
txd<<=1;


**IIC读取一个字节数据:**



//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN(); //SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck(); //发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}


#### IIC发送数据


![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411104227304.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411160446820.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


**Start**: IIC开始信号,表示开始传输。  
 **DEVICE\_ADDRESS:**: 从设备地址,就是7位从机地址  
 **R/W**: W(write)为写,R(read)为读  
 **ACK**: 应答信号  
 **WORD\_ADDRESS** : 从机中对应的寄存器地址 比方说访问 OLED中的 某个寄存器  
 **DATA**: **发送的数据**  
 **STOP**: 停止信号。结束IIC


主机要向从机写数据时:



> 
> 1. **主机首先产生START信号**
> 2. **然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方 向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)**
> 3. **主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器**
> 4. **这时候主机等待从机的应答信号(A)**
> 5. **当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号**
> 6. **当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,**
> 7. **主机产生停止信号,结束传送过程。**
> 
> 
> 


#### IIC读数据:


![在这里插入图片描述](https://img-blog.csdnimg.cn/2020041116021182.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)  
 主机要从从机读数据时



> 
> 1. **主机首先产生START信号**
> 2. **然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令,**
> 3. **这时候主机等待从机的应答信号(ACK)**
> 4. **当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号,**
> 5. **当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设 置成接收模式开始读取数据,**
> 6. **这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据**
> 7. **主机进而产生停止信号,结束传送过程。**
> 
> 
> 


#### 以AT24C02为例子


24C02是一个2K Bit的串行EEPROM存储器(掉电不丢失),内部含有256个字节。在24C02里面有一个8字节的页写缓冲器。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411233728215.png)  
 A0,A1,A2:硬件地址引脚  
 WP:写保护引脚,接高电平只读,接地允许读和写  
 SCL和SDA:IIC总线  
 可


以看出对于不同大小的24Cxx,具有不同的从器件地址。由于24C02为2k容量,也就是说只需要参考图中第一行的内容:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020041116204029.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)  
 芯片的寻址:  
 AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。A2~A0为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。


也就是说如果是  
 **写24C02的时候**,**从器件地址为10100000(0xA0);  
 读24C02的时候,从器件地址为10100001(0xA1)。**


片内地址寻址:


**芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。**


对应的修改 A2A1A0 三位数据即可  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411161834991.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)


**向AT24C02中写数据**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200411233850496.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)  
 操作时序:



> 
> 1. **MCU先发送一个开始信号(START)启动总线**


![img](https://img-blog.csdnimg.cn/img_convert/1b3601737262e735cce89d17b584264d.png)
![img](https://img-blog.csdnimg.cn/img_convert/66361579d2acfc97ca5528db6fc3898a.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

TM3,size_16,color_FFFFFF,t_70)  
 操作时序:



> 
> 1. **MCU先发送一个开始信号(START)启动总线**


[外链图片转存中...(img-48Msk9nM-1715883674579)]
[外链图片转存中...(img-d72Yol70-1715883674580)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值