搜索
bottom↓
回复: 42

[原创]根治AVR单片机EEPROM数据丢失,首次在单片机引入准入制度 --对中国电子开发网

[复制链接]

出0入0汤圆

发表于 2010-11-29 09:57:26 | 显示全部楼层 |阅读模式
方法如下:
1 .在数据区建立一个全局变量:EEPROM_PROTECT,一个全局写入缓冲区,缓冲区内放要写数据的地址(EEPROM_W_ADDR)、数据(EEPROM_W_DATA)
2.在你写的第一行代码给EEPROM_PROTECT赋值0xa1。
3.初始化一半时,判断EEPROM_PROTECT的值是否0xa1,是则赋值0xa2,否则RESET。
4.初始化完成后则把EEPROM_W_ADDR赋值0x0000,并判断EEPROM_PROTECT的值是否0xa2,是则赋值0xa4,否则RESET。
5.要擦、写EEPROM,把地址取反放入EEPROM_W_ADDR,把数据放入EEPROM_W_DATA
6.在擦、写子程序里,在最靠近镲写指令的前方判断EEPROM_W_ADDR值的取反是否越界,是则RESET,再判断EEPROM_PROTECT是否0xa4,否则RESET。
7.在擦、写子程序里,按地址(EEPROM_W_ADDR值的取反)把数据(EEPROM_W_DATA)写进EEPROM后,在最靠近镲写指令的后方把EEPROM_W_ADDR赋值0x0000。

这样上电复位时即使执行了擦、写子程序,由于EEPROM_PROTECT的值不对无法擦写;在运行中跑飞即使执行了擦、写子程序,由于EEPROM_W_ADDR值的取反越界,也无法擦写。这样就可以放心地使用EEPROM了。
                                     --by qianhng


又:以上EEPROM_PROTECT的用法确保了不开BOD也不会丢失EEPROM数据,但EEPROM_W_ADDR和EEPROM_W_DATA并不能完全确保免除跑飞的威胁。
第一次修改:
为了确保免除跑飞的威胁,引入严格的准入制度:
1.分配一全局变量PERMIT_ENTER_INDEX,并在主程序赋值为0x00,分配一足够大的全局空间PERMIT_ENTER_BUFF。并赋值PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]为0x0000。
2.每次要调用一个子程序,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX+1,把该子程序的入口赋值给PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX];每当退出一个子程序后,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX-1。

那么就可以在任意一个子程序里查询自己是否被调用(PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]==自己的入口),不是的话是跑飞,拒绝执行;也可以查自己是被谁调用的(PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX-1]),假如调用者不对,那么是非法调用,是跑飞的行为,要拒绝执行,要是像写EEPROM这样重要的程序,还可以再向上查一直查到始祖!^_^

这样,就再也不怕跑飞了!

首先谢谢snoopyzz及windy__xp 龙笑 帮忙指出我考虑不周之处!
第二次修改:
  原因:要避免从另一个有权调用“擦、写EEPROM子程序”的子程序中起飞,在另一个有权调用“擦、写EEPROM子程序”的子程序中降落。
  方法:
修改第一次修改的第2点为:每次要调用一个子程序,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX+1,把该子程序的入口赋值给PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX],再检测PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX-1]是否本子程序入口,否则RESET;每当退出一个子程序后,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX-1,再检测PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]是否本子程序入口,否则RESET。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-11-29 10:07:16 | 显示全部楼层
基本思想就是文件事务的意思吧

出0入0汤圆

发表于 2010-11-29 10:13:14 | 显示全部楼层
数据+crc32,用双块空间冗余,每块空间记录一个事务id,如果发现第一块空间crc错误,再验证第二块,如果正确,就恢复第一块(说明上次事务未完成,回滚到最近一次会话).正常情况下,两块空间有相同的事务id和正确的crc;写操作是先写第一块,验证后再写第二块,保持冗余.

出0入0汤圆

 楼主| 发表于 2010-11-29 10:16:35 | 显示全部楼层
回复【2楼】mcu_001
数据+crc32,用双块空间冗余,每块空间记录一个事务id,如果发现第一块空间crc错误,再验证第二块,如果正确,就恢复第一块(说明上次事务未完成,回滚到最近一次会话).正常情况下,两块空间有相同的事务id和正确的crc;写操作是先写第一块,验证后再写第二块,保持冗余.
-----------------------------------------------------------------------

这样既烦琐,又没有效率,也不一定保险(跑飞时执行了你的写入程序,两块都正确写入了你想要的数据。由于是用你的程序写的CRC是没问题的。)

出0入0汤圆

发表于 2010-11-29 10:19:33 | 显示全部楼层
再学习下你的思路

出0入0汤圆

发表于 2010-11-29 10:20:45 | 显示全部楼层
STM 有类似的功能

出0入0汤圆

发表于 2010-11-29 10:25:34 | 显示全部楼层
LZ的方法太麻烦....直接设一个寄存器变量(只用其中一位)f_EEPROM_W,
在EEMWE和EEWE置位之间判断下f_EEPROM_W是否为0
不为0的话才写EEWE位...

这样就没问题了,在写eeprom前,先置位f_EEPROM_W就可以了,写完了就清零f_EEPROM_W

由于写EEMWE和写EEWE之间有时间要求...所以必须用寄存器变量来做...
时间超了,eeprom写入是不会成功的....

我就是这样做的,一直没问题,其实最简单的方法就是开BOD,开了BOD就没事,不过有的产品有功耗要求,就只有软件方法解决了...

以下是部分代码
====================
#ifndef _H_EEPROM
#define _H_EEPROM

#include "main.h"

#define EEPROM_SIZE     256

#if     EEPROM_SIZE>256
#define EEPROM_INIT()
#define EEP_TYPE    u16
#else
#define EEP_TYPE    u8
#define EEPROM_INIT()   ( EEARH = 0 )
#undef  EEAR
#define EEAR    EEARL
#endif

typedef struct
{
    u8          Tick;
    u8          Data;
    EEP_TYPE    Address;
}   EEP_T;
extern  EEP_T EEP;

extern  void EEPROM_DoEvent(void);
extern  u8 EEPROM_ReadByte(EEP_TYPE address);
extern  void EEPROM_ReadBytes(EEP_TYPE address, u8* dest, EEP_TYPE count);
extern  void EEPROM_WriteBytes(EEP_TYPE address, u8* source, EEP_TYPE count);
//extern    void EEPROM_Destroy(EEP_TYPE address, u16 count);

#define EEPROM_WRITE(address,data)  \
{\
    FLAG_SET(f_EEPROM_W);\
    EEP.Address = address;\
    EEP.Data = data;\
}


#endif


====================


#include "EEPROM.h"

EEP_T EEP = {0};

#define EEPROM_WAIT()   { while( EECR&BIT(EEWE) ); }
#define EEPROM_CHK_BUSY()   { if(EECR&BIT(EEWE)) return; }
#define EEPROM_SET_ADDR(a)  { EEAR = a; }
#define EEPROM_SET_DATA(d)  { EEDR = d; }
#define EEPROM_DO_WRITE()   { EECR|=BIT(EEMWE); if(FLAG_CHK(f_EEPROM_W)!=0) EECR|=BIT(EEWE); else return; }

/*
void EEPROM_ReadBytes(EEP_TYPE address, u8* dest, EEP_TYPE count)
{
    EEPROM_INIT();
    EEPROM_WAIT();
    for(;;)
    {
        EEAR = address;
        EECR |= BIT(EERE);
        *dest++ = EEDR;
        address++;
        count--;
        if( count==0 )
        {
            break;
        }
    }
}

void EEPROM_WriteBytes(EEP_TYPE address, u8* source, EEP_TYPE count)
{
    EEPROM_INIT();
    for(;;)
    {
        EEPROM_WAIT();
        EEAR = address;
        EEDR = *source++;
        Interrupt_ALL_Disabled();
        EEPROM_DO_WRITE();
        Interrupt_ALL_Enabled();
        address++;
        count--;
        if( count==0 )
        {
            break;
        }
    }
}

void EEPROM_WriteByte(EEP_TYPE address, u8 data)
{
    EEPROM_INIT();
    EEPROM_WAIT();
    EEAR = address;
    EEDR = data;
    Interrupt_ALL_Disabled();
    EEPROM_DO_WRITE();
    Interrupt_ALL_Enabled()
}
*/
u8 EEPROM_ReadByte(EEP_TYPE address)
{
    EEPROM_INIT();
    EEPROM_WAIT();
    EEAR = address;
    EECR |= BIT(EERE);
    return EEDR;
}

void EEPROM_DoEvent(void)
{
    if( EEP.Tick>0 )
    {
        EEP.Tick--;
        return;
    }
    //
    if( FLAG_CHK(f_EEPROM_W) )
    {
        EEPROM_INIT();
        EEPROM_CHK_BUSY();
        EEPROM_SET_ADDR(EEP.Address);
        EEPROM_SET_DATA(EEP.Data);
        //
        Interrupt_ALL_Disabled();
        EEPROM_DO_WRITE();
        Interrupt_ALL_Enabled();
        //
        FLAG_CLR(f_EEPROM_W);
        EEP.Tick = MS(1000);
    }
}

出0入0汤圆

 楼主| 发表于 2010-11-29 10:33:20 | 显示全部楼层
回复【6楼】snoopyzz
lz的方法太麻烦....直接设一个寄存器变量(只用其中一位)f_eeprom_w,
在eemwe和eewe置位之间判断下f_eeprom_w是否为0
不为0的话才写eewe位...
这样就没问题了,在写eeprom前,先置位f_eeprom_w就可以了,写完了就清零f_eeprom_w
......
-----------------------------------------------------------------------

程序跑飞后,执行了你的EEPROM_WriteBytes就可以正确写入错误的数据了。

又:加了BOD在干扰下就不会从正常运行状态下跑飞了吗?^_^

出0入0汤圆

发表于 2010-11-29 10:56:35 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-11-29 11:04:02 | 显示全部楼层
2楼可行,相对安全性最高,即使程序跑飞,把两块都写的概率应该很低

出0入0汤圆

发表于 2010-11-29 11:05:53 | 显示全部楼层
不会的,EEPROM_WriteBytes并不包括f_EEPROM_W置1的内容....

是一个宏中置1的....

这个文件仅仅是思路描述,你看到的EEPROM_WriteBytes是在/**/注释中的....这部分代码已经被注释掉了,因为那个项目中不需要连续写入
实际需要连续写入的话,也是放在EEPROM_DoEvent中处理的....
宏只管设置写入起始地址,写入长度,置写入标置,
而是在主循环运行到EEPROM实际处理函数EEPROM_DoEvent时才会真正写入eeprom...

又由于整个程序是状态机结构,在复位,跑飞等状态下想同时满足这些条件太难了(先跑飞到EEPROM_WRITE出现的位置,再次跑飞到EEPROM_DoEvent)
至少我这曾经量产过的的产品从未出过这方面问题....现在都换stm8了^_^

出0入0汤圆

 楼主| 发表于 2010-11-29 11:12:51 | 显示全部楼层
回复【10楼】snoopyzz
不会的,eeprom_writebytes并不包括f_eeprom_w置1的内容....
是一个宏中置1的....
这个文件仅仅是思路描述,你看到的eeprom_writebytes是在/**/注释中的....这部分代码已经被注释掉了,因为那个项目中不需要连续写入
实际需要连续写入的话,也是放在eeprom_doevent中处理的....
宏只管设置写入起始地址,写入长度,置写入标置,
而是在主循环运行到eeprom实际处理函数eeprom_doevent时才会真正写入eeprom...
又由于整个程序是状态机结构,在复位,跑飞等状态下想同时满足这些条件太难了(先跑飞到eeprom_write出现的位置,再次跑飞到eeprom_doevent)
至少我这曾经量产过的的产品从未出过这方面问题....现在都换stm8了^_^

-----------------------------------------------------------------------

呵呵,你在哪里“置写入标置”,跑飞时飞到那里就写入错误的数据,当然,几率比不设“写入标置”要小多了,但不能杜绝。

出0入0汤圆

发表于 2010-11-29 11:25:13 | 显示全部楼层
LS还是没弄清了..我写入标置,和写eeprom的操作是分开两处地方....

程序除非连续两次跑飞到这两处才会出错....

已经有产品用这个方法,表示没问题,不信我也没办法,
当然LZ你的办法是有效的...但是如果连续跑飞,效果和我的也是一样的....

能连续跑飞到正好这两处....我也可以不做程序员了,改行买彩票多美^_^

出0入0汤圆

 楼主| 发表于 2010-11-29 11:32:05 | 显示全部楼层
回复【12楼】snoopyzz
ls还是没弄清了..我写入标置,和写eeprom的操作是分开两处地方....
程序除非连续两次跑飞到这两处才会出错....
已经有产品用这个方法,表示没问题,不信我也没办法,
当然lz你的办法是有效的...但是如果连续跑飞,效果和我的也是一样的....
能连续跑飞到正好这两处....我也可以不做程序员了,改行买彩票多美^_^
-----------------------------------------------------------------------

程序执行到这里(A)你要写EEPROM,你就先调用子程序写入标置,再调用子程序写eeprom对不对?

跑飞到A就够了,执行下去会按你的程序依次写入标置和写eeprom的。

又:我突然发现,我的程序还是存在和你一样的缺点:-(

出0入0汤圆

发表于 2010-11-29 11:48:16 | 显示全部楼层
回LS,还真不对.....

我准备写EEPROM的地方,只有写入地址和长度,还有写入数据(或写入数据指针)


需要经过其它很多地方,才执行会到EEPROM_DoEvent()(这个是在主循环中判断CPU空闲时执行的)

我并不是设计成立即写入的,而是CPU空闲时才写,不然浪费时间了,CPU还有其它事要做...



如果跑飞执行到置位的地方,由于函数调用的return不是正常途径进去的,也就无法正常返回,回不到主循环能正常运行的地方的...


主循环中还有程序正常运行检测标志等其它专用防跑飞手段....


于是,万无一失....除非干优硬是和干上了,专门跑飞到绕过检测的地方,还一次又一次....
这种情况下,LZ你的程序也一样-_-

出0入0汤圆

发表于 2010-11-29 11:51:25 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-11-29 11:53:02 | 显示全部楼层
顶下,LZ看14L我回帖

出0入0汤圆

 楼主| 发表于 2010-11-29 12:01:22 | 显示全部楼层
回复【16楼】snoopyzz
顶下,lz看14l我回帖
-----------------------------------------------------------------------

看了,深有同感,要杜绝的话看来还需要各方面的配合了,比如陷阱:
做很多不调用的子程序放在其它子程序之间,它们唯一做的事是先给EEPROM_PROTECT赋值0x00再RESET。
在主循环设置程序执行状态字PROC_STATUS:调用子程序前给把该子程序的编号赋值给PROC_STATUS,调用返回后再比对,不同则RESET.
。。。。。。

出0入0汤圆

 楼主| 发表于 2010-11-29 14:42:49 | 显示全部楼层
有了新的绝妙方法,已更新到【楼主位】

出0入0汤圆

发表于 2010-11-29 16:19:34 | 显示全部楼层
汗....LZ这"准入"制度,我正用在某产品上-_-不过没LZ这么严格....我只对关键的主循环下各函数设置了进入校验和返回校验...

一直觉着蛮多余的行为,怕被人拍砖,没想到LZ也有此想法,握手....

出0入0汤圆

发表于 2010-11-29 16:38:35 | 显示全部楼层
这样的话RAM消耗有点多

出0入0汤圆

 楼主| 发表于 2010-11-29 17:14:08 | 显示全部楼层
回复【19楼】snoopyzz
汗....lz这"准入"制度,我正用在某产品上-_-不过没lz这么严格....我只对关键的主循环下各函数设置了进入校验和返回校验...
一直觉着蛮多余的行为,怕被人拍砖,没想到lz也有此想法,握手....
-----------------------------------------------------------------------

哈哈,握手!

出0入0汤圆

 楼主| 发表于 2010-11-29 17:18:20 | 显示全部楼层
回复【20楼】linghu2 令狐二中
这样的话ram消耗有点多
-----------------------------------------------------------------------

安全第一!假如15层调用,该功能AVR才用了33个字节的RAM,也不算太多了。

出0入0汤圆

发表于 2010-11-29 17:36:11 | 显示全部楼层
弄个循环码不好?

出0入0汤圆

 楼主| 发表于 2010-11-29 17:59:31 | 显示全部楼层
回复【23楼】ssaweee
弄个循环码不好?
-----------------------------------------------------------------------

循环码对验证数据的正确性作用很大,但对验证是不是跑飞写的数据作用不大。

出0入0汤圆

发表于 2010-11-29 18:07:18 | 显示全部楼层
仅仅从软件上来说,程序跑飞修改数据的问题不能100%避免,只能降低跑飞后,数据被修改的概率,复杂的方法,程序各个部分分散,只能降低数据被修改的概率。

    mark,有时间再来学习。

出0入0汤圆

发表于 2010-11-29 18:09:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-11-29 18:30:19 | 显示全部楼层
回复【14楼】snoopyzz
回ls,还真不对.....
我准备写eeprom的地方,只有写入地址和长度,还有写入数据(或写入数据指针)
需要经过其它很多地方,才执行会到eeprom_doevent()(这个是在主循环中判断cpu空闲时执行的)
我并不是设计成立即写入的,而是cpu空闲时才写,不然浪费时间了,cpu还有其它事要做...
如果跑飞执行到置位的地方,由于函数调用的return不是正常途径进去的,也就无法正常返回,回不到主循环能正常运行的地方的...
主循环中还有程序正常运行检测标志等其它专用防跑飞手段....
于是,万无一失....除非干优硬是和干上了,专门跑飞到绕过检测的地方,还一次又一次....
这种情况下,lz你的程序也一样-_-
-----------------------------------------------------------------------
“我并不是设计成立即写入的,而是cpu空闲时才写,不然浪费时间了,cpu还有其它事要做... ”感觉这个才是关键吧?如何检测CPU空闲?而CPU空闲算是随机事件,也就是说何时调用写函数是不确定的,如果主循环做了跑飞检测,检测CPU是否空闲时也检测是否跑飞,那么就能避免,不然还是有问题。


为了确保免除跑飞的威胁,引入严格的准入制度:
1.分配一全局变量PERMIT_ENTER_INDEX,并在主程序赋值为0x00,分配一足够大的全局空间PERMIT_ENTER_BUFF。并赋值PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]为0x0000。
2.每次要调用一个子程序,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX+1,把该子程序的入口赋值给PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX];每当退出一个子程序后,PERMIT_ENTER_INDEX=PERMIT_ENTER_INDEX-1。

那么就可以在任意一个子程序里查询自己是否被调用(PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]==自己的入口),不是的话是跑飞,拒绝执行;也可以查自己是被谁调用的(PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX-1]),假如调用者不对,那么是非法调用,是跑飞的行为,要拒绝执行,要是像写EEPROM这样重要的程序,还可以再向上查一直查到始祖!^_^

这样,就再也不怕跑飞了!
------------------------------------------------------------------------------------
LZ 这个想法很好,但还是有问题。

出0入0汤圆

发表于 2010-11-29 18:37:49 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2010-11-29 19:04:19 | 显示全部楼层
回复【27楼】windy__xp 龙笑
LZ 这个想法很好,但还是有问题。
-----------------------------------------------------------------------

有什么问题麻烦你具体说一下,特别是如何导致写入错误数据,谢谢!

出0入0汤圆

发表于 2010-11-29 21:33:12 | 显示全部楼层
回复【29楼】qianhng
回复【27楼】windy__xp 龙笑
lz 这个想法很好,但还是有问题。
-----------------------------------------------------------------------
有什么问题麻烦你具体说一下,特别是如何导致写入错误数据,谢谢!

-----------------------------------------------------------------------
    在程序跑飞的检测上,不知道我理解的是否正确,比如 fun_write() 运行时,先检测PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]当前值是否是自己的地址,上级以及更上一级是否正常调用,是就执行,不是就不执行,对吗?如果是这样,还是老问题,如果调用跑飞切入点在调用  fun_write() 这个函数处呢,而入口处也做了PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]的设置,就算检测调用者是否合法,那么飞到上一级呢?如果再检测上一级,那么更上一级呢?就算所有调用级数的地址是可以确定的,就算所有调用都是合法的,就一定没有问题吗?估计仅仅是层数越深,概率越小吧,13L你提到了,只是现在搞得更复杂,降低概率而已,可能性还是比较大,关键一个问题是你不知道程序从“何处起飞,何处着陆”,这个想法的确很好,没有细想,不知道理解是否正确。snoopyzz的说法中,估计是跑了OS,不过具体怎么实现没有多想,这个问题以前考虑过,没有找到简单而又绝对好用的解决办法,只能降低概率。

    对了,snoopyzz 在 EEMWE和EEWE 之间检测标志位的方法才是正确得(4个指令必须完成检测和写入,这个用位寻址的变量比较方便,部分AVR芯片有一个字节可以位寻址,可以使用SBIC SBIS指令),不然刚好飞到写的部分避过了检测,那么前面再好的检测也没有用是不是?

    回复只算是 mark 一下,这个问题有必要深入讨论,回头好好考虑一下  snoopyzz  大侠的方法,不想太多了,头痛。

出0入0汤圆

 楼主| 发表于 2010-11-29 22:16:59 | 显示全部楼层
回复【30楼】windy__xp 龙笑
如果调用跑飞切入点在调用  fun_write() 这个函数处呢,而入口处也做了PERMIT_ENTER_BUFF[PERMIT_ENTER_INDEX]的设置,就算检测调用者是否合法,那么飞到上一级呢?如果再检测上一级,那么更上一级呢?就算所有调用级数的地址是可以确定的,就算所有调用都是合法的,就一定没有问题吗?估计仅仅是层数越深,概率越小吧
-----------------------------------------------------------------------

“如果调用跑飞切入点在调用  fun_write() 这个函数处”那么有两种情况,一种是从另一个有权调用fun_write() 的子程序中起飞,那么写入非预期数据将避免不了(在【楼主位】第二次修改中避免这种条件下出错);否则可以避免(查上一级即可)。

“那么飞到上一级呢”,“那么更上一级呢”(在上一点的解决方法同时解决了)

只有一种情况避免不了了:从本子程序起飞,在本子程序降落。大家也帮忙想想办法及挑挑错,力求取得完美结局。

出0入0汤圆

发表于 2010-11-30 09:12:26 | 显示全部楼层
学习EEPROM

出0入0汤圆

 楼主| 发表于 2010-11-30 18:39:31 | 显示全部楼层
"从本子程序起飞,在本子程序降落"这样的跑飞,大家有手段监测吗?

出0入0汤圆

发表于 2010-11-30 23:04:15 | 显示全部楼层
观点:以上软件手段只是一种冗余方法,只能解决由于程序跑飞,误写EEPROM的情况,并不能根除EEPROM数据丢失情况。

   依据:我曾做过一款产品,也开了BOD, 也采用上述类似软件冗余办法,但在现场仍出现EEPROM数据丢失情况,经多次分析,并未解

         决问题,后偶然用示波器探头碰到数字地,发现有轻微放电现象,多次触碰,竟发生EEPROM数据丢失现象,然后仔细分析

         发现电路中数字地对金属外壳焊有一个电容,于是将此电容去掉,然后再多次试验,竟未发生一次数据丢失现象。

   结论:EEPROM数据丢失现象主要原因是电源电压尖峰干扰造成。

   措施:1. BOD一定要开,保证电源波动时能尽快复位。

         2. 电源或地平面不能有干扰。若确实抗干扰需要数字地与外壳要滤波,一定要保证内部屏蔽地与外壳可靠连接,且现场

            外壳要可靠接大地。

   探讨:1. 程序如果跑飞,什么都干得出来,不仅仅会数据丢失,所以深究硬件设计才能解决此问题。

         2. 以上软件方法加上以后到底有无实际效果,不知大家有没有实例证据? 如果是编程前期已经考虑此问题,并在软件中

            做了处理,以后没有发生数据丢失现象,并不能说明软件方法有效,因为可能你的硬件已经过关;如果是产品出现此

            故障现象,然后仅在软件中做了以上处理,然后数据不再丢失,那才能证明软件手段有效。

出0入0汤圆

 楼主| 发表于 2010-11-30 23:13:23 | 显示全部楼层
回复【34楼】pujing
......后偶然用示波器探头碰到数字地,发现有轻微放电现象,多次触碰,竟发生EEPROM数据丢失现象,然后仔细分析
         发现电路中数字地对金属外壳焊有一个电容,于是将此电容去掉,然后再多次试验,竟未发生一次数据丢失现象。
-----------------------------------------------------------------------

从你文中“发现有轻微放电现象,多次触碰,竟发生EEPROM数据丢失现象”、“发现电路中数字地对金属外壳焊有一个电容”,可推断是由于电容放电引起程序跑飞把错误的数写入了EEPROM造成EEPROM数据丢失。
结论:电源电压尖峰干扰造成程序跑飞。

出0入0汤圆

发表于 2010-11-30 23:25:18 | 显示全部楼层
大家都忽略了一个问题:即便你程序里没有任何EEPROM的读写程序,你的EEPROM内容任然会改变!有的时候EEPROM改变完全是硬件误动一起的,和程序没有关系!

出0入0汤圆

 楼主| 发表于 2010-11-30 23:30:09 | 显示全部楼层
回复【36楼】zhxzhx 一丁
大家都忽略了一个问题:即便你程序里没有任何eeprom的读写程序,你的eeprom内容任然会改变!有的时候eeprom改变完全是硬件误动一起的,和程序没有关系!
-----------------------------------------------------------------------

这个还真不知道,估计这个只能加电磁屏蔽来解决了。

出0入4汤圆

发表于 2010-12-1 07:44:29 | 显示全部楼层
制标不制本呀,努力提高硬件可靠性才是王道

出0入0汤圆

 楼主| 发表于 2010-12-1 08:12:34 | 显示全部楼层
回复【38楼】electricit
制标不制本呀,努力提高硬件可靠性才是王道
-----------------------------------------------------------------------

一手软、一手硬,两手都要抓。有时候因成本的关系硬件可靠性很难做得很高(比如说低攻耗)。

出0入0汤圆

发表于 2012-5-12 09:46:05 | 显示全部楼层
我觉得关键确实是在硬件.如果硬件没有问题,程序就应该不会受到干扰,也就不会出现跑飞的现象.如果硬件有问题,程序编的再好,也依然会被干扰损坏.

出0入85汤圆

发表于 2012-9-12 15:57:46 | 显示全部楼层
一台设备用的M16,程序没有跑飞,系统也没有复位,工作中E2PROM数据变了,怎么引起的?

出0入0汤圆

发表于 2012-9-13 19:44:06 来自手机 | 显示全部楼层
路过,学习一下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 06:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表