AT24C02提供2024位的连续的可擦除的可编程的只读的存储器(即我们所说的EEPROM了,实质是一个断电数据不丢失的存储器),有共256字节的内部存储空间,就也是说有256个内部存储空间的地址,地址长度有8位。
IIC总线只有2根信号线,一根是数据线SDA,一根是时钟线SCL。SDA和SCL均为双向信号线,通过上拉电阻接正电源。当总线空闲时,两根线都是高电平。连接到总线上的任一器件,输出低电平,都将使总线的信号变低。
连接总线的器件输出级必须是集电极或漏极开路,以形成线“与”功能。
每个具有IIC接口的设备都有一个唯一的地址,也叫做设备地址。
数据位的有效性定义
IIC总线在进行数据传送时,时钟信号SCL为高电平期间,数据线SDA上的数据必须保持稳定。只有在时钟信号为低电平期间,数据线上的数据才允许变化。
IIC总线数据传输规范
在数据的传输过程中,必须确认数据传送的开始和结束。在IIC总线规范中,规定了起始信号和停止信号。
起始信号:当时钟线SCL为高电平时,数据线SDA由高变低。
停止信号:当时钟线SCL为高电平时,数据线SDA由低变高。
在起始信号以后,IIC总线就被认为是处于忙状态,直到停止信号以后的几个时钟周期,IIC总线才被认为重新处于空闲状态。 在起始信号之后,必须是器件的控制字节,也即是设备地址,其中高4位是器件的类型识别符(EEPROM的识别符为1010),接着3位是片选信号,最后1位是读写控制位,读操作为1,写操作为0。
对于EEPROM器件来说,如果片选信号为000,则:
读操作的设备地址为:0xA1。
写操作的设备地址为:0xA0。
IIC总线每次传送的数据字节不限,每一个字节必须是8位。数据传送时,必须先送最高位(MSB),每个数据字节后面都有一个确认位,也就是应答(ACK)
IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到。应答信号由接收方在数据开始后的第9个时钟周期发送,在SCL为高电平期间,接收方将SDA拉为低电平产生应答,用来结束一个字节的传输。也就是说,一帧完整的数据共有9位。
#include <STC15F2K60S2.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SCL = P2^0;
sbit SDA = P2^1;
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar yi,er,san,si,wu ,liu,qi,ba;
void Delay1ms(uint z);
void display1(uchar yi,uchar er);
void display2(uchar san,uchar si);
void display3(uchar wu,uchar liu);
void display4(uchar qi,uchar ba);
void allinit();
void iicstart();
void iicstop();
void writebyte(uchar dat);
uchar iicreadbyte();
void iicdelay(uchar m);
uchar ack();
void iicwrite(uchar add,uchar dat);
uchar iicread(uchar add);
void main()
{
uchar num;
allinit();
yi=11;er=11;san=11;si=11;wu=11;liu=0;qi=0;ba=0;
//iicwrite(0x00,0);//初始化 写入的地址 要写的字节 只在第一次写入0,烧录之后注释在进行第二次烧录
num=iicread(0x00);
iicwrite(0x00,num+1);//+1之后再存入原来地址
while(1)
{
liu=num/100;qi=num%100/10;ba=num%10;
display1(yi,er);
display2(san,si);
display3(wu,liu);
display4(qi,ba);
}
}
void iicstart()//开启iic,总线启动条件
{
SDA=1;
_nop_();
SCL=1;
_nop_();
SDA=0;
_nop_();
SCL=0;
_nop_();
}
void iicstop()//关闭iic,总线停止条件
{
SDA=0;
_nop_();
SCL=1;
_nop_();
SDA=1;
_nop_();
}
void writebyte(uchar dat)//写字节操作
{
uchar i;
for(i=0;i<8;i++)
{
SCL=0;//时钟线为0可以进行数据线操作
SDA=dat&0x80;//进行写操作
SCL=1;
dat<<=1;
}
SCL=0;
}
uchar iicreadbyte()//读字节操作
{
uchar dat;
uchar i;
for(i=0;i<8;i++)
{
SCL=1;
dat<<=1;
if(SDA)
{
dat|=0x01;//进行读操作
}
SCL=0;
}
return dat;
}
void iicdelay(uchar m)//延迟,防止读取时间不够
{
do
{
_nop_();
}
while(m--);
}
uchar ack()//等待eeprom应答
{
SCL=1;
iicdelay(5);
if(SDA==1)//释放总线
{
SCL=0;
iicstop();
return 0;//读取或写入数据成功,SDA返回0
}
else
{
SCL=0;
return 1;
}
}
void iicwrite(uchar add,uchar dat)
{
iicstart();
writebyte(0xa0);//0xa0,告知单片机进行写操作
ack();
writebyte(add);//写入地址add
ack();
writebyte(dat);//写入数据dat
ack();
iicstop();
}
uchar iicread(uchar add)
{
uchar temp;
iicstart();
writebyte(0xa0);////0xa0,告知单片机设备地址并进行写操作
ack();//等待响应
writebyte(add);//数据地址
ack();
iicstop();
iicstart();
writebyte(0xa1);//0xa1,告知单片机设备地址并进行读操作
ack();
temp=iicreadbyte();//每位读取字节
iicstop();
return temp;
}
void Delay1ms(uint z) //@12.000MHz
{
unsigned char i, j;
uint k;
for(k=z;k>0;k--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
void display1(uchar yi, uchar er)
{
//开位选
P2=0XC0;
P0=0X01;
//开段选
P2=0XFF;
P0=tab[yi];
Delay1ms(1);
//开位选
P2=0XC0;
P0=0X02;
//开段选
P2=0XFF;
P0=tab[er];
Delay1ms(1);
}
void display2( uchar san,uchar si)
{
//开位选
P2=0XC0;
P0=0X04;
//开段选
P2=0XFF;
P0=tab[san];
Delay1ms(1);
//开位选
P2=0XC0;
P0=0X08;
//开段选
P2=0XFF;
P0=tab[si];
Delay1ms(1);
}
void display3(uchar wu, uchar liu)
{
//开位选
P2=0XC0;
P0=0X10;
//开段选
P2=0XFF;
P0=tab[wu];
Delay1ms(1);
//开位选
P2=0XC0;
P0=0X20;
//开段选
P2=0XFF;
P0=tab[liu];
Delay1ms(1);
}
void display4(uchar qi, uchar ba)
{
//开位选
P2=0XC0;
P0=0X40;
//开段选
P2=0XFF;
P0=tab[qi];
Delay1ms(1);
//开位选
P2=0XC0;
P0=0X80;
//开段选
P2=0XFF;
P0=tab[ba];
Delay1ms(1);
}
void allinit()
{
P2=0X80;P0=0XFF;//关led
P2=0XC0;P0=0XFF;
P2=0XFF;P0=0XFF;//关数码管
P2=0XA0;P0=0X00;//蜂鸣器,继电器
}
PCF8951 与EEPROM操作基本一致,仅仅地址不同
写入为0X90
读取为0X91