SCL(clock)时钟信号
SDA(data)数据总线
数据位的有效性规定
I²C总线进行数据传输时,时钟信号为高电平期间。数据总线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或者低电平状态才允许变化。
时序图
起始信号和终止信号
当时钟信号高电平,
SDA变低电平,为起始信号,若SDA变高电平,为终止信号
起始信号产生后 ,总线处于占用状态
终止信号产生后,总线处于空闲状态
void start()//起始信号
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop()//终止信号
{
sda=0;
delay();
scl=1;
delay();
sda=0;
delay();
}
数据传送格式
(1)字节传送与应答
一帧=一个字节+应答位=9位,一个字节八位,第九位是应答位
从机如果接收不了信号,就将SDA数据线置于高电平 ,中断通信;若主机要中断通信,就要发送一个终止信号,从机应答,就能终端通信。
void responds()//应答信号
{
uchar i;
scl=1;
delay();
while((sda==1)&&(i<250))i++;
scl=0;
delay();
}
(2)数据帧格式
灰色为主机 白色为从机
发送数据
在起始信号后必须传送一个从机地址(7位),第八位是数据的传送放方向位(R/T),0表示主机发送数据给从机T(transmit),1表示主机接受从机数据R(receive)
读数据
E²PROM
这里用的是AT24C02
- 芯片地址1010(固定的)
- 地址控制字格式1010 A2A1A0 R/W, A2 A1 A0接高低电平后得到三位确定的编码,和1010形成确定的7位编码,即地址码。R/W为芯片读写控制位,0表示写操作,1表示读操作。(为了便于观察最后一位0或1,我们这里的A2A1A0全都接地)
- 片内子地址寻址:有256个,地址码相当于大楼的地址,子地址相当于大楼内的每一个房间号,0-255,共256个
字节写入方式
void write_byte(uchar date)//写地址
{
uchar i,temp;
temp=date;
scl=0;
delay();
for(i=0;i<8;i++)
{
temp=temp<<1;
sda=CY;//最高位
delay();
scl=1;
delay();
scl=0;
delay();
}
sda=1;
delay();
}
接下来解释补充
- 左移:最高位向左移动,移入PSW的CY位,最低位补0;右移最低位移除,最高位保留。
temp=temp<<1;//左移一位
- 数据是一个一个送出来的,具体如下
指定地址读操作
start();//启动
write_byte(0xa0);//器件地址+写
responds();//应答
write_byte(3);//子地址
responds();//应答
start();//这里要多一个应答
write_byte(0xa1);//器件地址+读
responds();//应答
P1=read_byte();//赋值
stop();//停止
while(1);
其中read_byte 具体如下
uchar read_byte()
{
uchar i,j,k=0;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
j=sda;
k=(k<<1)|j;
scl=0;
delay();
}
return k;
}
-
k的起始数值为0,相当于0000 0000B
-
或运算,有1为1,全0位0
-
对于 “ k=(k<<1) | j; ”解释如下
具体事例
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit sda=P2^0;
sbit scl=P2^1;
void delay()
{
;;
}
void delay1(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=100;y>0;y--);
}
void start()//ÆðʼÐźÅ
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop()//ÖÕÖ¹ÐźÅ
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
void responds()//Ó¦´ðÐźÅ
{
uchar i=0;
scl=1;
delay();
while((sda==1)&&(i<255))
i++;
scl=0;
delay();
}
void write_byte(uchar date)//дµØÖ·
{
uchar i,temp;
temp=date;
scl=0;
delay();
for(i=0;i<8;i++)
{
temp=temp<<1;
sda=CY;//×î¸ßλ
delay();
scl=1;
delay();
scl=0;
delay();
}
sda=1;
delay();
}
uchar read_byte() //¶ÁÊý¾Ý
{
uchar i,j,k=0;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
j=sda;
k=(k<<1)|j;
scl=0;
delay();
}
return k;
}
void init()
{
scl=1;
sda=1;
}
void write_add(uchar address, uchar date)
{
start();//ÆðʼÐźÅ
write_byte(0xa0);//Æ÷¼þµØÖ· ¸ßËÄλ¹Ì¶¨1010 0±íʾҪд device adress
responds();
write_byte(address);//д 0-256 word adress
responds();
write_byte(date);//data
responds();
stop();
}
uchar read_add(uchar address)
{
uchar date;
delay1(100);
start();
write_byte(0xa0);//µØÖ·
responds();
write_byte(address);
responds();
start();//»»·½Ïò
write_byte(0xa1);//Æ÷¼þµØÖ· ºóÃæ±ä1 ÒòΪÊǶÁ
responds();
date=read_byte();
stop();
return date;
}
void main()
{
init();//³õʼ»¯
write_add(23,0xaa);
delay1(100);
P1=read_add(23);
while(1);
}