【接口协议】04.IIC

【嵌入式八股】一、语言篇https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM

【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym

【嵌入式八股】三、硬件篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM

【嵌入式八股】四、嵌入式Linux篇https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0

IIC

IIC 基础

IIC协议简介—学习笔记_iic标准协议_越吃越胖的黄的博客-CSDN博客

简介

I2C(Inter-Integrated Circuit)是一种串行、同步、半双工通信协议,带应答机制,支持一主多从、多主多从,用于连接微控制器、传感器、存储器和其他外设。

硬件连接

要能手撕出来

I2C使用两条线(SDA和SCL)进行通信,可以连接多个设备,每个设备都有一个唯一的地址。I2C总线上的设备可以充当主设备或从设备。主设备负责发起通信,从设备负责响应通信请求。

alt

仲裁:SDA线的仲裁也是建立在总线具有线“与”逻辑功能(线与逻辑,即两个以上的输出端直接互连就可以实现“AND”的逻辑功能。两个一出一,一个一出零、没有一出零)的原理上的。节点在发送1位数据后,比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,进行比较,输出低电平进行发送,输出高电平退出。SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线。

时序

要能手撕出来

时序总结:

alt

总线空闲状态 SCL和SDA均为高电平,接上拉电阻。
起始信号(START) 在SCL保持高电平期间,SDA由高电平被拉低。由主控器发出。
数据位传送(DATA) 在SCL保持高电平期间,SDA上的电平保持稳定,低电平为数据0、高电平为数据1。用法:主控器和被控器都可发出。
应答信号(ACK) 在SCL保持高电平期间,SDA保持低电平。IIC总线上所有数据都是以8位字节传送的,发送器每发送一个字节,就在第9个时钟脉冲期间释放SDA(高电平),由接收器反馈一个ACK。
非应答信号(NACK) 在SCL保持高电平期间,SDA保持高电平。如果接收器是主控器,则它在收到最后一个字节后,发送一个NACK,通知被控器结束数据发送,并释放SDA(高电平),以便主控器发送一个STOP。
停止信号(STOP) 在SCL保持高电平时间,SDA由低电平被释放(拉高)。由主控器发出。

各时序部分的代码(要能手撕出来):

起始信号

void IIC_Start(void)
{
	SDA_H;						//拉高SDA线
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);		//延时,速度控制
	
	SDA_L;						//当SCL线为高时,SDA线一个下降沿代表开始信号
	DelayUs(iicInfo.speed);		//延时,速度控制
	SCL_L;						//钳住SCL线,以便发送数据
}  

停止信号

void IIC_Stop(void)
{
	SDA_L;						//拉低SDA线
	SCL_L;						//拉低SCL先
	DelayUs(iicInfo.speed);		//延时,速度控制
	
	SCL_H;						//拉高SCL线
	SDA_H;						//拉高SDA线,当SCL线为高时,SDA线一个上升沿代表停止信号
	DelayUs(iicInfo.speed);
}

应答信号

//产生ACK应答,读取从机一字节数据后还要接着读的时候使用
//SCL在SDA一直为低电平期间完成低高电平转换
void IIC_Ack(void)
{	
	SCL_L;						//拉低SCL线
	SDA_L;						//拉低SDA线<----
	DelayUs(iicInfo.speed);
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);
	SCL_L;						//拉低SCL线
}
//不产生ACK应答,读取从机一字节数据后不读了的时候使用    
//SCL在SDA一直为高电平期间完成低高电平转换
void IIC_NAck(void)
{
	SCL_L;						//拉低SCL线
	SDA_H;						//拉高SDA线<----
	DelayUs(iicInfo.speed);
	SCL_H;						//拉高SCL线
	DelayUs(iicInfo.speed);
	SCL_L;						//拉低SCL线
}
//等待ACK应答    
//发送完一个字节后(释放SDA)的下一个时钟高电平时期,读取SDA电平,0为收到应答
_Bool IIC_WaitAck(unsigned int timeOut)
{
	SDA_H;DelayUs(iicInfo.speed);			//拉高SDA线
	SCL_H;DelayUs(iicInfo.speed);			//拉高SCL线
	
	while(SDA_R)							//如果读到SDA线为1,则等待。应答信号应是0
	{
		if(--timeOut)
		{
			printf("WaitAck TimeOut\r\n");
			IIC_Stop();						//超时未收到应答,则停止总线			
			return IIC_Err;					//返回失败
		}		
		DelayUs(iicInfo.speed);
	}	
	SCL_L;									//拉低SCL线,以便继续收发数据	
	return IIC_OK;							//返回成功	
}

发送数据

void IIC_Send(unsigned char byte)
{
	unsigned char count = 0;
	
    SCL_L;							//拉低时钟开始数据传输	
    for(; count < 8; count++)		//循环8次,每次发送一个bit
    {
		if(byte & 0x80)				//【先发送最高位,大端传输】
			SDA_H;
		else
			SDA_L;
		
		byte <<= 1;					//byte左移1位
		
		DelayUs(iicInfo.speed);
		SCL_H;
		DelayUs(iicInfo.speed);
		SCL_L;
    }
}   

接收数据

unsigned char IIC_Read(void)
{	
	unsigned char count = 0, receive = 0;	
	SDA_H;						//拉高SDA线,开漏状态下,需线拉高以便读取数据
	
    for(; count < 8; count++ )	//循环8次,每次发送一个bit
	{
		SCL_L;                  //拉低,从机放数据
		DelayUs(iicInfo.speed);
		SCL_H;                  //拉高,主机读数据
		
        receive <<= 1;			//左移一位	
        if(SDA_R)				//如果SDA线为1,则receive变量自增,每次自增都是对bit0的+1,然后下一次循环会先左移一次
			receive++;		
		DelayUs(iicInfo.speed);
    }	
    return receive;	
}

代码

要能手撕软件模拟IIC通讯代码

一、写数据

字节写

alt

void IIC_SEND_BYTE(u8 slaveaddr,u8 registeraddr,u8 byte);//发送到具体从机地址及相关寄存器一个字节
{
	IIC_Start();           //通讯开始
	IIC_Send(slaveaddr);   //先发送从机的地址,寻址从机
	IIC_WaitAck();         //得到回应,说明,电路中有这个外设器件
	IIC_Send(registeraddr);//寻址这个器件中的相关寄存器
	IIC_WaitAck();         //得到回应,说明这个寄存器存在
	IIC_Send(byte);        //发送一个字节
	IIC_WaitAck();         //等待回应
}

页写

alt

指定设备+指定地址+指定数据

void IIC_SEND_BYTES(u8 slaveaddr,u8 registeraddr,u8 *pbuffer,u16 num );//发送一串数据给具体从机的相关寄存器
{
	IIC_Start();             //开始通讯
	IIC_Send(slaveaddr);     //寻址从机
	IIC_WaitAck();           //等待回应
	IIC_Send(registeraddr);  //寻址寄存器
	IIC_WaitAck();           //等待回应

	for(t=0;t<num;t++)       //发送数组中的数据
	{
		IIC_Send(*(pbuffer+t));
		IIC_WaitAck();       //每发送一个字节,都需要一个应答
	}
	IIC_Stop();              //终止通讯
}

二、读数据

当前地址读

alt

指定设备+从机当前地址指针指示的地址下,读从机的数据

指定地址读

alt

指定设备+指定地址+读从机数据

  • 指定设备写+指定地址(让从机指针先指过去)

  • 指定设备读+读指定地址

void I2C_READ_BYTES(u8 slaveaddr,u8 registeraddr,u8 *pbuffer,u16 num );//读取具体从机的相关寄存器一串字节
{
    I2C_Start();           //开始通讯
	I2C_Send(slaveaddr);   //寻址从机
	I2C_WaitAck();         //等待回应
	I2C_Send(registeraddr);//寻址寄存器
	I2C_WaitAck();         //等待回应

	I2C_Start();           //重新通讯
	I2C_Send(slaveaddr+1); //改为读数据
	I2C_WaitAck();         //等待回应

	for(t=0;t<num;t++)     //存储数据
	{
		*(pbuffer+t)=I2C_Read();
		if (t== num-1)     //字节没发完,必须给出应答,发完的给个非应答信号
	 	{
	   	 	IIC_Ack();
		}
		else
		{
	    	IIC_NAck();
		}
	}
	IIC_Stop();            //通讯结束
}

常见面试问题

IIC优势有哪些?
  • 两根线
  • 同步
  • 带应答
  • 一主多从、多主多从
I2C可以挂载多少个器件

IIC协议规定,在启动总线后第1字节的高7位是从节点的寻址地址,其中高四位为器件类型识别符,接着三位为片选,最后一位为读写位,当为1时为读操作,为0时为写操作,所以具体挂载多少个器件由I2C地址决定,7位寻址地址减去1个广播地址0x00不用,所以有2^7=128 - 1 = 127,那就是127个地址,所以理论上可以挂127个从器件。

每个设备都必须具有唯一的7位或10位地址(在7位地址模式下,地址是0-127之间的数字,在10位地址模式下,地址是0-1023之间的数字)。

I2C如何同时挂载多个同一种器件(地址相同的器件)?

通过GPIO控制IIC芯片上的地址选择引脚选择改变器件地址

或可以通过硬件上设计,控制器件是否挂载总线来实现(方法可用一个开关电路切断器件SDA或者SCL是否接入总线来实现)。

I2C总线的仲裁你知道吗?

I2C总线具有多主控能力,有时会发生两个或多个主器件同时想占用总线的情况,这种情况叫做总线竞争。I2C可以对发生在SDA线上的总线竞争进行仲裁,I2C总线的仲裁逻辑是建立在线与功能上的,有一个拉低SDA总线就是低。

其仲裁原则是这样的:每一个主器件每次发送一位数据,然后比较总线上所呈现的电平与自己所发送的数据是否一致,如果一致,继续发送下一位数据,否则就退出竞争。

总线竞争的仲裁在两个层次上进行:首先是地址位的比较,如果主器件寻址同一个从器件,则进入数据位比较,从而确保竞争仲裁的可靠性。由于是利用IIC总线上的信息进行仲裁,不会造成信息的丢失。

如果一个设备收到了其他设备发送的仲裁比特和地址,那么它会停止发送数据并释放总线,让另一个设备继续控制总线。如果没有任何一个设备释放总线,则总线将一直处于锁定状态,直到有设备释放总线。如果I2C总线一直处于锁定状态,那么任何设备都无法进行数据传输,因为总线被其他设备占用。这意味着任何设备都不能发送数据,也不能接收数据。因此,设备之间的通信将被阻塞,直到总线被释放。如果总线被锁定的时间太长,可能会导致数据传输的失败和系统的异常。为了避免这种情况,需要在设计和实现I2C系统时仔细考虑总线仲裁机制,并确保在系统中合理地分配和协调I2C总线上的设备。

I2C总线的其他注意点

1、进行数据传送时,在SCL为高电平期间,SDA线上电平必须保持稳定,只有SCL为低时,才允许SDA线上电平改变状态。并且每个字节传送时都是高位在前。 2、对于应答信号,ACK=0时为有效应答位,说明从机已经成功接收到该字节,若为1则说明接受不成功。 3、如果从机需要延迟下一个数据字节开始传送的时间,可以通过把SCL电平拉低并保持来强制主机进入等待状态。 4、主机完成一次通信后还想继续占用总线在进行一次通信,而又不释放总线,就要利用重启动信号Sr。它既作为前一次数据传输的结束,又作为后一次传输的开始。 5、总线冲突时,按“低电平优先”的仲裁原则,把总线判给在数据线上先发送低电平的主器件。 6、在特殊情况下,若需禁止所有发生在I2C总线上的通信,可采用封锁或关闭总线,具体操作为在总线上的任一器件将SCL锁定在低电平即可。 7、SDA仲裁和SCL时钟同步处理过程没有先后关系,而是同时进行的。

I2C十位设备地址

任何IIC设备都有一个7位地址,理论上,现实中只能有127种不同的IIC设备。实际上,已有IIC的设备种类远远多于这个限制,在一条总线上出现相同的地址的IIC设备的概率相当高。为了突破这个限制,很多设备使用了双重地址——7位地址加引脚地址。IIC标准也预知了这种限制,提出10位的地址方案。

10位的地址方案对IIC协议的影响有两点:

  • 第一,地址帧为两个字节长,原来的是一个字节。
  • 第二,第一个字节前五位最高有效位用作10位地址标识,约定是“11110”。

alt

除了10位地址标识,标准还预留了一些地址码用作其它用途,如下表:

Address R/W Purpose
0000 000 0 general call address
0000 000 1 START byte
0000 001 X CBUS address
0000 010 X reserved for different bus formats
0000 011 X reversed for future purpose
0000 1XX X high speed master code
1111 0XX X 10-bits slave addressing
1111 1XX X reverse for future purpose
I2C时钟拉伸

在IIC通信中,主设备决定了时钟速度。因为时钟脉冲信号是由主设备显式发出的。但是,当从设备没办法跟上主设备的速度时,从设备需要一种机制来请求主设备慢一点,这种机制称为时钟拉伸。而基于IIC结构的特殊性,这种机制得到实现。当从设备需要降低传输的速度的时候,它可以按下时钟线,逼迫主设备进入等待状态,直到从设备释放时钟线,通信才继续。

I2C时钟信号(SCL)的同步问题

在I2C总线上传送信息时的时钟同步信号是由挂接在SCL线上的所有器件的逻辑“与”完成的。SCL线上由高电平到低电平的跳变将影响到这些器件,一旦某个器件的时钟信号下跳为低电平,将使SCL线一直保持低电平,使SCL线上的所有器件开始低电平期。此时,低电平周期短的器件的时钟由低至高的跳变并不能影响SCL线的状态,于是这些器件将进入高电平等待的状态。当所有器件的时钟信号都上跳为高电平时,低电平期结束,SCL线被释放返回高电平,即所有的器件都同时开始它们的高电平期。其后,第一个结束高电平期的器件又将SCL线拉成低电平。这样就在SCL线上产生一个同步时钟。可见,时钟低电平时间由时钟低电平期最长的器件确定,而时钟高电平时间由时钟高电平期最短的器件确定。

如果被控器希望主控器降低传送速度可以通过将SCL主动拉低延长其低电平时间的方法来通知主控器,当主控器在准备下一次传送发现SCL的电平被拉低时就进行等待,直至被控器完成操作并释放SCL线的控制控制权。这样,主控器实际上受到被控器的时钟同步控制。可见SCL线上的低电平是由时钟低电平最长的器件决定;高电平的时间由高电平时间最短的器件决定。这就是时钟同步,它解决了I2C总线的速度同步。

I2C的通讯速度有几种?

彻底搞懂IIC总线(5)I2C总线传输速度详解 - 德力威尔王术平 - 博客园 (cnblogs.com)

(2条消息) spi、iic、can高速传输速度与选择_万_大_帅的博客-CSDN博客_spi速度

终于看懂了!通信协议 IIC 与 SPI 最全对比 - 知乎 (zhihu.com)

速度模式最高比特率( bit/s)备注
标准模式(Sm) 100K 双向传输,高速模式兼容低速模式
快速模式(Fm) 400K
快速模式增强(Fm+) 1M
高速模式(HSm) 3.4M
超快速模式(UFm) 5M 单向传输,不兼容其他模式
  1. 标准模式(Standard Mode):标准模式是I2C总线最基本的通讯速度。在标准模式下,时钟频率最高可以达到100 kHz,总线电容最大为400 pF。这种通讯速度适用于较长的总线和较慢的设备,如LCD显示屏、温度传感器等。
  2. 快速模式(Fast Mode):快速模式是I2C总线的一种较快的通讯速度。在快速模式下,时钟频率最高可以达到400 kHz,总线电容最大为400 pF。这种通讯速度适用于数据传输速度要求较高的设备,如EEPROM、实时时钟等。
  3. 快速模式加(Fast Mode Plus):快速模式加是I2C总线的一种改进版快速模式。在快速模式加下,时钟频率最高可以达到1 MHz,总线电容最大为400 pF。这种通讯速度适用于对数据传输速度要求更高的设备,如高速ADC、高速数字信号处理器等。
  4. 高速模式(High-Speed Mode):高速模式是I2C总线的一种较快的通讯速度。在高速模式下,时钟频率最高可以达到3.4 MHz,总线电容最大为400 pF。这种通讯速度适用于对数据传输速度要求非常高的设备,如高清视频处理器、高速闪存等。
  5. 超高速模式(Ultra Fast-mode):超高速模式是I2C总线的一种非常快的通讯速度。在超高速模式下,时钟频率最高可以达到5 MHz,总线电容最大为200 pF。这种通讯速度适用于需要超高速数据传输的设备,如图像处理器、高速网络接口等。

高速模式

原理上讲,使用上拉电阻来设置逻辑1,会限制总线的最大传输速度。而速度是限制总线应用的因素之一。这也说明为什么要引入高速模式(3.4Mbps)。在发起一次高速模式传输前,主设备必须先在低速的模式下(例如快速模式)发出特定的“High Speed Master”信号。为缩短信号的周期和提高总线速度,高速模式必须使用额外的I/O缓冲区。另外,总线仲裁在高速模式下可屏蔽掉。

异步IIC有了解吗?

异步IIC是指同步串行通信的I2C协议的一种变体。在标准的I2C协议中,通信是同步的,而异步IIC则是一种基于异步通信方式的I2C协议。

在异步IIC中,时钟信号不是由主设备提供,而是由从设备生成。这意味着从设备负责控制时钟,并在数据线上发送数据。主设备则负责检测从设备发送的时钟信号和数据,并对数据进行解析。

异步IIC协议的工作原理如下:

  1. 从设备在数据线上生成时钟信号,并将数据发送到数据线上。
  2. 主设备检测数据线上的时钟信号,并在时钟信号的边沿进行数据采样。
  3. 主设备根据采样到的数据进行处理,如读取数据或向从设备发送命令。
  4. 主设备和从设备之间通过数据线进行双向通信。

异步IIC协议相对于标准的同步I2C协议,在实现上更为简单,因为主设备不需要提供时钟信号。然而,由于时钟信号是由从设备生成的,因此在异步IIC中可能存在一些时钟同步的挑战,例如时钟偏移和数据速率的不一致。因此,异步IIC通常用于一些特定的应用场景,而不是广泛应用于各种设备之间的通信。

通过IIC配置外设失败了,一般从哪几种角度出发排查。

当通过IIC配置外设失败时,可以从以下几种角度出发进行排查:

  1. 硬件连接问题:检查IIC总线的物理连接是否正确。确保SDA(数据线)和SCL(时钟线)正确连接到外设和主控制器,并且没有短路或断开的情况。还要确保上拉电阻的数值和位置正确。
  2. 电源供电问题:确认外设和主控制器都正常供电,并检查电源电压是否在可接受范围内。低电压可能导致通信错误或不稳定。
  3. 地址设置问题:检查外设的地址设置是否正确。确保外设的IIC地址与要求的地址匹配。有些外设具有可编程地址,因此需要验证是否正确设置了地址。
  4. IIC协议参数设置问题:确保主控制器和外设之间的IIC协议参数设置一致,如速率、传输模式等。确认主控制器发送的start bit、stop bit等控制信号正确地驱动外设。
  5. 软件程序问题:检查软件代码是否正确实现了IIC通信协议。确认发送和接收的数据格式、顺序、时序是否符合规范。还要确保正确处理ACK(应答)信号和超时等异常情况。
  6. 外设工作状态问题:检查外设自身是否正常工作。对于某些外设,可能需要进行初始化或配置才能正常通信。确保外设处于正确的模式或状态。
IIC协议中上拉电阻和速率的关系,如果是速率高,上拉电阻如何调整?

上拉电阻的数值决定了总线上的电平转换速度。较大的上拉电阻会导致总线上的电平变化速度较慢,而较小的上拉电阻则会使电平变化速度更快。

当需要提高IIC总线的速率时,可以采取以下两种方法来调整上拉电阻:

  1. 减小上拉电阻的数值:通过减小上拉电阻的阻值,可以加快总线上的电平变化速度,从而提高总线的速率。通常,在标准模式(Standard-mode)下,推荐使用4.7kΩ的上拉电阻;在快速模式(Fast-mode)下,推荐使用1.5kΩ的上拉电阻。
  2. 使用强驱动能力的器件:除了调整上拉电阻的数值外,还可以选择具有较高驱动能力的器件来驱动IIC总线。这些器件能够提供更大的电流,从而加快总线上的电平变化速度,进而提高总线的速率。

在调整上拉电阻的数值或选择器件时,必须遵循IIC协议规范中对于不同模式(如标准模式、快速模式、高速模式等)的要求,以确保通信的可靠性和兼容性。

#C++##嵌入式##笔试##面试##八股#
【嵌入式八股】三、硬件篇 文章被收录于专栏

查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇 2.计算机基础 3.硬件篇【本专栏】 4.嵌入式Linux (建议PC端查看)

全部评论

相关推荐

4 17 评论
分享
牛客网
牛客企业服务