单片机--E2PROM
宗旨:技术的学习是有限的,分享的精神是无限的.
24C02:256 个字节的 EEPROM.一般情况下,EEPROM 拥有 30 万到 100 万次的寿命.基于 I2C 通信协议的器件.I2C 是一个通信协议,它拥有严密的通信时序逻辑要求,而 EEPROM 是一个器件,只是这个器件采样了 I2C 协议的接口与单片机相连而已,二者并没有必然的联系,EEPROM 可以用其它接口, I2C 也可以用在其它很多器件上.
1,EEPROM 写数据流程
第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地
址,并且在读写方向上选择 "写" 操作.
第二步,发送数据的存储地址.24C02 一共 256 个字节的存储空间,地址从 0x00~0xFF,我们想把数据存储在哪个位置,此刻写的就是哪个地址.
第三步,发送要存储的数据第一个字节,第二个字节„„注意在写数据的过程中,
EEPROM 每个字节都会回应一个 "应答位 0",来告诉我们写 EEPROM 数据成功,如果没有回应答位,说明写入不成功.
在写数据的过程中,每成功写入一个字节,EEPROM 存储空间的地址就会自动加 1,当加到 0xFF 后,再写一个字节,地址会溢出又变成了 0x00.
2,EEPROM 读数据流程
第一步,首先是 I2C 的起始信号,接着跟上首字节,也就是我们前边讲的 I2C 的器件地址,并且在读写方向上选择 "写" 操作.这个地方可能有同学会诧异,我们明明是读数据为何方向也要选 "写" 呢?刚才说过了,24C02 一共有 256 个地址,我们选择写操作,是为了把所要读的数据的存储地址先写进去,告诉 EEPROM 我们要读取哪个地址的数据.这就如同我们打电话,先拨总机号码(EEPROM 器件地址),而后还要继续拨分机号码(数据地址),而拨分机号码这个动作,主机仍然是发送方,方向依然是 "写".
第二步,发送要读取的数据的地址,注意是地址而非存在 EEPROM 中的数据,通知 EEPROM 我要哪个分机的信息.
第三步,重新发送 I2C 起始信号和器件地址,并且在方向位选择 "读" 操作.
这三步当中,每一个字节实际上都是在 "写",所以每一个字节 EEPROM 都会回应一个 "应答位 0".
第四步,读取从器件发回的数据,读一个字节,如果还想继续读下一个字节,就发送一个 "应答位 ACK(0)",如果不想读了,告诉 EEPROM,我不想要数据了,别再发数据了,那就发送一个 "非应答位 NAK(1)".
和写操作规则一样,我们每读一个字节,地址会自动加 1,那如果我们想继续往下读,给 EEPROM 一个 ACK(0) 低电平,那再继续给 SCL 完整的时序,EEPROM 会继续往外送数据.如果我们不想读了,要告诉 EEPROM 不要数据了,那我们直接给一个 NAK(1) 高电平即可.这个地方大家要从逻辑上理解透彻,不能简单的靠死记硬背了,一定要理解明白.梳理一下几个要点: A,在本例中单片机是主机,24C02 是从机; B,无论是读是写, SCL 始终都是由主机控制的; C,写的时候应答信号由从机给出,表示从机是否正确接收了数据; D,读的时候应答信号则由主机给出,表示是否继续读下去.
#include < reg52.h > extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
/* E2读取函数,buf-数据接收指针,addr-E2中的起始地址,len-读取长度 */
void E2Read(unsigned char * buf, unsigned char addr, unsigned char len) {
do //用寻址操作查询当前是否可进行读写操作
{
I2CStart();
if (I2CWrite(0x50 << 1)) //应答则跳出循环,非应答则进行下一次查询
{
break;
}
I2CStop();
} while ( 1 );
I2CWrite(addr); //写入起始地址
I2CStart(); //发送重复启动信号
I2CWrite((0x50 << 1) | 0x01); //寻址器件,后续为读操作
while (len > 1) //连续读取len-1个字节
{ * buf++=I2CReadACK(); //最后字节之前为读取操作+应答
len--;
} * buf = I2CReadNAK(); //最后一个字节为读取操作+非应答
I2CStop();
}
/* E2写入函数,buf-源数据指针,addr-E2中的起始地址,len-写入长度 */
void E2Write(unsigned char * buf, unsigned char addr, unsigned char len) {
while (len > 0) {
//等待上次写入操作完成
do //用寻址操作查询当前是否可进行读写操作
{
I2CStart();
if (I2CWrite(0x50 << 1)) //应答则跳出循环,非应答则进行下一次查询
{
break;
}
I2CStop();
} while ( 1 );
//按页写模式连续写入字节
I2CWrite(addr); //写入起始地址
while (len > 0) {
I2CWrite( * buf++); //写入一个字节数据
len--; //待写入长度计数递减
addr++; //E2地址递增
if ((addr & 0x07) == 0) //检查地址是否到达页边界,24C02每页8字节,
{
//所以检测低3位是否为零即可
break; //到达页边界时,跳出循环,结束本次写操作
}
}
I2CStop();
}
}
来源: http://lib.csdn.net/article/embeddeddevelopment/36261