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通信协议详细文档连接
|