当前位置:文档之家› I2C总线接口的EEPROM应用笔记

I2C总线接口的EEPROM应用笔记

I2C总线接口的EEPROM应用笔记
I2C总线接口的EEPROM应用笔记

应用笔记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,/

相关主题
文本预览
相关文档 最新文档