应用笔记AT24Cxx系列EEPROM应用笔记
sungangb@https://www.doczj.com/doc/753874040.html,
AT24Cxx系列EEPROM应用笔记
1.概述
EEPROM指的是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。
它的最大优点是可直接用电信号擦除,也可用电信号写入。EEPROM不能取代RAM的原因是其工艺复杂,耗费的门电路过多,且重编程时间比较长,同时其有效重编程次数也比较低。
EEPROM根据数据总线的不同分为串行和并行两种。
首先介绍一下串行EEPROM,按照串行总线的不同,可以分为I2C?总线兼容系列、Microwire?总线兼容系列和SPI?总线兼容系列,如表1所示。
表 1 串行EEPROM的分类
下面以I2C系列中的24C64为例详细介绍I2C系列EEPROM的具体操作和使用。
2.特点
A T24Cxx系列EEPROM是由美国Mcrochip公司出品,1-512K位的支持I2C总线数据传送协议的串行CMOS E2PROM,可用电擦除,可编程自定时写周期(包括自动擦除时间不超过10ms,典型时间为5ms)的。串行E2PROM一般具有两种写入方式,一种是字节写入方式,还有另一种页写入方式。允许在一个写周期内同时对1个字节到一页的若干字节的编程写入,1页的大小取决于芯片内页寄存器的大小。其中,A T24C01具有8字节数据的页面写能力,A T24C02/04/08/16具有16字节数据的页面写能力,A T24C32/64具有32字节数据的页面写能力。
A T24Cxx系列EEPROM的特点如下:
?低电压和标准电压应用
5.0 (VCC = 4.5V to 5.5V)
2.7 (VCC = 2.7V to 5.5V)
2.5 (VCC = 2.5V to 5.5V)
1.8 (VCC = 1.8V to 5.5V)
?低功耗
? 两线串行接口
?双向数据传输协议
?100 kHz (1.8V, 2.5V, 2.7V) ,400 kHz (5V)兼容
? 写保护管脚
? 32-Byte页写模式
? 可编程自定时写周期(包括自动擦除时间不超过10ms,典型时间为5ms)
? 高可靠性
可读写次数: 1 Million Cycles
数据保存: 100年
? 8-Pin JEDEC PDIP, 8-Pin and 14-Pin JEDEC SOIC and 8-Pin EIAJ Packages
3.管脚描述
A T24Cxx系列E2PROM提供标准的8脚DIP封装和8脚表面安装的SOIC封装。
A T24C32/64管脚排列图分别如下图(图1)所示,其管脚功能描述如表(表2)所示。
图 2 管脚排列图
表 3 管脚功能
SCL:串行时钟
这是一个输入管脚,用于产生器件所有数据发送或接收的时钟。
SDA:串行数据/地址
这是一个双向传输端,用于传送地址和所有数据的发送或接收。它是一个漏极开路端,因此要求接一个上拉电到Vcc端(典型值为:100KHz是为10K,400KHz时为1K)。对于一般的数据传输,仅在SCL为低期间SDA才允许变化。在SCL为高期间变化,留给指示START(开始)和STOP(停止)条件。
A0、A1、A2:器件地址输入端
这些输入端用于多个器件并联时设置器件地址,当这些脚悬空时默认值为0(A T24C01除外)。
WP:写保护
如果WP管脚连接到Vcc,所有的内容都被写保护(只能读)。当WP管脚连接到Vss或悬空,允许器件进行正常的读/写操作
4.器件操作
4.1. 开始START CONDITION
主器件通过发送一个起始信号启动发送过程。这个信号的时序要求是当SCL为高时,SDA 出现一个由低到高的跳变。时序图如下(图3)。
图 4 开始时序
4.2. 应答信号ACKNOWLEDGE
I2C总线数据传送时,每成功地传送一个字节数据后,接收器都必须产生一个应答信号。
应答的器件在第9个时钟周期时将SDA线拉低(发送一个0),表示其已收到一个8位数据。
A T24Cxx在接收到起始信号和从器件地址之后响应一个应答信号,如果器件已选择了写操作,
则在每接收一个8位字节之后响应一个应答信号。
当A T24Cxx工作于读模式时,在发送一个8位数据后释放SDA线并监视一个应答信号,一旦接收到应答信号,A T24Cxx继续发送数据,如主器件没有发送应答信号,器件停止传送数据并等待一个停止信号。主器件必须发一个停止信号给A T24Cxx使其进入候命模式并使器件处于已知的状态。
应答信号的时序如下图所示(图5)。
图 5 应答信号时序图
4.3. 停止STOP CONDITION
主器件通过发送一个起始信号启动发送过程。这个信号的时序要求是当SCL为高时,SDA 出现一个由高到低的跳变。停止命令将使E2PROM 进入候命(standby power)模式。
停止操作的时序图如下图(图6)所示。
图 6 停止信号时序图
4.4. 候命状态STANDBY MODE
两个条件下器件可以进入候命状态:
a)上电
b)接收到停止位或者器件内部操作结束。
5.器件寻址
5.1. 从器件地址位
主器件通过发送一个起始信号启动发送过程,然后发送它所要寻址的从器件的地址。如下图所示(图7)8位从器件地址的高4位D7-D4固定为1010,接下来的3位D3-D1(A2、A1、A0)为器件的片选地址位或作为存储器页地址选择位,用来定义哪个器件以及器件的哪个部分被主器件访问,最多可以连接8个A T24C01/02,4个A T24C04,2个A T24C08,8个A T24C32/64,4个A T24C256器件到同一总线上,这些位必须与硬连线输入脚A2、A1、A0相对应。1个A T24C16/128可单独被系统寻址。从器件8位地址的最低位D0,作为读写控制位。“1”表示对从器件进行读操作,“0”表示对从器件进行写操作。在主器件发送起始信号和从器件地址字节后,A T24Cxx监视总线并当其地址与发送的从地址相符时响应一个应答信号。A T24Cxx再根据读写控制位(R/W)的状态进行读或写操作。
图7 从器件地址
5.2. 数据地址分配
A T24Cxx系列串行E2PROM数据地址是一维顺序排列的。A T24C01/02/04/08/16的A8~A15位无效,只有A0~A7是有效位。对于A T24C01/02正好合适,但对于A T24C04/08/16来说,则需要a8、a9、a10地址位进行相应的配合。
6.写操作
6.1. 字节写
图(图8)是字节写模式下的时序图。在字节写模式下,主器件发送起始命令和从器件地址信息(R/W位置0)给从器件,主器件在收到从器件产生应答信号后,主器件发送1个8位字节地址写入A T24C01/02/04/08/16的地址指针,对于A T24C31/64/128/256来说,所不同的是主器件发送两个8位地址字写入A T24C32/64/128/256的地址指针。主器件在收到从器件的另一个应答信号后,再发送数据到被寻址的存储单元。A T24Cxx再次应答,并在主器件产生停止信号后开始内部数据的擦写,在内部擦写过程中,A T24Cxx不再应答主器件的任何请求。
图8 字节写时序图
6.2. 页写
如图(图9)所示为A T24Cxx页写时序图。在页写模式下,A T24C01/02/04/08/16/32/64/128/256 可一次写入8 /16/16/16/16/32/32/64/64个字节数据。页写操作的启动和字节写一样,不同的是在于传送了一字节数据后并不产生停止信号。主器件被允许发送P(AT24C01:P=7;
A T24C02/04/08/16:P=15;A T24C32/64:P=31;A T24C128/256:P=63)个额外的字节。每发送一个字节数据后A T24Cxx产生一个应答位, 且内部低位地址加1,高位保持不变。如果在发送停止信号之前主器件发送超过P+1个字节,地址计数器将自动翻转,先前写入的数据被覆盖。接收到P+1字节数据和主器件发送的停止信号后,A T24Cxx启动内部写周期将数据写到数据区。所有接收的数据在一个写周期内写入A T24Cxx。
图9 页写时序图
页写时应该注意器件的页“翻转”现象,如A T24C01的页写字节数为8,从0页首址00H 处开始写入数据,当页写入数据超过8个时,会页“翻转”;若从03H处开始写入数据,当页写入数据超过5个时,会页“翻转”,其它情况依此类推。
6.3. 应答查询
可以利用内部写周期时禁止数据输入这一特性。一旦主器件发送停止位指示主器件操作结束时,A T24Cxx启动内部写周期,应答查询立即启动,包括发送一个起始信号和进行写操作的从器件地址。如果A T24Cxx正在进行内部写操作,不会发送应答信号。如果A T24Cxx已经完成了内部自写周期,将发送一个应答信号,主器件可以继续进行下一次读写操作。
7.读操作
对A T24Cxx读操作的初始化方式和写操作时一样,仅把R/W位置为1,有三种不同的读操作方式:读当前地址内容、读随机地址内容、读顺序地址内容。
7.1. 立即地址读取
如图(图10)所示为A T24Cxx立即地址读时序图。A T24Cxx的地址计数器内容为最后操作字节的地址加1。也就是说,如果上次读/写的操作地址为N,则立即读的地址从地址N+1开始。如果N=E(A T24C01,E=127;A T24C02,E=255;AT24C04,E=511;A T24C08,E=1023;A T24C16,E=2047;A T24C32,E=4095;A T24C64,E=8191;A T24C128,E=16383;A T24C256,E=32767),则计数器将翻转到0且继续输出数据。A T24Cxx接收到从器件地址信号后(R/W位置1 ),它首先发送一个应答信号,然后发送一个8位字节数据。主器件不需发送一个应答信号,但要产生一个停止信号。
图10 立即地址读时序图
7.2. 随机地址读取
如图(图11)所示为A T24Cxx随机地址读时序图。随机读操作允许主器件对寄存器的任意字节进行读操作,主器件首先通过发送起始信号、从器件地址和它想读取的字节数据的地址执行一个伪写操作。在A T24Cxx应答之后,主器件重新发送起始信号和从器件地址,此时R/W位置1,A T24CXX响应并发送应答信号,然后输出所要求的一个8位字节数据,主器件不发送应答信号但产生一个停止信号。
图11 随即地址读时序图
7.3. 顺序地址读取
如图(图12)为A T24Cxx顺序地址读时序图。顺序读操作可通过立即读或选择性读操作启动。在A T24Cxx发送完一个8位字节数据后,主器件产生一个应答信号来响应,告知A T24CXX 主器件要求更多的数据,对应每个主机产生的应答信号A T24Cxx将发送一个8位数据字节。当主器件不发送应答信号而发送停止位时结束此操作。从A T24Cxx输出的数据按顺序由N到N+1输出。读操作时地址计数器在A T24Cxx整个地址内增加,这样整个寄存器区域在可在一个读操作内全部读出。当读取的字节超过E(A T24C01,E=127;A T24C02,E=255;A T24C04,E=511;
A T24C08,E=1023;A T24C16,E=2047;A T24C32,E=4095;A T24C64,E=8191;A T24C128,E=16383;A T24C256,E=32767)计数器将翻转到零并继续输出数据字节。
图12 顺序地址读时序图
8.应用实例
下面给出已经验证过的用51单片机模拟I2C总线,对存储器进行操作的程序。
硬件连接图如下(图13)所示:
图13 硬件连线图
源程序
#define _EEPROM_C
#include
#include
/****************************************************************************
*******
* 名称: void Delay_10_uS(void)
* 功能描述: 延时程序,延时10us
* 输入参量: 无
* 输出参量: 无
* 调用子程: 无
* 使用方法:
**************************************/
void Delay_10_uS(void)
{
char i=10;
while(i--);
}
/*********************************************************************************** * 名称:Delay_N_mS( unsigned int n_milisecond
* 功能描述:
* 输入参量:
* 输出参量:
* 调用子程:
* 使用方法:
************************************/
void Delay_N_mS( unsigned int n_milisecond) /* n mS delay */
{
unsigned char i;
while(n_milisecond--)
{
i=37;
while(i--);
}
}
/*********************************************************************************** * 名称:bit I2C_Start(void)
* 功能描述:启动传送?
* 输入参量: A high-to-low transition of SDA with SCL high is a start condition which must
precede any other command (refer to Start and Stop Definition timing diagram.
SCL --------
SDA ----|___
* 输出参量:
* 调用子程:
* 使用方法:
********************/
bit I2C_Start(void)
{
Delay_10_uS();
I2C_SDA =1;
Delay_10_uS();
I2C_SCK =1;
Delay_10_uS();
if ( I2C_SDA == 0) return 0;
if ( I2C_SCK == 0) return 0;
I2C_SDA = 0;
Delay_10_uS();
I2C_SCK = 0;
Delay_10_uS();
return 1;
}
/*********************************************************************************** * 名称:
* 功能描述: A low-to-high transition of SDA with SCL high is a stop condition.After
a read sequence, the stop command will place the E2PROM in a standby power mode
SCL --------
SDA ____|-----
* 输入参量:
* 输出参量:
* 调用子程:
* 使用方法:
*******************/
void I2C_Stop(void)
{
Delay_10_uS();
I2C_SDA = 0;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
I2C_SDA = 1;
Delay_10_uS();
}
/***********************************************************************************
* 名称: void I2C_Ack(void)
* 功能描述: I2C总线数据传送时,每成功地传送一个字节数据后,接收器都必须产生一个应答信号。
应答的器件在第9个时钟周期时将SDA线拉低,表示其已收到一个8位数据。
* 输入参量:
* 输出参量:
* 调用子程:
* 使用方法:
******************/
void I2C_Ack(void)
{
Delay_10_uS();
I2C_SDA=0;
Delay_10_uS();
I2C_SCK=1;
Delay_10_uS();
I2C_SCK=0;
Delay_10_uS();
}
/***********************************************************************************
* 名称:void I2C_Nack(void)
* 功能描述:无应答的时序,有应答时需要在第9位输出0,没有应答时,第9位为高
* 输入参量:无
* 输出参量:无
* 调用子程:
* 使用方法:
******************/
void I2C_Nack(void)
{
Delay_10_uS();
I2C_SDA=1;
Delay_10_uS();
I2C_SCK=1;
Delay_10_uS();
I2C_SCK=0;
Delay_10_uS();
}
/*********************************************************************************** * 名称:bit I2C_Send_Byte( unsigned char d)
* 功能描述:如果发送完成并且在第9个脉冲处得到ack,那么返回0,表示成功
* 输入参量:d,需要传送的数据字节
* 输出参量:位变量成功=0,不成功=1
* 调用子程:
* 使用方法:主器件向EEPROM写数据的时候,必须首先要传送数据,就可以直接调用这个函数**************************************/
bit I2C_Send_Byte( unsigned char d)
{
unsigned char i = 8;
bit bit_ack;
while( i-- )
{
Delay_10_uS();
if ( d &0x80 ) I2C_SDA =1;
else I2C_SDA =0;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
I2C_SCK = 0;
d = d << 1;
}
Delay_10_uS();
I2C_SDA = 1;
Delay_10_uS();
I2C_SCK = 1;
Delay_10_uS();
bit_ack = I2C_SDA;
I2C_SCK =0;
Delay_10_uS();
return bit_ack;
}
/***********************************************************************************
* 名称:unsigned char I2C_Receive_Byte(void)
* 功能描述:接收一个8位数据
* 输入参量:无
* 输出参量:接收到的数据
* 调用子程:
* 使用方法:主控器件读数据的时候,需要接收EEPROM传回来的数据,这时直接调用这个函数
**************************************/
unsigned char I2C_Receive_Byte(void)
{
unsigned char i = 8, d;
Delay_10_uS();
I2C_SDA = 1;
while ( i--)
{
d = d << 1;
Delay_10_uS();
I2C_SCK =1;
if ( I2C_SDA ) d++;
Delay_10_uS();
I2C_SCK =0;
}
return d;
}
/***********************************************************************************
* 名称:void A T24C64_W(void *mcu_address,unsigned int A T24C64_address,unsigned int count)
* 功能描述:写EEPROM操作
* 输入参量:void *mcu_address单片机内部存储单元地址, unsigned int A T24C64_address 存储数据的EEPROM 地址,
unsigned int count 数据串的长度
* 输出参量:无
* 调用子程:I2C_Send_Byte( );
* 使用方法:如果单片机需要存储的数据地址为data,要向EEPROM的0x30处写数据,数据串的长度为10,那么
函数的调用为A T24C64_W(data,0x30,10)
**************************************/
void A T24C64_W(void *mcu_address, unsigned int A T24C64_address, unsigned int count )
{
//DOG_WDI=!DOG_WDI;
//DOGTIME=0;
while(count--)
{
I2C_Start();
/*I2C_Send_Byte( 0xa0 + A T24C64_address /256 *2);*/ /* 24C16 USE */
I2C_Send_Byte( 0xa0 );
I2C_Send_Byte( A T24C64_address/256 );
I2C_Send_Byte( A T24C64_address %256 );
I2C_Send_Byte( *(unsigned char*)mcu_address );
I2C_Stop();
Delay_N_mS(10); /* waiting for write cycle to be completed */
((unsigned char*)mcu_address)++;
A T24C64_address++;
}
}
/***********************************************************************************
* 名称:void A T24C64_R(void *mcu_address,unsigned int A T24C64_address,unsigned int count)
* 功能描述:度EEPROM函数
* 输入参量:void *mcu_address单片机内部存储单元地址, unsigned int A T24C64_address 存储数据的EEPROM 地址,
unsigned int count 数据串的长度
* 输出参量:将读取的数据存储在单片机的内存中
* 调用子程:I2C_Receive_Byte();
* 使用方法:如果单片机缓存的地址为data,要从EEPROM的0x30处读数据,数据串的长度为10,那么函数的调用为A T24C64_R(data,0x30,10)
**************************************/
void A T24C64_R(void *mcu_address,unsigned int A T24C64_address,unsigned int count)
{
//DOG_WDI=!DOG_WDI;
//DOGTIME=0;
while(count--)
{
I2C_Start();
/*I2C_Send_Byte( 0xa0 + A T24C64_address / 256 *2 );*/ /* 24C16 USE */
I2C_Send_Byte( 0xa0 );
I2C_Send_Byte( A T24C64_address/256 );
I2C_Send_Byte( A T24C64_address % 256 );
I2C_Start();
/*I2C_Send_Byte( 0xa1 + A T24C64_address /256 *2 );*/
I2C_Send_Byte( 0xa1 );
*(unsigned char*)mcu_address = I2C_Receive_Byte();
I2C_Nack();
I2C_Stop();
((unsigned char*)mcu_address)++;
A T24C64_address++;
}
}
附:头文件eeprom.h
#ifndef _EEPROM_H_ //用来避免重复包含,必须注意不同的模块使用不同的名字
#define _EEPROM_H_
#ifndef _EEPROM_C
#define _EEPROM_E extern
#else
#define _EEPROM_E
#endif
sbit I2C_SCK=P1^0; //模拟时钟线的端口
sbit I2C_SDA=P1^1; //模拟数据线的端口
_EEPROM_E void Eeprom_Init(void);
_EEPROM_E bit I2C_Start(void);
_EEPROM_E void I2C_Stop(void);
_EEPROM_E void I2C_Ack(void);
_EEPROM_E void I2C_Nack(void);
_EEPROM_E bit I2C_Send_Byte( unsigned char);
_EEPROM_E u8_t I2C_Receive_Byte(void);
_EEPROM_E void A T24C64_R(void *mcu_address,unsigned int A T24C64_address,unsigned int count);
_EEPROM_E void A T24C64_W(void *mcu_address,unsigned int A T24C64_address,unsigned int count);
#endif
9.鸣谢
在程序的调试过程中得到郑文刚,姜文峰的协助,在此对他们致意。
10.参考资料
https://www.doczj.com/doc/753874040.html,/
https://www.doczj.com/doc/753874040.html,/
https://www.doczj.com/doc/753874040.html,/