对IIC总线的理解、调⽤函数以及常见⾯试问题
⼀、IIC 总线概述:
IIC 即Inter-Integrated Circuit(集成电路总线)
I2C总线是PHLIPS公司推出的⼀种串⾏总线, I2C总线只有两根双向信号线。⼀根是数据线SDA,另⼀根是时钟线SCL。
每个接到I2C总线上的器件都有唯⼀的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。
⼆、IIC 总线通信协议:
要掌握IIC的通信协议,需要掌握以下6个通信信号:
1.起始信号
2.终⽌信号
3.写数据
4.读数据
5.应答信号
6.⾮应答信号
起始和终⽌信号
SCL线为⾼电平期间,SDA线由⾼电平向低电平的变化表⽰起始信号;SCL线为⾼电平期间,SDA线由低电平向⾼电平的变化表⽰终⽌信号。
应答信号
IIC 总线协议规定,每传送⼀个字节数据后,都要有⼀个应答信号以确定数据传送是否被对⽅收到。应答信号由接受设备产⽣,在SCL为⾼电平期间,接受设备将SDA拉低为低电平,表⽰数据传输正确,产⽣应答(ACK)
数据传送
I2C总线进⾏数据传送时,时钟信号为⾼电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的⾼电平或低电平状态才允许变化。
根据AT24C02的芯⽚,可编写以下信号函数程序:
//1.起始信号 SCL线为⾼电平期间,SDA线由⾼电平向低电平的变化表⽰起始信号;
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
delay_us(1);  //15us    >> 4.7us
SDA = 0;
delay_us(1);
SCL = 0;
}
/
/2.终⽌信号 SCL线为⾼电平期间,SDA线由低电平向⾼电平的变化表⽰终⽌信号。
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
delay_us(1);  //15us    >> 4.7us
SDA = 1;
delay_us(1);
SCL = 0;
}
void IIC_SendByte(unsigned char dat)  //3.写数据
{
unsigned char i;
for (i = 0; i < 8; i++)
{
if((dat<<i)&0x80)
SDA = 1;
}
else
{
SDA = 0;
}
SCL = 1;      //开始让数据维持稳定
delay_us(1);
SCL = 0;
delay_us(1);
}
SDA = 1; //释放总线,发送完8位,主机置⾼电平
SCL = 1;
delay_us(1);
if (SDA)        //SDA 低电平从机回馈低电平
{
ack = 0;  //0 == ack  代表⽆ack信号,从机不应答,发送不成功
}
else
{
ack = 1;  //从机应答,发送成功
}
SCL = 0;
delay_us(5);
}
unsigned char IIC_RecvByte(void)  //4. 读数据
{
unsigned char i, temp;
SDA = 1;              //保险⾼的与上低的是低的,线与
for (i = 0; i < 8; i++)
{
SCL = 0;      // 告诉数据可以变化      SDA  脉冲线
//只有在时钟线上的信号为低电平期间,数据线上的⾼电平或低电平状态才允许变化。
delay_us(1);
SCL = 1;      // 数据保持稳定,开始读
delay_us(1);
temp<<=1;
if (SDA)
{
temp = temp + 1;
}
}
SCL = 0;
delay_us(10);
return temp;
}
void IIC_ACK(void)        //5. 应答信号
{
SDA = 0;
recv函数SCL = 1;
delay_us(1);
SCL = 0;
}
void IIC_NOACK(void)      //6. ⾮应答信号
{
SDA = 1;
SCL = 1;
delay_us(1);
SCL = 0;
}
根据时序图,可编写24C02的读写函数程序:
unsigned char AT24CXX_WriteStr(unsigned char devaddr, unsigned char romaddr, unsigned char *s, unsigned char num) {
unsigned char i;
IIC_Start();
IIC_SendByte(devaddr);
if (0 == ack)
{
return 0;
}
IIC_SendByte(romaddr);
if (0 == ack)
{
return 0;
}
for (i = 0; i < num; i++)
{
IIC_SendByte(*s);
if (0 == ack)
{
return 0;
}
s++;
}
IIC_Stop();
return 1;
unsigned char AT24CXX_ReadStr(unsigned char devaddr, unsigned char romaddr, unsigned char *s, unsigned char num)
{
unsigned char i;
IIC_Start();
IIC_SendByte(devaddr);
if (0 == ack)        //⽆应答返回0 失败
{
return 0;
}
IIC_SendByte(romaddr);
if (0 == ack)
{
return 0;
}
IIC_Start();
IIC_SendByte(devaddr + 1);
if (0 == ack)
{
return 0;
}
for (i = 0; i < num - 1; i++)
{
*s = IIC_RecvByte();
IIC_ACK();
s++;
}
*s = IIC_RecvByte();
IIC_NOACK();
IIC_Stop();
return 1;
}
三、有关 IIC 总线常见⾯试题:(参考)
介绍⼀下你了解的I2C?
I2C总线是飞利浦(PHLIPS)公司推出的⼀种串⾏总线,⽤于连接微控制器及其外围设备, I2C串⾏总线有两根双向信号线。⼀根是数据线SDA,另⼀根是时钟线SCL。它仅通过两根信号线就可以完成对所有挂载在I2C总线上的从器件进⾏操作。这样的好处是可以⼤⼤的节省我们微处理器的IO⼝资源。
I2C到底可以挂载多少个器件呢?
答:IIC协议规定,在启动总线后第1字节的⾼7位是从节点的寻址地址,其中⾼四位为器件类型识别符,接着三位为⽚选,最后⼀位为读写位,当为1时为读操作,为0时为写操作,所以具体挂载多少个器件由I2C地址决定,7位寻址地址减去1个⼴播地址0x00不⽤,所以有2^7=128 - 1 = 127,那就是127个地址,所以理论上可以挂127个从器件。
I2C如何同时挂载多个同⼀种器件(地址相同的器件)?
答:理论上是不会这样设计的,如果⼀定要这样做的话,可以通过硬件上设计,控制器件是否挂载总线来实现(⽅法可⽤⼀个开关电路切断器件SDA或者SCL是否接⼊总线来实现)
I2C总线的主机与从机之间是如何通信的呢?
I2C总线的主机与从机之间的通信主要和I2C的时序有关。在通信开始的时候SCL与SDA都置为⾼电平,此时为总线空闲时间。当SCL为⾼电平期间SDA的电平被拉低,标志这总线的启动。当SCL为⾼电平期间SDA的电平被拉⾼,标志这总线的终⽌。在进⾏数据传送时,SCL为⾼电平期间,SDA上的数据必须保持稳定,只有在SCL的信号为低电平时,SDA上的⾼电平才允许变化。所以只要我们根据芯⽚⼿册正确的写好IIC的时序,按时序发送器件地址(不同的器件的地址不同)以及数据,就可以使主机与从机之间通信。
I2C总线的仲裁你知道吗?
总线上可能挂接有多个器件,有时会发⽣两个或多个主器件同时想占⽤总线的情况,这种情况叫做总线竞争。I2C总线具有多主控能⼒,可以对发⽣在SDA线上的总线竞争进⾏仲裁,其仲裁原则是这样的:当多个主器件同时想占⽤总线时,如果某个主器件发送⾼电平,⽽另⼀个主器件发送低电平,则发送电平与此时SDA总线电平不符的那个器件将⾃动关闭其输出级。总线竞争的仲裁是在两个层次上进⾏的。⾸先是地址位的⽐较,如果主器件寻址同⼀个从器件,则进⼊数据位的⽐较,从⽽确保了竞争仲裁的可靠性。由于是利⽤I2C总线上的信息进⾏仲裁,因此不会造成信息的丢失。
I2C时钟信号(SCL)的同步问题
在I2C总线上传送信息时的时钟同步信号是由挂接在SCL线上的所有器件的逻辑“与”完成的。SCL线上由⾼电平到低电平的跳变将影响到这些器件,⼀旦某个器件的时钟信号下跳为低电平,将使SCL线⼀直保持低电平,使SCL线上的所有器件开始低电平期。此时,低电平周期短的器件的时钟由低⾄⾼的跳变并不能影响SCL线的状态,于是这些器件将进⼊⾼电平等待的状态。当所有器件的时钟信号都上跳为⾼电平时,低电平期结束,SCL线被释放返回⾼电平,即所有的器件都同时开始它们的⾼电平期。其后,第⼀个结束⾼电平期的器件⼜将SCL线拉成低电平。这样就在SCL线上产⽣⼀个同步时钟。可见,时钟低电平时间由时钟低电平期最长的器件确定,⽽时钟⾼电平时间由时钟⾼电平期最短的器件确定。
I2C总线的其他注意点
1、进⾏数据传送时,在SCL为⾼电平期间,SDA线上电平必须保持稳定,只有SCL为低时,才允许SDA线上电平改变状态。并且每个字节传送时都是⾼位在前。
2、对于应答信号,ACK=0时为有效应答位,说明从机已经成功接收到该字节,若为1则说明接受不成功。
3、如果从机需要延迟下⼀个数据字节开始传送的时间,可以通过把SCL电平拉低并保持来强制主机进⼊等待状态。
4、主机完成⼀次通信后还想继续占⽤总线在进⾏⼀次通信,⽽⼜不释放总线,就要利⽤重启动信号Sr。它既作为前⼀次数据传输的结束,⼜作为后⼀次传输的开始。
5、总线冲突时,按“低电平优先”的仲裁原则,把总线判给在数据线上先发送低电平的主器件。
6、在特殊情况下,若需禁⽌所有发⽣在I2C总线上的通信,可采⽤封锁或关闭总线,具体操作为在总线上的任⼀器件将SCL锁定在低电平即可。
7、SDA仲裁和SCL时钟同步处理过程没有先后关系,⽽是同时进⾏的。
I2C的基础概念和框架
⼀、IIC 基础概念
IIC(Inter-Integrated Circuit)总线是⼀种由PHILIPS公司开发的两线式串⾏总线,⽤于连接微控制器及其外围设备。IIC总线产⽣于在80年代,最初为⾳频和视频设备开发,如今主要在服务器管理中使⽤,其中包括单个组件状态的通信。例如管理员可对各个组件进⾏查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。可随时监控内存、硬盘、⽹络、系统温度等多个参数,增加了系统的安全性,⽅便了管理。
1、 IIC总线的特点
IIC总线最主要的优点是其简单性和有效性。由于接⼝直接在组件之上,因此IIC总线占⽤的空间⾮常⼩,减少了电路板的空间和芯⽚管脚的数量,降低了互联成本。总线的长度可⾼达25英尺,并且能够以10Kbps的最⼤传输速率⽀持40个组件。IIC总线的另⼀个优点是,它⽀持多主控(multimastering),其中任何能够进⾏发送和接收的设备都可以成为主总线。⼀个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有⼀个主控。
2、IIC总线⼯作原理
a -- 总线构成
IIC总线是由数据线SDA和时钟SCL构成的串⾏总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进⾏双向传送,最⾼传送速率
100kbps。各种被控制电路均并联在这条总线上,但就像电话机⼀样只有拨通各⾃的号码才能⼯作,所以每个电路和模块都有唯⼀的地址,在信息的传输过程中,IIC总线上并接的每⼀模块电路既是主控器(或被控器),⼜是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分:
1) 地址码⽤来选址,即接通需要控制的电路,确定控制的种类;
2) 控制量决定该调整的类别(如对⽐度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同⼀条总线上,却彼此独⽴,互不相关。
b -- 信号类型
IIC总线在传送数据过程中共有四种类型信号:
开始信号:SCL为⾼电平时,SDA由⾼电平向低电平跳变,开始传送数据;
结束信号:SCL为⾼电平时,SDA由低电平向⾼电平跳变,结束传送数据;
数据传输信号:在开始条件以后,时钟信号SCL的⾼电平周期期问,当数据线稳定时,数据线SDA的状态表⽰数据有效,即数据可以被读⾛,开始进⾏读操作。在时钟信号SCL的低电平周期期间,数据线上数据才允许改变。每位数据需要⼀个时钟脉冲。
应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表⽰已收到数据。CPU向受控单元发出⼀个信号后,等待受控单元发出⼀个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
⽬前有很多半导体集成电路上都集成了IIC接⼝。带有IIC接⼝的单⽚机有:CYGNAL的 C8051F0XX系列,PHILIPSP87LPC7XX系
列,MICROCHIP的PIC16C6XX系列等。很多外围器件如存储器、监控芯⽚等也提供IIC接⼝。
3、总线基本操作
IIC规程运⽤主/从双向通讯。器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以⼯作于接收和发送状态。总线必须由主器件(通常为微控制器)控制,主器件产⽣串⾏时钟(SCL)控制总线的传输⽅向,并产⽣起始和停⽌条件。SDA线上的数据状态仅在SCL
为低电平的期间才能改变,SCL为⾼电平的期间,SDA状态的改变被⽤来表⽰起始和停⽌条件。
a -- 控制字节
在起始条件之后,必须是器件的控制字节,其中⾼四位为器件类型识别符(不同的芯⽚类型有不同的定义,EEPROM⼀般应为1010),接着三位为⽚选,最后⼀位为读写位,当为1时为读操作,为0时为写操作。
b -- 写操作
写操作分为字节写和页⾯写两种操作,对于页⾯写根据芯⽚的⼀次装载的字节不同有所不同。关于页⾯写的地址、应答和数据传送的时序。
c -- 读操作
读操作有三种基本操作:当前地址读、随机读和顺序读。图4给出的是顺序读的时序图。应当注意的是:最后⼀个读操作的第9个时钟周期不
是“不关⼼”。为了结束读操作,主机必须在第9个周期间发出停⽌条件或者在第9个时钟周期内保持SDA为⾼电平、然后发出停⽌条件。
d -- 总线仲裁
主机只能在总线空闲的时候启动传输。两个或多个主机可能在起始条件的最⼩持续内产⽣⼀个起始条件,结果在总线上产⽣⼀个规定的起始条件。
当SCL线是⾼电平时,仲裁在SDA线发⽣:这样,在其他主机发送低电平时,发送⾼电平的主机将断开它的数据输出级,因为总线上的电平和它⾃⼰的电平不同。
仲裁可以持续多位。从地址位开始,同⼀个器件的话接着就是数据位(如果主机-发送器),或者⽐较相应位(如果主机-接收器)。IIC总线的地址和数据信息由赢得仲裁的主机决定,在这个过程中不会丢失信息。
仲裁不能在下⾯情况之间进⾏:
1)重复起始条件和数据位;
2)停⽌条件和数据位;
3)重复起始条件和停⽌条件。
4、特性总结
IIC肯定是2线的(不算地线)IIC协议确实很科学,⽐3/4线的SPI要好,当然线多通讯速率相对就快了
IIC的原则是
a -- 在SCL=1(⾼电平)时,SDA千万别忽悠否则,SDA下跳则"判罚"为"起始信号S",SDA上跳则"判罚"为"停⽌信号P".
b -- 在SCL=0(低电平)时,SDA随便忽悠(可别忽悠过⽕到SCL跳⾼)
c -- 每个字节后应该由对⽅回送⼀个应答信号ACK做为对⽅在线的标志.⾮应答信号⼀般在所有字节的最后⼀个字节后.⼀般要由双⽅协议签定.
d -- SCL必须由主机发送,否则天下⼤乱
e -- ⾸字节是"⽚选信号",即7位从机地址加1位⽅向(读写)控制.从机收到(听到)⾃⼰的地址才能发送应答信号(必须应答)表⽰⾃⼰在线.其他地址的从机不允许忽悠(当然呼可以忽悠但只能听不许说话)
f -- 读写是站在主机的⽴场上定义的."读"是主机接收从机数据,"写"是主机发送数据给从机.
g-- 重复位主要⽤于主机从发送模式到接收模式的转换"信号",由于只有2线,所以收发转换肯定要⽐SPI复杂,因为SPI可⽤不同的边沿来收发数据,⽽IIC 不⾏.
h -- 在硬件IIC模块,特别是MCU/ARM/DSP等每个阶段都会得到⼀个准确的状态码,根据这个状态码可以很容易知道现在在什么状态和什么出错信息.
i -- 7位IIC总线可以挂接127个不同地址的IIC设备,0号"设备"作为呼地址.10位IIC总线可以挂接更多的10位IIC设备.
⼆、 Linux下IIC驱动架构
Linux定义了系统的IIC驱动体系结构,在Linux系统中,IIC驱动由3部分组成,即IIC核⼼、IIC总线驱动和IIC设备驱动。这3部分相互协作,形成了⾮常通⽤、可适应性很强的IIC框架。