掉电存储EEPROM中的坑

我们在使用单片机存储数据时,经常用到24c02

24C02是一个2Kbit的串行EEPROM存储芯片,可存储256个字节数据。工作电压范围为1.8V到6.0V,具有低功耗CMOS技术,自定时擦写周期,1000000次编程/擦除周期,可保存数据100年。24C02有一个16字节的页写缓冲器和一个写保护功能。通过I2C总线通讯读写芯片数据,通讯时钟频率可达400KHz。

可以通过存储IC的型号来计算芯片的存储容量是多大,比如24C02后面的02表示的是可存储2Kbit的数据,转换为字节的存储量为21024/8 = 256byte;有比如24C04后面的04表示的是可存储4Kbit的数据,转换为字节的储存量为41024/8 = 512byte;以此来类推其它型号的存储空间。

芯片的寻址:AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。A2-A0=000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。

也就是说如果是写24C02的时候,从器件地址为10100000(0xA0);读24C02的时候,从器件地址为10100001(0xA1)。

片内地址寻址:

芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。具体解释:由于24C02只有256个字节的存储空间,所以只需要1个字节就可以寻址完24C02的存储空间,但是无法寻址完更大容量的存储IC,比如24C04的存储容量是512字节,需要9个bit的地址位才能寻址完。由上图可以看到,24C04的设备地址内是没有A0参数的,被a8代替了,这个a8就是24C04的第9个bit的地址位,也就是说24C04的A0引脚是不起作用的,这样也就造成了在I2C总线上只能同时挂载4个24C04芯片。其它存储器如24C08、24C16也可以这么类推。

24C02的WP引脚是写保护引脚,当WP引脚接高电平的时,24C02只能进行读取操作,不能进行写操作。只有当WP引脚悬空或接低电平时,24C02才能进行写操作。  IIC 主设备/从设备:简单介绍一下主从机区分,对于新手来说老是区分不开主从机还是很有利的,通常我们为了方便把IIC设备分为主设备和从设备,基本上谁控制时钟线(即控制SCL的电平高低变换)谁就是主设备。

IIC主设备功能:主要产生时钟,产生起始信号和停止信号

IIC从设备功能:可编程的IIC地址检测,停止位检测

IIC的协议层I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。

开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

在SCL的高电平期间,SDA是不允许变化的;而只有在时钟线SCL的低电平期间,SDA才能够出现变化;

应答信号每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,

应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答

应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

Start: IIC开始信号,表示开始传输。DEVICE_ADDRESS:: 从设备地址,就是7位从机地址R/W: W(write)为写,R(read)为读ACK: 应答信号WORD_ADDRESS : 从机中对应的寄存器地址 比方说访问 OLED中的 某个寄存器DATA: 发送的数据STOP: 停止信号。结束IIC

主机要向从机写数据时:

主机首先产生START信号然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方 向位(R/W),0表示主机发送数据(写),1表示主机接收数据(读)主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,根据R/T位将自己确定为发送器和接收器这时候主机等待从机的应答信号(A)当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号,主机产生停止信号,结束传送过程。

主机要从从机读数据时

主机首先产生START信号然后紧跟着发送一个从机地址,注意此时该地址的第8位为0,表明是向从机写命令,这时候主机等待从机的应答信号(ACK)当主机收到应答信号时,发送要访问的地址,继续等待从机的应答信号,当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送)所以主机重新发送一个开始start信号,然后紧跟着发送一个从机地址,注意此时该地址的第8位为1,表明将主机设 置成接收模式开始读取数据,这时候主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据主机进而产生停止信号,结束传送过程。

向AT24C02中写数据

MCU先发送一个开始信号(START)启动总线接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0)等待应答信号(ACK)发送数据的存储地址。24C02一共有256个字节的存储空间,地址从0x00~0xFF,想把数据存储>在哪个位置,此刻写的就是哪个地址。发送要存储的数据第一字节、第二字节、…注意在写数据的过程中,E2PROM每个字节都会>回应一个“应答位0”,老告诉我们写E2PROM数据成功,如果没有回应答位,说明写入不成功。发送结束信号(STOP)停止总线注意:在写数据的过程中,每成功写入一个字节,E2PROM存储空间的地址就会自动加1,当加到0xFF后,再写一个字节,地址就会溢出又变成0x00。

写数据的时候需要注意,E2PROM是先写到缓冲区,然后再“搬运到”到掉电非易失区。所以这个过程需要一定的时间,AT24C02这个过程是不超过5ms!所以,当我们在写多个字节时,写入一个字节之后,再写入下一个字节之前,必须延时5ms才可以

读随机地址的数据

1、MCU先发送一个开始信号(START)启动总线2、接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0)注意:这里写操作是为了要把所要读的数据的存储地址先写进去,告诉E2PROM要读取哪个地址的数据。3、发送要读取内存的地址(WORD ADDRESS),通知E2PROM读取要哪个地址的信息。4、重新发送开始信号(START)5、发送设备读操作地址(DEVICE ADDRESS)对E2PROM进行读操作 (0xA1)6、E2PROM会自动向主机发送数据,主机读取从器件发回的数据,在读一个字节后,MCU会回应一个应答信号(ACK)后, E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据7、如果不想读了,告诉E2PROM不想要数据了,就发送一个“非应答位NAK(1)”。发送结束信号(STOP)停止总线

连续读数据

E2PROM支持连续写操作,操作和单个字节类似,先发送设备写操作地址(DEVICE ADDRESS),然后发送内存起始地址(WORD ADDRESS),MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据。E2PROM的地址指针会自动递增,数据会依次保存在内存中。不应答发送结束信号后终止传输。

下面开始着重写24c02:

24C02有两种工作模式:(1)、字节写入模式:结合技术文档我认为该模式是这样工作的:首先是可以再任意的地址(0x00~0xFF)写入一个字节,也可以在某一地址连续的写入N字节,而且不需要翻页,从技术手册得知,答题时说字节写入模式下,页指针根写入数据的多少来自动增加实现翻页功能,不用自己在程序里边实现;(2)、页写入模式:页写入模式下,手册上写着,一页可以存8字节,当存储的数据大于8时,则会覆盖先前保存的数据,例如,有16个数据 uchar data[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},从24C02的0x00地址开始存放,当存完一页(8个)时,第9个数据会保存在0x00,覆盖掉开始保存的1,后边的数据一次类推,这样的现象叫做“翻转”,如果想写完一页后将剩余的数据保存在下一页,页指针需要自己来设定。

这个是多字节写入,注意程序中注释

按页写于单字节写的最大区别在于,写入数据的时序不同,单字节写入是写完一个字节之后就要主机停止信号,然后进行数据的擦写周期,看按页写的时许图可以知道,每次发送完一个字节之后只要跟一个应答就可以继续写入下一个字节,当写满8字节之后才需要停止信号进行数据的擦写。

uint8_t I2C_EEPROM_BufferWrite(uint8_t *psrc_data,uint8_t adr,uint8_t nbyte)
{
   uint8_t i;
	i2c_Start();     
         
     i2c_SendByte(I2C_DeviceAddress);	/* 发送设备地址+写信号 */
    
     if(i2c_WaitAck())
	{
		return 0;
	}
    i2c_SendByte(adr);   //设置起始地址 
	i2c_WaitAck();
  /* 
		写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。
		对于24xx02,page size = 8
		简单的处理方法为:按字节写操作模式,每写1个字节,都发送地址
		为了提高连续写的效率: 本函数采用page wirte操作。
	*/
 for(i=0;i<nbyte;i++)
 {
//	 i2c_Start();     
//         
//     i2c_SendByte(I2C_DeviceAddress);	/* 发送设备地址+写信号 */
//    
//     if(i2c_WaitAck())
//	{
//		return 0;
//	}
//    i2c_SendByte(adr);   //设置起始地址 
//	i2c_WaitAck();
	 i2c_SendByte(psrc_data[i]);           //写数据
	  if(i2c_WaitAck())
	{
		return 0;
	}
//	  psrc_data++;    //指向待写数据的指针加1
        adr++;    //对24C08的操作地址加1 
//	 delay(5000);	
	if(adr%8==0)                //每页8字节  //换页
        {
			if(i==nbyte-1)
			{
			}
			else
			{
				i2c_Stop();  
				delay(5000);											//停止时间需超过5ms.
				i2c_Start();  											//地址为8倍数重新开始
				i2c_SendByte(I2C_DeviceAddress);	/* 发送设备地址+写信号 */
				 i2c_WaitAck();
				i2c_SendByte(adr);   //设置起始地址 
				i2c_WaitAck();
			}				
            
        }
//        i2c_Stop();
       delay(12000);		
  //注意:因为这里要等待EEPROMPROM写完,可以采用查询或延时方式(10ms)
//        DelayMs(12); //写入延时 12ms  写周期大于10ms即可
        
 }
     i2c_Stop();
// delay(5000);		
 return 1;
}

在向 EEPROM 连续写入多个字节的数据时,如果每写一个字节都要等待的话,整体上的写入效率就太低了。因此 EEPROM 的厂商就想了一个办法,把 EEPROM 分页管理。24C01.24C02 这两个型号是8 字节一个页,而 24C04、24C08、24C16是16 个字节一页。例如AT24C02,一共是 256 个字节,8 个字节一页,那么就一共有 32 页分配好页之后,如果我们在同一个页内连续写入几个字节后,最后再发送停止位的时席.EEPROM 检测到这个停止位后,就会一次性把这一页的数据写到非易失区域,就不需要像上节课那样写一个字节检测一次了,并且页写入的时间也不会超过 5ms。如果我们写入的数据跨页了,那么写完了一页之后,我们要发送一个停止位,然后等待并且检测 EEPROM 的空闲模式,一直等到把上一页数据完全写到非易失区域后,再进行下一页的写入,这样就可以在很大程度上提高数据的写入效率

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 4
关注 192
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧