I2C是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。I2C是总线结构,1个Master,1个或多个Slave,各Slave设备以7位地址区分,地址后面再跟1位读写位,表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址,此时每个设备有读、写两个地址,高7位地址其实是相同的。
I2C数据格式如下:
无数据:SCL=1,SDA=1;
开始位(Start):当SCL=1时,SDA由1向0跳变;
停止位(Stop):当SCL=1时,SDA由0向1跳变;
数据位:当SCL由0向1跳变时,由发送方控制SDA,此时SDA为有效数据,不可随意改变SDA;
当SCL保持为0时,SDA上的数据可随意改变;
地址位:定义同数据位,但只由Master发给Slave;
应答位(ACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=0;
否应答位(NACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=1。
当数据为单字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,停止位。
当数据为一串字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,8位数据,应答,……,8位数据,应答,停止位。
需要注意的是:
1,SCL一直由Master控制,SDA依照数据传送的方向,读数据时由Slave控制SDA,写数据时由Master控制SDA。当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反。
2,开始位“Start”和停止位“Stop”,只能由Master来发出。
3,地址的8位传送完毕后,成功配置地址的Slave设备必须发送“ACK”。否则否则一定时间之后Master视为超时,将放弃数据传送,发送“Stop”。
4,当写数据的时候,Master每发送完8个数据位,Slave设备如果还有空间接受下一个字节应该回答“ACK”,Slave设备如果没有空间接受更多的字节应该回答“NACK”,Master当收到“NACK”或者一定时间之后没收到任何数据将视为超时,此时Master放弃数据传送,发送“Stop”。
5,当读数据的时候,Slave设备每发送完8个数据位,如果Master希望继续读下一个字节,Master应该回答“ACK”以提示Slave准备下一个数据,如果Master不希望读取更多字节,Master应该回答“NACK”以提示Slave设备准备接收Stop信号。
6,当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。
在实际应用中,并没有强制规定数据接收方必须对于发送的8位数据做出回应,尤其是在Master和Slave端都是用GPIO软件模拟的方法来实现的情况下,编程者可以事先约定数据传送的长度,slave不检查NACK,有时可以起到减少系统开销的效果。但是如果slave方是硬件i2c要求一定要标准的NACK,master方是GPIO软件模拟i2c并没有正确的发送NACK,就会出现“slave收不到stop”导致i2c挂死。
在正常情况下,I2C总线协议能够保证总线正常的读写操作。但是,当I2C主设备异常复位时(看门狗动作,板上电源异常导致复位芯片动作,手动按钮复位等等)有可能导致I2C总线死锁产生。下面详细说明一下总线死锁产生的原因。
在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于I2C主设备来说.复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态。同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导致I2C总线进入死锁状态。
方法
(1)尽量选用带复位输人的I2C从器件。
(2)将所有的从I2C设备的电源连接在一起,通过MOS管连接到主电源,而MOS管的导通关断由I2C主设备来实现。
(3)在I2C从设备设计看门狗的功能。
(4)在I2C主设备中增加I2C总线恢复程序。
每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况,“9个clk可以激活”的方法来自NXP的文档,NXP(Philips)作为I2C总线的鼻祖,这样的说法是可信的),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。
这种方法有很大的局限性,因为大部分主设备的I2C模块由内置的硬件电路来实现,软件并不能够直接控制SCL信号模拟产生需要时钟脉冲。
或者,发送I2C_Stop条件也能让从设备释放总线。
如果是GPIO模拟I2C总线实现,那么在I2C操作之前,加入I2C总线状态检测I2C_Probe,如果总线被占用,则可尝试恢复总线,待总线释放后,再进行操作。要保证I2C操作最小单元的完整性,不被其他事件(中断、高优先级线程,等)打断。
(5)在I2C总线上增加一个额外的总线恢复设备。这个设备监视I2C总线。当设备检测到SDA信号被拉低超过指定时间时,就在SCL总线上产生9个时钟脉冲,使I2C从设备完成读操作,从死锁状态上恢复出来。总线恢复设备需要有具有编程功能,一般可以用单片机或CPLD实现这一功能。
(6)在I2C上串人一个具有死锁恢复的I2C缓冲器,如Linear公司的LTC4307是一个双向的I2C总线缓冲器,并且具有I2C总线死锁恢复的功能。LTC4307总线输入侧连接主设备,总线输出侧连接所有从设备。当LTC4307检测到输出侧SDA或SCL信号被拉低30ms时,就自动断开I2C总线输入侧与输出侧的连接.并且在输出侧SCL信号上产生16个时钟脉冲来释放总线。当总线成功恢复后,LTC4307会再次连接输入输出侧,使总线能够正常工作。
void I2Cstart()//开始标志
{
SDA=1;
SCL=1;
SDA=0;
delay1ms(4);
SCL=0;
delay1ms(4);
}
void I2Cstop()//结束标志
{
SCL=0;
delay1ms(4);
SDA=0;
delay1ms(4);
SCL=1;
delay1ms(4);
SDA=1;
delay1ms(4);
}
unsigned char I2Creadack()
{
unsigned char i,byte;
byte=0;
for(i=0;i<8;i++)
{
SCL=0;
SDA=1;
delay1ms(4);
byte<<=1;
if(SDA==1)
{
byte|=0x01;
delay1ms(4);
}
}
SCL=0;
delay1ms(4);
SDA=0;
delay1ms(4);
SCL=1;
delay1ms(4);
SCL=0;
return byte;
}
void I2Csend(unsigned char byte)//I2C写数据的过程
{
unsigned char mask,i;
for(i=0;i<8;i++)
{
SCL=0;
if((mask&byte)==0)
{
SDA=0;
}
else
{
SDA=1;
}
mask>>=1;
delay1ms(4);
SCL=1;//给足够时间让数据读取
delay1ms(4);
}
SCL=0;
SDA=1; //因为总线上有一个信号为低则低
delay1ms(4);
SCL=1;
delay1ms(4);//等待应答位
SCL=0;
}
unsigned char I2Cread(void)
{
unsigned char i,byte;
byte =0;
for(i=0;i<8;i++)
{
SCL=0;
SDA=1;//读数据必须拉高
delay1ms(4);
SCL=1;//数据稳定
delay1ms(4);
byte<<=1;
if(SDA==1)
{
byte|=0x01;
}
delay1ms(4);
}
SCL=0;
delay1ms(4);
SDA=0;//发送的应答位
delay1ms(4);
SCL=1;
delay1ms(4);
SCL=0;
return byte;
}
unsigned char I2Cread_eeprom(unsigned char addr)//I2C读取数据
{
unsigned char datebyte,datebyte2;
I2Cstart();
I2Csend(0xa0);//写数据
I2Csend(addr);
I2Cstart();
I2Csend(0xa1);//读数据
datebyte2=I2Creadack();
datebyte=I2Cread();
I2Cstop();
return datebyte;
}
void write_eeprom(unsigned char addr,unsigned char datebyte)
{
I2Cstart();
I2Csend(0xa0);
I2Csend(addr);
I2Csend(datebyte);
I2Cstop();
}
上一篇:51单片机DS18B20温度计制作 带仿真和源码
下一篇:单片机国旗自动升降系统仿真及程序
推荐阅读
史海拾趣
为了进一步满足中国市场的本地化需求,依必安派特在2005年成立了依必安派特电机(上海)有限公司,开始了国产化进程。这一举措不仅提高了产品的性价比,还缩短了交货周期,使得依必安派特在中国市场的竞争力得到了显著提升。随着国产化产品的快速增长,依必安派特在中国的前十年市场业绩突飞猛进,为后续的飞跃发展打下了坚实基础。
Davies Molding公司在发展过程中,始终注重市场布局与拓展。公司不仅在美国中西部建立了稳固的市场地位,还积极开拓国际市场,将产品出口到全球多个国家和地区。通过与全球客户的合作,Davies Molding公司不仅提升了品牌影响力,还获得了更多的发展机遇。
Davies Molding公司在追求经济效益的同时,始终关注社会责任和可持续发展。公司积极参与环保公益活动,推动绿色生产,降低对环境的影响。此外,Davies Molding公司还注重员工福利和社会公益事业,为员工提供良好的工作环境和发展空间,为社会做出积极贡献。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了坚实基础。
Captive Fastener公司深知产品质量是企业生存和发展的关键。公司建立了严格的质量管理体系,从原材料采购到生产加工、产品检验等各个环节都进行严格把关。此外,公司还定期对员工进行质量意识和技能培训,确保每一道工序都符合质量标准。这些措施有效提升了公司的产品质量和客户满意度。
作为一家领先的电子企业,ETC公司深知自身肩负的社会责任。公司积极履行社会责任,关注环境保护和资源节约。ETC通过引进先进的生产工艺和设备,减少生产过程中的能源消耗和废弃物排放。同时,公司还积极参与公益事业和社会活动,为社会做出了积极贡献。这些举措不仅提升了ETC的企业形象,也为公司的可持续发展奠定了坚实的基础。
ETC公司非常重视团队建设和文化塑造。公司注重培养员工的创新能力和团队协作精神,为员工提供广阔的发展空间和良好的职业前景。同时,ETC还积极营造积极向上、开放包容的企业文化,使员工能够在轻松愉悦的氛围中工作和学习。这些举措不仅提高了员工的满意度和忠诚度,也为公司的长期发展奠定了坚实的基础。
求一个在AT89C2051下能够正常运行的keilc的C语言工程。 哪位大侠,手头上有现成的,比较简单的,给我一个成熟的工程。 因为我要编一个AT89C2051的小程序,无论如何下载到片机上以后,程序都不能正常的运行,所以希望能够参考一下成熟的程序。 一 ...… 查看全部问答∨ |
当我屁颠屁颠地跟在老师后面不厌其烦询问如何编写某个程序的时候,老师总是对我说先画出你程序的 控制流程序图吧。当时觉得麻烦,也就把这经验之谈当成了一阵风吹过。现在,走上了程序开发这条路 ,才知道开发之前系统的规化一下自已的思路是 ...… 查看全部问答∨ |
6410(或2440)上, 向GPIO口写1(或置高) 的步骤是不是以下这样: 6410(或2440)上, 向GPIO口写1(或置高) 的步骤是不是以下这样: Port X Pull-up/down Register --> pull-up enabled (置高使能) Port X Configuration Register - ...… 查看全部问答∨ |
|
请教一下在ARM9下wince系统的视频监控如何实现,有没有大虾们做过类似的。最好可以给出实例代码,万分感谢!可以发送到本人邮箱:jhlovebb@126.com… 查看全部问答∨ |
在下初学VHDL,下面是一个D触发器的VHDL代码,感觉没错,但是Quartus2在编译的时候总是不能成功,提示: Error (10533): VHDL Wait Statement error at text.vhd(13): Wait Statement must contain condition clause with UNTIL keyword PS: 1. ...… 查看全部问答∨ |
今天刚用NRF24L01无线模块做了一个程控小车,但目前还是初级阶段,只能控制运动,我想再加一些辅助功能,像通过无线传送图像,就是把摄像头采集到的图像通过无线传到电脑,达到一个监控的作用,但是不知道这个无线模块能不能实现,刚网上订购的摄像 ...… 查看全部问答∨ |
|
我以前用的51的一段显示字符串子函数: void print(uchar *str) { while(*str!=\'\\0\') { LCD_Write(*str); ...… 查看全部问答∨ |