详解AVR单片机防eeprom掉数据的办法应用AVR芯片内部EEPROM写入(或写入后读出)出错问题,下面有AVR的芯片手册有相关介绍(来自mega8中文翻译文档):防止EEPROM数据丢失若电源电压过低,CPU和EEPROM有可能工作不正常,造成EEPROM数据的毁坏(丢失)。这种情况在使用独立的EEPROM器件时也会遇到。因而需要使用相同的保护方案。由于电压过低造成EEPROM数据损坏有两种可能:一是电压低于EEPROM写操作所需要的最低电压;二是CPU本身已经无法正常工作。EEPROM数据损坏的问题可以通过以下方法解决:当电压过低时保持AVRRESET信号为低。这可以通过使能芯片的掉电检测电路BOD来实现。如果BOD电平无法满足要求则可以使用外部复位电路。若写操作过程当中发生了复位,只要电压足够高,写操作仍将正常结束。以上官方文档介绍主要提示的是电压过低发生的异常而造成读写错误,并未涉及到其它问题。个人总结,在实际应用过程中有以下问题造成数据读写错误:1.程序受到干扰(或程序存在BUG)造成写入EEPROM的数据本身就是错误的;2.EEPROM写入次数过多(这个问题在频繁写入时会遇到),造成无法写入的;3.再提电压问题:由于电压过低,造成写入的数据实际未写入或写入错误;EEPROM写入错误问题是不可避免的,因此就应有相关的归避措施和恢复措施:从硬件方面来说:加入BOD措施是必要的,同时芯片的电源滤波也有较高要求,芯片的复位电路、晶振(及芯片晶振设置位,指单片机的工作频率,这对EEPROM读写有影响)也应仔细处理,以提高抗干扰;当然,一个设计优良的线路板对抗干扰有很大帮助;从软件方面来说:可以有以下方式进行控制:1.在写入EEPROM前,需对写入的EEPROM数据进行验证措施,若不正常则不写入;2.EEPROM写入后再读出(即较验),写前数据比较,应一致,否则可能为EEPROM无法再写入,这时可能要更换存储区地址;3.楼主的解决方案有比较好的效果,但是我14楼提出的问题:太占EERPOM存储空间了,可以精简一下会更好;因为AVR内部的EEROM区有限,若存在大量存储数据情况下,则有可能选用高阶的芯片而造成成本上升;4.数据读出时有验证,并存在恢复措施,以使数据错误降到最低。以下是另一种办法.附源码基本思路:每份写到EEPRM的数据,都做三个备份,每个备份的数据都做CRC16校验,只要系统运行中出错,错误地修改了EEPROM数据,那么根据校验字节就知道哪个备份的数据被修改了,然后用正确的备份覆盖出错的备份,达到数据恢复的目的。EEPROMSave.h文件:/*EEPROM管理定义*/#defineEepromPageSize64//页容量定义#defineEepromPage0Addr0x0000//各个页的其始地址定义#defineEepromPage1Addr(EepromPage0Addr+EepromPageSize)#defineEepromPage2Addr(EepromPage1Addr+EepromPageSize)#defineEepromPage3Addr(EepromPage2Addr+EepromPageSize)#defineEepromPage4Addr(EepromPage3Addr+EepromPageSize)#defineEepromPage5Addr(EepromPage4Addr+EepromPageSize)#defineEepromPage6Addr(EepromPage5Addr+EepromPageSize)#defineEepromPage7Addr(EepromPage6Addr+EepromPageSize)/*最后两个字节为CRC16校验码,其余为数据|0|1|2||.......................|61|62|63|DataData...................Data.....CRCHCRCL*/#defineVALID0x01#defineINVALID0x00/*-----------------------------------------------------------------------------------------*/EEPROMSave.c文件:/********************************************************************函数名称:EepromReadByte()*函数功能:写一个Byte的数据进EEPROM*输入参数:address:地址*返回参数:从指定地址读出来的数据*编写作者:my_avr*编写时间:2007年8月13日*相关说明:********************************************************************/unsignedcharEepromReadByte(unsignedchar*address){unsignedchardata;data=0;eeprom_busy_wait();data=eeprom_read_byte(address);returndata;}/********************************************************************函数名称:EepromReadWord();*函数功能:写一个Word的数据进EEPROM*输入参数:address:地址*返回参数:从指定地址读出来的数据*编写作者:my_avr*编写时间:2007年8月13日*相关说明:********************************************************************/uint16_tEepromReadWord(uint16_t*address){uint16_tdata;data=0;eeprom_busy_wait();data=eeprom_read_word(address);returndata;}/********************************************************************函数名称:EepromWriteByte()*函数功能:写一个Byte的数据进EEPROM*输入参数:address:地址;data:数据*返回参数:无*编写作者:my_avr*编写时间:2007年8月13日*相关说明:********************************************************************/voidEepromWriteByte(unsignedchar*address,unsignedchardata){eeprom_busy_wait();eeprom_write_byte(address,data);}/********************************************************************函数名称:EepromWriteWord()*函数功能:写一个Word的数据进EEPROM*输入参数:address:地址;data:数据*返回参数:*编写作者:my_avr*编写时间:2007年8月13日*相关说明:********************************************************************/voidEepromWriteWord(unsignedint*address,unsignedintdata){eeprom_busy_wait();eeprom_write_word(address,data);}/********************************************************************函数名称:EepromWriteBlock()*函数功能:将缓冲区中的n个数据写进EEPROM*输入参数:address:地址;data:数据*返回参数:*编写作者:my_avr*编写时间:2007年8月13日*相关说明:********************************************************************/voidEepromWriteBlock(unsignedchar*buff,unsignedchar*address,unsignedcharn){unsignedchari;for(i=0;in;i++){EepromWriteByte((unsignedchar*)(address+i),*buff);buff++;}}/*******************************************************************函数名称:unsignedcharEepromCheck(unsignedchar*pdata,unsignedcharpacksize)*函数功能:检查EEPROM的数据是否有效,采用CRC16校验技术。一次校验默认最后两个字节为校验码,需要注意,packsize包括数据长度和校验码字节*输入参数:pdata:数组指针;packsize:数据长度*返回参数:数据是否有效,有效:VALID,无效:INVALID*编写作者:my_avr*编写时间:2007年8月21日*相关说明:********************************************************************/unsignedcharEepromCheck(unsignedchar*pdata,unsignedcharpacksize){unsignedchari,j;unsignedintcrc,ref_crc;crc=0;ref_crc=0;for(i=0;i(packsize-2);i++){crc=crc^((uint16_t)EepromReadByte(pdata)8);for(j=0;j8;j++){if(crc&0x8000){crc=(crc1)^0x1021;}else{crc=crc1;}}pdata++;}ref_crc=(uint16_t)EepromReadByte(pdata);ref_crc=ref_crc8;pdata++;ref_crc|=(uint16_t)EepromReadByte(pdata);if(crc==ref_crc){returnVALID;}else{returnINVALID;}}/********************************************************************函数名称:unsignedcharCheckWriteCRC(unsignedchar*pdata,unsignedcharpacksize)*函数功能:为EEPROM数据写CRC校验码*输入参数:pdata:数组指针;packsize:数据长度*返回参数:操作成功否?,成功:VALID,失败:INVALID*编写作者:my_avr*编写时间:2007年8月21日*相关说明:********************************************************************/unsignedcharCheckWriteCRC(unsignedchar*pdata,unsignedcharpacksize){unsignedchari,j;unsignedintcrc;crc=0;for(i=0;i(packsize-2);i++){crc=crc^((uint16_t)EepromReadByte