I2C串行总线协议

一、I2C串行总线概述

I2C总线是PHILIPS公司推出的一种串行信息总线,用于连接微控制器及外围设备,是具备多主系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。

I2C总线只有两根双向信号线,一根是数据线SDA,一根是时钟线SCL。单片机与I2C器件连接如下图所示:

 

 

每个连接到I2C器件都有唯一的地址,这个地址是由I2C器件硬件连接决定的。

 

二、I2C串行总线工作原理

1、I2C总线上数据的有效性

I2C总线以串行方式传输数据,从数据字节的高位开始传输,每一个数据位在SCL上都有一个时钟脉冲相对应。在一个时钟周期内,当时钟信号为高电平时数据线上的数据必须保持稳定,当时钟信号为低电平时,才允许数据的变化。如下图所示:

 

 

 2、I2C总线上的信号

I2C总线在数据传输过程中共有4种类型信号,分别为开始信号、停止信号、重新开始信号和应答信号。

开始信号:当SCL为高电平时,SDA线由高电平向低电平跳变即为开始信号。

停止信号:当SCL为高电平时,SDA线由低电平向高电平跳变即为停止信号。

 

重新开始信号:在I2C总线上,由主机发送一个开始信号启动一次通信后,在首次发送停止信号之前,主机发送开始信号即为重新开始信号。

应答信号:接受数据的IC在接收到8位数据后,向发送数据的IC发出特地的低电平脉冲。每一个数据字节后面都跟有一位应答信号,表示已接收到数据。应答信号在第9个时钟周期出现,这时发生器必须在这一时钟位上释放数据线,通过接收设备拉低SDA产生应答,保持SDA高电平产生非应答。

3、I2C总线上的数据传输格式

一般情况下,一个标准的I2C通信通常由4部分组成:开始信号、从机地址传输、数据传输和结束信号。

数据传输开始时,先是主机发送一个开始信号,启动I2C通信,在主机对从机寻址后,再在总线上传输数据,I2C总线上传输的每一字节均为8位,高位在前、低位在后,每传送1字节后必须跟随一个应答位,每次的数据字节没有限制,在全部数据传送结束后,主机发出停止信号,结束通信。

4、I2C总线上的寻址约定

在I2C总线系统中,寻址字节由从机的7位地址为(D7~D1位)和1位方向位(D0)组成。方向位为“0”时,表示主机将数据写入从机;为“1”时,表示主机从从机读取数据。

5、主机向从机读/写1字节数据的过程

主机写字节时,首先产生开始信号,然后发送一个7位的从机地址和将方向位清零。这时候主机等待从机的应答信号,当主机接收到应答信号时,发送要访问的地址,继续等待,应答后接着发送1字节数据,等待到应答并产生停止信号,传输过程结束。如下图所示

 

 

主机读数据时,首先产生启动信号,然后发送一个7位的从机地址并将方向位清零,等待应答后,发送要访问的地址,等待应答后重新发送开始信号,然后发送一个7位地址并将方向位置“1”,这时候主机等待从机的应答,应答后,就可以接收一字节的数据;当接收完成后,主机发送非应答信号,主机产生停止信号,传输过程结束。如下图所示:

 

 

三、8051与AT24C02相连接

 

 

四、程序设计

本程序是先向24C02写进数据,接着从24C02读出来,并将传到P2,形成流水灯现象:

#include<reg52.h>

#include<intrins.h>

#define uint unsigned int

#define uchar unsigned char

sbit SCL=P3^0;

sbit SDA=P3^1;

void delay5us()   // 延时大于4.7us   

{

   _nop_();_nop_();_nop_();_nop_();_nop_();   

}

void delayms(uint z)

{

   uint x,y;

   for(x=0;x<110;x++)

       for(y=0;y<z;y++);

}

void IIC_start()

{

   SDA=1;

   SCL=1;              //在SCL为高电平期间,将SDA由高电平跳到低电平

   delay5us();

   SDA=0;

   delay5us();

   SCL=0;

}

void IIC_stop()

{

   SDA=0;

   SCL=1;            //在SCL为高电平期间,将SDA由低电平跳到高电平

   delay5us();

   SDA=1;

   delay5us();

   SCL=0;

}

void IIC_ACK(bit temp)

{

   SDA=temp;           //在第9个时钟周期,产生应答/非应答

   delay5us();

   SCL=1;

   delay5us();

   SCL=0;

}

void IIC_write_byte(uchar temp)

{

   uchar i;

   for(i=0;i<8;i++)

   {

        SCL=0;

        _nop_();_nop_();_nop_();

      SDA=(bit)(temp&0x80);        //上升沿发送数据

        temp<<=1;

        delay5us();

        SCL=1;

        delay5us();

   }

   SCL=0;

}

uchar IIC_read_byte()

{

   uchar i,temp=0;

   for(i=0;i<8;i++)

   {

         SCL=0;

         _nop_();_nop_();_nop_();

         SDA=1;

         delay5us();

         SCL=1;                //下降沿接收数据

         delay5us();

         temp<<=1;

         if(SDA)temp+=1;

   }

   SCL=0;

   return temp;

}

void main()

{

   uchar table[4],i;

   IIC_start();

   IIC_write_byte(0xa0);        //发送从机地址

   IIC_ACK(0);

   IIC_write_byte(0x01);        //发送访问地址

 

   IIC_ACK(0);

   IIC_write_byte(0x01);        //发送数据

 

   IIC_ACK(0);

   IIC_write_byte(0x02);        //发送数据

 

   IIC_ACK(0);

   IIC_write_byte(0x04);        //发送数据

 

   IIC_ACK(0);

   IIC_write_byte(0x08);            //发送数据

 

   IIC_ACK(1);

   IIC_stop();

   delayms(1000);       

 

   IIC_start();

   IIC_write_byte(0xa0);        //发送从机地址

   IIC_ACK(0);

   IIC_write_byte(0x01);        //发送访问地址

   IIC_ACK(0);

   IIC_start();                               //重新开始信号

   IIC_write_byte(0xa1);

   IIC_ACK(0);

   table[0]=IIC_read_byte();       //接收数据

   IIC_ACK(0);

 

   table[1]=IIC_read_byte();       //接收数据

   IIC_ACK(0);

 

   table[2]=IIC_read_byte();       //接收数据

   IIC_ACK(0);

 

   table[3]=IIC_read_byte();         //接收数据

   IIC_ACK(0);

 

   IIC_stop();                                     //停止信号

   while(1)

   {

       for(i=0;i<4;i++)

         {

            P2=table[i];

               delayms(300);

         }

         P2=0XFF;

   }

}

posted @ 2013-03-18 19:51  天涯海角路  阅读(290)  评论(0)    收藏  举报