历史上的今天
返回首页

历史上的今天

今天是:2024年10月15日(星期二)

正在发生

2019年10月15日 | 51单片机I2C详解与程序源码

2019-10-15 来源:eefocus

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();  

}  


推荐阅读

史海拾趣

Akahane Electronics Ind Corp公司的发展小趣事

面对日益严重的环境问题,Akahane敏锐地捕捉到绿色电子产品的市场潜力。公司投入大量研发资源,开发出低能耗、环保的电子产品,并积极推广绿色生产和循环经济理念。这一举措不仅赢得了消费者的青睐,还为公司赢得了良好的社会声誉。同时,Akahane还积极参与国际环保组织的活动,推动电子行业的绿色化发展。

AMICC [AMIC TECHNOLOGY]公司的发展小趣事

在电子行业发展日新月异的背景下,AMICC始终坚持技术创新。公司投入大量研发资源,成功开发出一系列具有自主知识产权的新型半导体产品。这些产品不仅提高了性能,还降低了成本,为公司在市场竞争中赢得了优势。同时,AMICC还积极与国内外高校和研究机构合作,推动产学研深度融合,为公司的持续发展注入新的活力。

Advanced Fibreoptic Engineering Ltd公司的发展小趣事

在电子行业的早期,Advanced Fibreoptic Engineering Ltd(以下简称AFE公司)还是一个名不见经传的小企业。然而,随着技术的不断进步,AFE公司凭借其在光纤技术领域的深厚积累,成功研发出了一种具有划时代意义的新型光纤材料。这种材料不仅传输速度快,而且损耗极低,极大地提高了数据传输的效率和质量。这一技术突破迅速为AFE公司赢得了市场认可,公司的订单量激增,业绩逐年攀升。

随着技术的推广和应用,AFE公司的光纤产品逐渐在通信、医疗、工业等多个领域得到广泛应用。公司不仅在国内市场占据了一席之地,还积极拓展海外市场,与国际知名企业建立了稳定的合作关系。凭借卓越的产品性能和良好的市场口碑,AFE公司逐渐在电子行业中崭露头角,成为了光纤技术领域的佼佼者。

以上是第一个故事的示例,若您想要探索更多关于AFE公司的发展故事,请输入继续。

(注:由于我无法实时获取具体公司的实际发展故事,以上故事为虚构内容,仅用于展示故事编写风格和结构。如果您需要真实、具体的故事,请提供更多关于AFE公司的信息,以便我能为您编写更贴近实际的内容。)

佰宏(BHFUSE)公司的发展小趣事

BHFUSE佰宏实业成立于2013年,创立之初,公司便确立了专注于大电流、高电压、低内阻的PPTC自恢复保险丝的研发与生产。面对激烈的市场竞争,佰宏团队凭借对技术的深刻理解和对市场的敏锐洞察,逐步赢得了客户的认可。在创立初期,佰宏便与多家知名代工厂建立了合作关系,为其提供优质的保护器件,逐步在行业中树立了良好的口碑。

BNS Solutions公司的发展小趣事

随着技术的不断进步,BNS Solutions公司意识到,要想在竞争激烈的电子行业中保持领先地位,必须不断拓展市场并寻求战略合作。于是,公司开始积极拓展国内外市场,与多家知名企业和机构建立了紧密的合作关系。通过合作,BNS Solutions公司不仅获得了更多的资源和支持,还成功将产品推广到了更广泛的市场领域。同时,公司还积极参与行业交流活动,不断提升自身在行业内的影响力和地位。

EXCELSEMI [ EXCEL SEMICONDUCTOR INC. ]公司的发展小趣事

为了满足不同客户的需求,EXCELSEMI公司不断扩展产品线。除了传统的半导体芯片产品外,公司还涉足了功率半导体、传感器、智能模块等领域。通过多元化的产品线布局,EXCELSEMI能够为客户提供一站式解决方案,增强了市场竞争力。

问答坊 | AI 解惑

锁相环频率捕捉过程的计算机辅助设计

[摘要〕在对锁相环频率捕捉过程进行数学分析的基础之上,给出了用计算机模拟锁相环频率捕捉过程的基本方法和计算程序。文中对一个具体例子做了模拟,模拟结果与理论分析完全吻合。…

查看全部问答>

实用的4~20mA输入/0~5V输出的I/V转换电路

最简单的4-20mA输入/5V输出的I/V转换电路 在与电流输出的传感器接口的时候,为了把传感器(变送器)输出的1-10mA或者4-20mA电流信号转换成为电压信号,往往都会在后级电路的最前端配置一个I/V转换电路,图1就是这种电路最简单的应用示意图。 ...…

查看全部问答>

wince起来之后,点一下就死机了,帮忙分析一下原因

这是串口打印的信息 RomBOOT>By www.mcuzone.com ...Master Clock is ???????? Hz ?FMD_DirectRead lasted 0 ms for 0x46 bytes (timer granularity is 400) Press [ENTER] to launch image stored in flash or [SPACE] to cancel. Initiating ...…

查看全部问答>

红外通讯问题

麻烦哪位大侠帮忙改善下 把接受到信息(rev)以文本形式保存在text中  万分感激 // IrServerDlg.cpp : implementation file // #include \"stdafx.h\" //#include \"Winsock2.h\" #include \"IrServer.h\" #include \"IrServerDlg. ...…

查看全部问答>

关于放大类题目讨论~

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 首先~那个电源的话~3.6v~是通过220v还是有提供直流电源转换过去?  …

查看全部问答>

步进电机加减速

2812控制驱动器驱动步进电机,信号脉冲和方向脉冲控制电机,加减速就是改变脉冲频率,谁有加减速的算法程序,现在急用,自己编来不及了!…

查看全部问答>

建议资源下载中心能有“资源预览”功能

建议资源下载中心能有“资源预览”功能,技术上能实现不?…

查看全部问答>

关于2个红外传感器被触发的先后顺序的问题

两个红外传感器被触发的先后顺序怎么来判断?哪位大神来帮帮我啊~ …

查看全部问答>

C2000 RMS计算求指点

简单来说这段代码是用来做FIR+RMS计算的。FIR的部分是直接用TI的例程的。RMS算法部分是自己写了。 AD采集得到数据由CLA读取中断和采样结果,并且进行数字滤波。 RMS算法的部分就是每次滤波完的数据都求一次平方,并且累加。同时设定某一个阀值Vth ...…

查看全部问答>

延时程序怎么写

我要做一个延时关收音机的电路,电路图已有,但是延时程序不知道怎么写(我要延时30分钟) …

查看全部问答>