| I2C通信以及51单片机程序I2C总线是PHLIPS公司推出的一种双向串行总线,只有两根双向信号线。一根是数据/地址线SDA,另一根是时钟线SCL,半双工。这两根信号线上挂载着主机与从机,一般来说,谁控制SCL信号线,谁就是主机。
 1、空闲状态: 两根总线接上拉电阻,且都为高电平时,说明两根总线为空闲状态。
 2、8位数据传输:
 
  规则: I2C总线进行数据传送时,SCL为高电平期间,SDA上的数据必须保持稳定,只有在SCL上的信号为低电平期间,SDA上的高电平或低电平状态才允许变化。
 就看这张图,下面一边介绍原理一边写程序:
 (1)起始信号,既然是两根信号线来传输数据,那么就需要协议,也就是I2C协议,此协议包括起始信号,如上图所示,当SCL为高电平时,SDA由高电平变为低电平时,表示可以传输数据了,也就是所谓的起始信号
 那么程序怎么写?很简单,基于51单片机的起始信号程序如下:
 void startiic()
{
SDA=1;
delay();
delay();
SCL=1;
delay();
SDA=0;
delay();
SCL=0;
delay();
}
 注意:开始信号结束后,SCL信号线为低电平(2)有了起始信号,接着就可以传输数据了,需要注意的是,数据传输从高位开始到低位传输结束,一共8位数据,开始信号结束后,SCL信号线为低电平,那么传输数据里的读数据程序第一步就要将SCL电平拉高,保持数据信号线上的数据可读,且读8位
 51单片机的读8位数据程序如下:
 unsigned char readbit8()
{
unsigned char i;
unsigned char dat=0;
for(i=0;i<8;i++)
{
SCL=1;
dat<<=1;
dat|=(unsigned char)SDA;
SCL=0;
delay();
}
return(dat);
}
 注意:8位的数据传输完毕后,SCL的电平状态为低电平我们再来看一下写数据程序应该如何写,首先数据信号线要改变电平状态,SCL的电平要为低电平,所以写数据的程序第一步就是SCL的电平状态要先拉低,当我们的起始信号开始后,SCL的电平信号正好为低,那么只需写一句SDA=(bit)(dat&0x80);就把dat变量的最高位传递给SDA了,接下来将SCL拉高保持数据稳定,再拉低使数据可以改变,从而在稳定状态时实现传输
 51单片机的写8位数据的程序如下:
 void writebit8(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
SDA=(bit)(dat&0x80);
delay();
SCL=1;	
dat<<=1;
delay();
SCL=0;
}	
}
 注意:8位的数据传输完毕后,SCL的电平状态为低电平(3)数据传输完毕之后,需要有个应答信号,表示8位的数据已经传输完毕,在SCL的信号线为低电平的情况下拉高SDA信号线,实质上是主机释放SDA线的控制权,将控制权交给从机,如果从机将SDA信号线拉低,说明8位数据已经正常传输
 51单片机的应答信号的程序如下:
 bit ack()
{
	
bit a;
SDA=1;
SCL=1;
delay();	
a=SDA;
SCL=0;
return(a);
	
}
 注意:应答信号完毕后,SCL的电平状态为低电平3、I2C总线器件的地址
 为什么要了解I2C总线器件的地址呢?因为主机要想传送数据给从机必须要知道它的地址才能传送。
 I2C总线是由数据线SDA 和时钟线SCL构成的串行总线,可发送和接受数据。在单片机与被控器件之间、器件与器件之间均可进行双向信息传送。器件地址共7位,它与方向位构成了I2C总线器件的寻址字节SLA。
 
  I . DA3 DA2 DA1 DA0:器件地址位,是I2C总线外围接口器件固有的地址编码,器件出厂时就给定了(使用者不能改变)。如I2C总线器件AT24CXX系列器件的地址为1010。
 II. A2 A1 A0:引脚地址位,是由I2C总线外围器件的地址端口根据接地或电源的不同而形成的地址数据(由使用者控制)。
 III.R/W:数据方向位。R/W=1时,为接收(读出);R/W=0时,为发送(写入)。
 AT24C02的芯片地址(0xa0为写,0xa1为读)
 4、51单片机与AT24C02通讯的数据传输程序
 读数据:读数据就是先寻找从机器件地址,然后再寻找器件的寄存器地址,然后再从寄存器里把数据读出来 ,程序如下:
 unsigned char  readdate(unsigned char address)
{  
  
  unsigned char dat;
	 startiic();
	writebit8(WRITECOMDE);
	 ack();	  
	 writebit8(address); 
	 ack();	 
	 startiic();
	writebit8(READCOMDE);
	 ack();	  
	dat=readbit8();
	 stopiic(); 
	 return dat;
}
 写数据:写数据就是先寻找从机器件地址,然后再寻找器件的寄存器地址,然后再把数据写进寄存器里 ,程序如下: void writedate(unsigned char address,unsigned dat)
{
   startiic();
	 writebit8(WRITECOMDE);
	 ack();	  
	 writebit8(address); 
	 ack();	 
	 writebit8(dat);
	 ack();	  
	 stopiic();
	 delaynms(2);
}
 5、51单片机与AT24C02通讯的电路图
   6、51单片机与AT24C02通讯的完整程序
 #include <reg51.h>        
#include <intrins.h>      
#define	READCOMDE	  0xa1		
#define	WRITECOMDE  0xa0		
sbit SDA=P3^4;          
sbit SCL=P3^3;         
unsigned char code table[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
  void delay1ms()
{
   unsigned char i,j;	
	 for(i=0;i<10;i++)
	  for(j=0;j<33;j++);		 
 }
 void delay()
{ ;; }
void delaynms(int n)
 {
   int i;
	for(i=0;i<n;i++)
	   delay1ms();
 }
void startiic()
{
SDA=1;
delay();
delay();
SCL=1;
delay();
SDA=0;
delay();
SCL=0;
delay();
}
unsigned char readbit8()
{
unsigned char i;
unsigned char dat=0;
for(i=0;i<8;i++)
{
SCL=1;
dat<<=1;
dat|=(unsigned char)SDA;
SCL=0;
delay();
}
return(dat);
}
void writebit8(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
SDA=(bit)(dat&0x80);
delay();
SCL=1;	
dat<<=1;
delay();
SCL=0;
}	
}
bit ack()
{
	
bit a;
SDA=1;
SCL=1;
delay();	
a=SDA;
SCL=0;
	
	return(a);
	
}
void stopiic()
{
SDA=0;
delay();
SCL=1;	
delay();
SDA=1;
delay();
}
unsigned char  readdate(unsigned char address)
{  
  
  unsigned char dat;
	 startiic();
	writebit8(WRITECOMDE);
	 ack();	  
	 writebit8(address); 
	 ack();	 
	 startiic();
	writebit8(READCOMDE);
	 ack();	  
	dat=readbit8();
	 stopiic(); 
	 return dat;
}
void writedate(unsigned char address,unsigned dat)
{
   startiic();
	 writebit8(WRITECOMDE);
	 ack();	  
	 writebit8(address); 
	 ack();	 
	 writebit8(dat);
	 ack();	  
	 stopiic();
	 delaynms(2);
}
void main()
{
	 
	  unsigned char k;
    unsigned char i;
while(1)
{
	for(i=0;i<8;i++)
	{
	   writedate(8,table[i]);
	   k=readdate(8);
	   P1=k; 
		delaynms (1000);
	}
	 i=0;
}
}
 7、详细文档I2C通信协议详细文档连接
 |