24C01/02/04/08/16是低工作电压的1K/2K/4K/8K/16K 位串行电可擦除只读存储器,内部组织为128/256/512/1024/2048 个字节,每个字节8位,该芯片被广泛应用于低电压及低功耗的工商业领域。
AT24C02存储器写操作需要在给出开始态、器件地址和确认之后,紧跟着给出一个8位数据地址。一经收到该地址,EEPROM就通过 SDA发出确认信号,并随时钟输入8位数据。在收到8位数据之后,EEPROM 将向SDA确认,数据传送设备必须用停止状态来终止写操作,这时,EEPROM进入一个内计时固定存储器写入周期。在该写周期时,所有输入被禁止,EEPROM直到写完后才应答,写字节时序如图所示。
中文版:
英文版:
1KB/2KB EEPROM能进行8字节页面写入,4KB、8KB和16KB设备能进行16字节页面写入。
激发写页面与激发写字节相同,只是数据传送设备无须在第一个字节随时钟输入之后,发出一个停止状态。在 EEPROM确认收到第一个数据之后,数据传送设备能再传送7个(1KB、2KB)或15个(4KB、8KB、16KB)数据,每一个数据收到之后,EEPROM都将通过SDA回送一个确认信号,最后数据传送设备必须通过停止状态终止页面写序列。
英文版:
中文版
除了器件地址码中读/写选择位置1,读操作与写操作是一样的。读操作有三种:立即地址读取、随机地址读取和顺序读取。
内部数据字地址指针保持在读写操作中最后访问的地址,按“1”递增。只要芯片保持上电,该地址在两个操作之间一直有效,如果最后一个操作是在地址n处读取,则立即地址是n+1;如果最后操作是在地址n处写入,则立即地址也是n+1。
随机读取需要一个空字节写序列来载入数据地址一旦器件地址码和数据码地址码时钟输入,并被EEPROM确认,数据传送设备就必须产生另一个开始条件。读/写选择位处于高电平时,通过送出一个器件地址,数据传送设备激发出一个立即寻址读取,EEPROM确认器件地址,并随时钟串行输出数据。器件读数据不通过确认(使SDA总线处于高电平)应答,而通过产生一个停止条件应答。
顺序读取由立即地址读取或随机地址读取激发,在读数据器件收到一数据码之后,通过确认应答,只要EEPROM收到确认之后,便会继续增加数据码地址及串行输出数据码。当达到存储器地址极限时,数据码地址将重复滚动,顺序读取将继续。当读数据器件不通过确认(使SDA总线处于高电平)应答,而通过产生一个停止条件应答时,顺序读取操作被终止。
将开机次数存储在 AT24CO2中,范围0~100,并通过数码管显示出来。
mian.c
#include "STC15F2K60S2.h"
#include "iic.h"
#include "intrins.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uchar dsp_code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar dsp_dat[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
uchar dat;
void time0_init()
{
AUXR |= 0x80;
TMOD &= F0;
TL0=0XCD;
TH0=0XD4;
TR0=1;
ET0=1;
EA=1;
}
void time0_isr() interrupt 1
{
static uchar dsp_com = 0;
P0=0,P2=0xc0,P2=0;
P0=dsp_dat[dsp_com],P2=0xe0,P2=0;
P0=1<<dsp_com,P2=0xc0,P2=0;
if(++dsp_com==8) dsp_com=0;
}
void Delay300ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 13;
j = 156;
k = 83;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
int main()
{
uchar i;
P0=0xff,P2=0x80,P2=0;
P0=0x00,P2=0xa0,P2=0;
Delay300ms(); //电源按键延时
dat = read_dat(0x00);
if(dat>99) dat=0;
wirte_dat(0x00,++dat);
//在连续多次写入时需加延时5ms
time0_init();
while(1)
{
if(dat>9) dsp_dat[6]=dsp_code[dat/10];
else dsp_dat[6]=0xff;
dsp_dat[7]=dsp_code[dat%10];
}
while(1);
}
iic.c
#include "iic.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//void IIC_SendAck(bit ackbit)
//{
// SCL = 0;
// SDA = ackbit;
// IIC_Delay(DELAY_TIME);
// SCL = 1;
// IIC_Delay(DELAY_TIME);
// SCL = 0;
// SDA = 1;
// IIC_Delay(DELAY_TIME);
//}
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
IIC_WaitAck(); //直接将等待应答函数写到此处
// 后面写读取函数or 转换函数时就不用一直重复写这个函数
}
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
IIC_WaitAck(); //直接将等待应答函数写到此处
// 后面写读取函数or 转换函数时就不用一直重复写这个函数
return da;
}
//注意∶写设备和读设备地址只相差1
unsigned char read_dat(unsigned char add)
{
unsigned char dat;
IIC_Start();
IIC_SendByte(0xa0); // MCU 向AT24c02发送"写设备"命令
IIC_SendByte(add);
IIC_Start();
IIC_SendByte(0xa1); //MCU 向 AT24c02发送"读设备"命令
dat =IIC_RecByte(); //读取 A/D转换值 0-255
IIC_Stop();
return dat;
}
void wirte_dat(unsigned char add,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0); // MCU 向AT24c02发送"写设备"命令
IIC_SendByte(add);
IIC_SendByte(dat);
IIC_Stop();
}
iic.h
#ifndef _IIC_H
#define _IIC_H
#include
#include "intrins.h"
sbit SDA = P2^1;
sbit SCL = P2^0;
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
unsigned char read_dat(unsigned char add); //这个自己加上的
void wirte_dat(unsigned char add,unsigned char dat);
#endif