1I2C总线AT24C02芯片的应用一,I2总线概述1,I2C总线介绍在主从通信中,可以有多个I2C总线器件同时接到I2C总线上,所有与I2C兼容的器件都具有标准的接口,通过地址来识别通信对象,使它们可以经由I2C总线互相直接通信。I2C总线由数据线SDA和时钟线SCL两条线构成通信线路,即可发送数据,也可接受数据,最高传送速率400Kbps,各种器件均并联在总线上,但每个器件都有唯一的地址,CPU发送的控制信号分为地址码和数据码两部分:地址码用来选址,即接通需要控制的电路;数据码是通信的内容,这样个IC控制电路虽然挂在同一条总线上,却彼此独立。2,I2C总线硬件结构图下图为I2C总线系统的硬件结构图,其中SCL是时钟线,SDA是数据线。总线上各器件都采用漏极开路结构与总线相连,因此,SCL和SDA均需上拉电阻,上拉电阻一般为10K,总现在空闲状态下均保持高电平,连到总线上的任一器件输出的低电平,都将使总线信号变低,即各器件的SDA及SCL都是线“与”关系。2I2C总线支持多主和主从两种工作方式,通常为主从工作方式。在主从工作方式中,系统中只有一个主器件(单片机),其它器件都是具有I2C总线的外围从器件。在主从工作方式中,主器件启动数据的发送(发出启动信号),产生时钟信号,发出停止信号。3,I2C总线的通信格式图为I2C总线上进行一次数据传输的通信格式34,数据位的有效性规定I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟信号为低电平期间,数据线上高电平或低电平状态才允许变化,5,发送启动(始)信号在利用I2C总线进`行一次数据传输时,首先由主机发出启动信号,启动I2C总线,在SCL为高电平期间,SDA出现下降沿则为启动信号。此时,具有I2C总线接口的从器件会检测到该信号,启动时序如图所示:46,发送寻址信号主机发送启动信号后,再发出寻址信号。器件地址有7位和10位两种,这里只介绍7位地址寻址方式。寻址字节的位定义如图所示位:76543210从机地址R/——W主机发送地址时,总线上每个从机都将这个7位地址码与自己的地址进行比较,如果相同,则认为自己正被主机寻址,根据R/——W位将自己确定为发送器或者接收器。从机的地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机的7位寻址位有4位是固定的位,3位是可编程位,这是仅能寻址8个同样的器件,即可以有8个同样的器件接入到该I2C总线中。7,应答信号I2C协议规定,每传送一个字节数据(含地址及命令字)后,都要有一个应答信号,以确定数据传送是否被对方收到,应答信号由接收5设备产生,在SCL信号为高电平期间,接收设备将SDA拉为低电平,表示数据传输正确,产生应答,时序图如图所示8,数据传输每个字节必须保证8位长度,数据传送时,先传送高八位(MSB),每一个被传送的字节后面必须跟随一位应答位(即一帧共有9位),主机发送寻址信号并得到从器件应答后,便可进行数据传输,每次一个字节,但每次传输都应在得到应答信号后再进行下一字节的传送。IIC传送的数据信号包括地址信号和数据信号,在起始信号后必须传送一个从从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R),每次数据传送总是由主机产生终止信号结束,但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号,对另一从机进行寻址。9,非应答信号当主机为接收设备时,主机对最后一个字节不应答,以向发送设备表示数据传输结束。10,发送停止信号6在全部数据传输完毕后,主机发送停止信号,即在SCL为高电平期间,SDA上产生一个上升沿信号,停止时序图如图所示:7传送数据时,单片机首先发送一个字节的被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各数据字节,但每发送一个字节后都要等待应答。8二,单片机模拟I2C总线在总线的一次数据传送过程中,可以有以下几种组合方式:(1),主机向从机发送数据,数据传送方向在整个传送过程中不变。(2),主机在一个字节后,立即从从机读数据。(3)在传送过程中,当需要改变传送方向时,需将起始信号和从机地址各重复一次,而两次读/写方向位正好相反。单片机在模拟I2C总线通信时,需写出如下几个关键部分的程序:总线的初始化,启动信号,应答信号,停止信号,写一个字节,读一个字节。下面分别给出具体函数的写法供大家参考。1,总线的初始化voidmain(){9SCL=1;delay();SDA=1;delay();}将总线都拉高以释放总线。2,启动信号Voidstart(){SDA=1;Delay();SCL=1;Delay();SDA=0;Delay();}SCL在高电平期间,SDA一个下降沿启动信号。3,应答信号voidrespons(){Uchari=0;SCL=1;10Delay();While((SDA==1)&&(i255))I++;SCL=0;Delay();}SCL在高电平期间,SDA被从设备拉为低电平表示应答。上面代码中有一个(SDA==1)和(i255)想与的关系,表示若在一段时间内没有收到从器件的应答则主器件默认从器件已经收到数据而不再等待应答信号,(不必深究),如果不加这个延时退出,一旦从器件没有发送应答信号,程序将永远停止在这里,而真正的程序中不允许这样的情况发生的。4,停止信号Voidstop(){SDA=0;Delay();SCL=1;Delay();SDA=1;Delay();}11SCL在高电平期间,SDA一个上升沿停止信号。5,写一个字节Voidwritebyte(uchardata){Uchari,temp;Temp=data;For(i=0;i8;i++){Temp=temp1;SCL=0;Delay();SDA=CY;Delay();SCL=1;Delay();}SCL=0;Delay();SDA=1;Delay();}串行发送一个字节时,需要把这个字节中的8位一位一位地发出12去,“temp=temp1;”表示将temp左移一位,最高位将移入PSW寄存器的CY位中,然后将CY赋给SDA进而在SCL的控制下发送出去。6,读一个字符Ucharreadbyte(){Uchari,k;SCL=0;Delay();SDA=1;For(i=0;i8;i++){SCL=1;Delay();K=(k1)|SDA;SCL=0;Delay();}Delay();Returnk;}串行接收一个字符时需将8位一位一位的接收,然后再组合成一个字节,上面代码中我们定义了一个临时变量K,将K左移一位后与13SDA进行“或”运算,依次把8个独立的位放入一个字节中来完成接收。三,E2PORMAT24C02与单片机的通信实例1,AT24C02引脚配置与引脚功能AT24C02芯片的常用封装形式有直插(DIP8)式和贴片(SO-8)式两种,。各引脚功能如下:1,2,3(A0,A1,A2)——可编程地址输入端。4(GND)——电源地5(SDA)——串行数据输入/输出端。6(SCL)——串行时钟输入端。7(WP)——写保护输入端,用于硬件数据保护。当其为低电平时,可以对整个存储器进行正常的读/写操作;当其为高电平时,存储器具有写保护功能,但读操作不受影响。8(VCC)——电源正端。2,存储器结构与寻址AT24C02的存储空间为2KB,内部分成32页,每页8B,共256B,操作时有两种寻址方式:芯片寻址和片内子地址寻址。(1),芯片寻址。AT24C02的芯片地址为1010,其地址控制字格14式为1010A2A1A0R/——W。其中A2,A1,A0为可编程地址选择位。A2,A1,A0引脚接高,低电平后得到确定的单位编码,与1010形成7位编码,即为该器件的地址码。R/——W为芯片读写控制位,该位为零,表示对芯片进行写操作;该位为一,表示对芯片进行读操作。(2)片内子地址寻址。芯片寻址可对内部256B中任一个进行读/写操作,其寻址范围为00-FF,共256个寻址单元。例程:仿真图:程序如下:#includereg52.h#defineucharunsignedchar#defineuintunsignedintbitwrite=0;//写24C02的地址15sbitsda=P2^0;//定义数据线sbitscl=P2^1;//定义时钟线sbitwe1=P2^2;//数码管位选一sbitwe2=P2^3;//数码管位选二uchartcnt,sec;//定义两个参数uchartable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,160x71};//数码管显示数组voiddelay()//微秒级延时{;;}voiddelay1ms(uintz)//延时函数{uintx,y;for(x=z;x0;x--)for(y=110;y0;y--);}/****************/voidstart()//开始信号{sda=1;//SCL在高电平期间,SDA一个下降沿启信delay();号scl=1;//时钟线拉高delay();sda=0;//数据线拉低delay();}17/***************/voidstop()//停止{//SCL高电平期间,SDA一个上升沿启动停止信sda=0;//数据线拉低号delay();scl=1;//时钟线拉高delay();sda=1;//数据线拉高delay();}/************/voidrespons()//应答信号{//时钟线在高电平期间,数据线被拉低uchari;//表示应答scl=1;//时钟线拉高delay();while((sda==1)&&(i250))i++;//SDA==1说明没18有应答与上(i《250)i++只要有一个为假就会退出scl=0;//时钟线拉低delay();}/****************/voidinit()//初始化{sda=1;//数据线被拉高delay();scl=1;//时钟线被拉高delay();}/******************/voidwrite_byte(uchardate)//写入一个字节{uchari,temp;temp=date;for(i=0;i8;i++)//时钟线高电平期间,数据线上数据{//必须保持稳定,时钟线为低电平期间temp=temp1;//数据线上数据才允许改变19scl=0;//时钟线拉低delay();sda=CY;//最高位送入CYdelay();scl=1;时钟线拉高delay();}scl=0;delay();sda=1;delay();}/****************/ucharread_byte()//读一个字节{uchari,k;scl=0;//时钟线拉低delay();sda=1;//数据线拉高delay();for(i=0;i8;i++){20scl=1;delay();k=(k1)|sda;scl=0;delay();}returnk;}/**************************/voidwrite_add(ucharaddress,uchardate){//写一个数据start();//开始函数write_byte(0xa0);//写入地址10100000respons();//等待回复write_byte(address);//写入地址respons();//等待回复write_byte(date);//写入数据respons();//等待回复stop();//停止信号}/*******************/ucharread_add(ucharaddress)//读一个数据