《匠人手记》推荐网上购书渠道:
  互动出版网(china-pub)   >>>
  当当网(dangdang)   >>>
  卓越亚马逊网    >>>
  淘宝网(taobao)   >>>
  更多购书渠道……   >>> 

设为首页加入收藏联系匠人管理入口21IC首页21IC博客21IC社区侃单片机回复的贴参与的贴

天气预报
百宝日历
载入中...

百宝专栏

载入中...
最新货色

载入中...

粉丝评论

载入中...

载入中...



百宝信息

载入中...

百宝流量

(2006-07-01开始)


匠人手记

关于24C01中数据出错(丢失)的问题的讨论
程序匠人 发表于 2006-11-9 20:33:00  阅读全文 | 回复(2) | 引用通告 | 编辑

主题:讨论一下24C01中数据出错(丢失)的问题吧(HOTPOWER请进!!) 返回主题列表

刷新 社员投票 PAGE 1 / 1 共17篇 返回主题列表 返回前个操作 首页 前页 后页 尾页  
 
 程序匠人 发表于 2006-11-8 23:38 侃单片机 ←返回版面   

讨论一下24C01中数据出错(丢失)的问题吧(HOTPOWER请进!!)

24C01读写,大多数情况下正常,但是在极偶然的时候,发生数据出错的情况。

由于出现的概率太小,很难再现故障,所以给查找原因分析问题带来困难。

虽然出错的概率很小,但仍然是不可接受的,所以请大家一起,讨论一下可能的原因。

匠人猜想过的几中可能原因:

1、上拉电阻是采用CPU内部上拉电阻,是否太大了?
2、快速频繁地断电/上电,是否会打乱读写的时序?并凑巧拼接出一个错误的读写命令?
3、中断的打搅?(可能性不大吧?)


HOTPOWER是此中忽悠高手了,快来忽悠一下吧。忽悠的深刻的话,匠人将赠送“尿童牌”开档裤子一条,呵呵!

 


签名:

               ____________________________
    ∽∽∽    /                            \
   ( 。 。)  ( 技术源于积累,成功源于执着! )
-oOOo-∪-oOOo-\ ___________________________/
              |/ 


打造一流博客,我们每天在努力!(点击进入……)
 
 

 kasedy 发表于 2006-11-8 23:55 侃单片机 ←返回版面   

估计是在开关电源时电压不稳造成的

我也碰过几次,程序运行中不会出错(系统为一个机械设备,频繁电动机起停,现场电磁干扰较厉害,一般连续运行四、五个小时),每次出错都是在断电后重新开机,幸亏有了定值校验,开机后能够及时发现。我现在打算在其WP端跟地之间接一开关,当设定时使其接地,设定完后断开,保证在开关电源时处于写保护状态(用MCU的一个IO口控制WP也不保险?)。


凯思迪电子,编程器超市


 
 

 程序匠人 发表于 2006-11-8 23:58 侃单片机 ←返回版面   

匠人的系统中没有电动机

虽然我也怀疑是电源不稳导致,但查无实据。
另外,WP端是直接接地了。

 


签名:

               ____________________________
    ∽∽∽    /                            \
   ( 。 。)  ( 技术源于积累,成功源于执着! )
-oOOo-∪-oOOo-\ ___________________________/
              |/ 


打造一流博客,我们每天在努力!(点击进入……)
 
 

 程序匠人 发表于 2006-11-9 00:01 侃单片机 ←返回版面   

大伙对于上拉电阻如何看

SCL和SDA线上的上拉电阻如果太大,是否会在偶然的干扰下不能保持晚节,而导致问题呢?

 


签名:

               ____________________________
    ∽∽∽    /                            \
   ( 。 。)  ( 技术源于积累,成功源于执着! )
-oOOo-∪-oOOo-\ ___________________________/
              |/ 


打造一流博客,我们每天在努力!(点击进入……)
 
 

 diannaoza 发表于 2006-11-9 00:07 侃单片机 ←返回版面   

极偶然的时候,发生数据出错

是呀,这类问题肯定是该高的没高,该低的没低就出现数据不对了,哈...

 


 

 computer00 发表于 2006-11-9 00:15 侃单片机 ←返回版面   

写完后立即读回验证,判断数据是否成功写入,

这样即可排除上拉电阻干扰问题.

系统在电压较低时可能会乱跑,不知道你的系统中是否有相关电源的检测(例如低电压复位芯片),防止程序乱跑.


中断中是否有对它写操作的操作?可能误入中断也难说(我以前做掉电保护的时候,在上电时由于掉电保护部分还没
工作起来,所以指示掉电,从而一上电就执行掉电保护中断,修改了数据,吃了暗亏~~~~~).


写保护最好在需要的时候再关掉,数据校验不可少(随是废话,还得要敲出来~~~~~)

 


签名:

***********************声明*********************
本人所有发言均为个人观点。由此帖带来的后果,   
本人一般不予负责。在您相信本帖之前,请慎重考虑!
                                    
                                      Computer00 
访问我的Blog


总算将ARM_00_OS移植到LPC213x上了
 
 

 coldra 发表于 2006-11-9 00:17 侃单片机 ←返回版面   

上拉电阻太大有可能偶然起不到作用

SCL和SDA的布线是不是太长或接近干扰源,读写时钟频率是不是太高

 


 

 IceAge 发表于 2006-11-9 00:53 侃单片机 ←返回版面   

同意 kasedy 的意见,电源应该是罪魁祸首

应与上拉电阻,中断没有太大关系,除非你的软件有 bug.
把 eeprom 的电源隔离开,如加电阻or二极管 + 电容,以减少电源冲击.
或者是口线+三极管控制2401的电源,用电容之类吸收mcu 上电时的口线不稳定,仅在必要时打开2401电源。

 


 
 

 农民讲习所 发表于 2006-11-9 07:58 侃单片机 ←返回版面   

总线初始化很重要。90%和它相关。

I2C是串行的,几乎很难发生写意外。楼主的“快速频繁地断电/上电”过程中I2C寄存器还保持着原来数值,如果没有总线初始化过程,肯定容易发生写错误。

再一个就是尽量使用单字节写。
尽量使用映射缓冲,可以相同的数据不写入。

 


 

 程序匠人 发表于 2006-11-9 08:28 侃单片机 ←返回版面   

答复前面各位

1、中断中没有操作I2C的动作。
2、关于农民讲习所 所说的总线初始化,是指STOP时序指令吗?单字节写要比多字节写更可靠吗?WHY?

 


签名:

               ____________________________
    ∽∽∽    /                            \
   ( 。 。)  ( 技术源于积累,成功源于执着! )
-oOOo-∪-oOOo-\ ___________________________/
              |/ 


打造一流博客,我们每天在努力!(点击进入……)
 
 

 农民讲习所 发表于 2006-11-9 08:36 侃单片机 ←返回版面   

单字节是尽量减少操作时间,而且容易校验判断出错。

俺写的通用I2C总线驱动程序。

C文件:51下用reg51.h(reg52.h)替代"..\works.h"
//-----------------------------------------------------------
//I2C驱动
//-----------------------------------------------------------
#define _I2CBusH

#i nclude "..\works.h"

struct InI2CBus{
    unsigned int mDelay;
    void (*IO_SCK)(unsigned int bState );                    //I2C的SCK
    unsigned char (*IO_SDA)( unsigned int bState );            //I2C的SDA
};
struct InI2CBus sInI2CBus;

#define this sInI2CBus

#define SDA(x)    (*this.IO_SDA)(x)
#define SCK(x)    (*this.IO_SCK)(x)

//-----------------------------------------------------------
//内部延时
//-----------------------------------------------------------
void InI2CBus_Delay( unsigned int mDelay )
{
    while( mDelay-- );
}

//-----------------------------------------------------------
//内部函数,I2C开始
//-----------------------------------------------------------
void InI2CBus_Start()
{
    SDA(1);
    SCK(1);
    InI2CBus_Delay( this.mDelay );
    SDA(0);
    InI2CBus_Delay( this.mDelay );
    SCK(0);
    InI2CBus_Delay( this.mDelay );
}

//-----------------------------------------------------------
//内部函数,I2C结束
//-----------------------------------------------------------
void InI2CBus_Stop()
{
    SDA(0);
    SCK(1);
    InI2CBus_Delay( this.mDelay );
    SDA(1);
    InI2CBus_Delay( this.mDelay );
}

//-----------------------------------------------------------
//内部函数,输入ACK
//-----------------------------------------------------------
void InI2CBus_InputACK()
{
    SCK(1);
    InI2CBus_Delay( this.mDelay );
    SCK(0);
    InI2CBus_Delay( this.mDelay );
}

//-----------------------------------------------------------
//内部函数,输出ACK
//-----------------------------------------------------------
void InI2C_OutputACK( unsigned char mAck )
{
    SCK(1);   
    SDA(mAck);
    InI2CBus_Delay( this.mDelay );
    SCK(0);
    InI2CBus_Delay( this.mDelay );
}

//-----------------------------------------------------------
//写数据
//-----------------------------------------------------------
void InI2CBus_WrData( unsigned char mData )
{
    unsigned int i;
   
    for( i=0; i<8; i++ )
    {
        SDA(mData&0x80);
        mData <<= 1;
        SCK(1);
        InI2CBus_Delay( this.mDelay );
        SCK(0);
        InI2CBus_Delay( this.mDelay );
    }
    InI2CBus_InputACK();
}

//-----------------------------------------------------------
//读数据
//-----------------------------------------------------------
unsigned char InI2CBus_RdData( void )
{
    unsigned int i;
    unsigned char mData;
   
    for( i=0; i<8; i++ )
    {
        SDA(1);                                            //***重要
        SCK(1);
        mData <<= 1;
        mData |= SDA(0xff) & 0x1;                        //读数据
        InI2CBus_Delay( this.mDelay );
        SCK(0);
        InI2CBus_Delay( this.mDelay );
    }
    return mData;
}


//-----------------------------------------------------------
//内部函数:写的开始操作
//-----------------------------------------------------------
void InI2CBus_WrStart( unsigned char mDevice, unsigned int mLocation )
{
    InI2CBus_Start();
   
    //写DEVICE地址
    InI2CBus_WrData( 0xa0 | (mDevice<<1) );                    //写地址
    if( !(mDevice & 0x80) ){
        InI2CBus_WrData( (unsigned char)(mLocation>>8) );    //高位地址
    }   
    InI2CBus_WrData( (unsigned char)(mLocation) );            //低位地址
}

//-----------------------------------------------------------
//内部函数:读的开始操作
//-----------------------------------------------------------
void InI2CBus_RdStart( unsigned char mDevice, unsigned int mLocation )
{
    InI2CBus_WrStart( mDevice, mLocation );
   
    InI2CBus_Start();
    InI2CBus_WrData( 0xa1 | (mDevice<<1) );                    //开始读
}


//========================================================================================

//-----------------------------------------------------------
//读字节
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
unsigned char I2CBus_ReadByte( unsigned char mDevice, unsigned int mLocation )
{
    unsigned char i;
   
    InI2CBus_RdStart( mDevice, mLocation );
   
    i = InI2CBus_RdData();
    InI2C_OutputACK( 1 );                                    //读结束
   
    InI2CBus_Stop();
   
    return i;
}

//-----------------------------------------------------------
//读半字
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
unsigned short I2CBus_ReadShort( unsigned char mDevice, unsigned int mLocation )
{
    unsigned short i;
   
    InI2CBus_RdStart( mDevice, mLocation );
   
    i = InI2CBus_RdData();
    InI2C_OutputACK( 0 );                                    //读继续
    i |= InI2CBus_RdData()<<8;
    InI2C_OutputACK( 1 );                                    //读结束
   
    InI2CBus_Stop();
   
    return i;
}


//-----------------------------------------------------------
//读int
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
unsigned int I2CBus_ReadInt( unsigned char mDevice, unsigned int mLocation )
{
    union VarStruct tmp;
   
    InI2CBus_RdStart( mDevice, mLocation );
   
    tmp.mChar[0] = InI2CBus_RdData();
    InI2C_OutputACK( 0 );                                    //读继续
    tmp.mChar[1] = InI2CBus_RdData();
    InI2C_OutputACK( 0 );                                    //读继续
    tmp.mChar[2] = InI2CBus_RdData();
    InI2C_OutputACK( 0 );                                    //读继续
    tmp.mChar[3] = InI2CBus_RdData();
    InI2C_OutputACK( 1 );                                    //读结束
   
    InI2CBus_Stop();
   
    return tmp.mInt;
}

//-----------------------------------------------------------
//读数组
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
void I2CBus_ReadToBuf( unsigned char mDevice, unsigned int mLocation, unsigned char *pRdBuffer, unsigned int mLength )
{
    if( mLength == 0)return;
   
    InI2CBus_RdStart( mDevice, mLocation );
   
    while( --mLength ){
        *pRdBuffer++ = InI2CBus_RdData();
        InI2C_OutputACK( 0 );
    }   
    *pRdBuffer++ = InI2CBus_RdData();
    InI2C_OutputACK( 1 );                                    //读结束
   
    InI2CBus_Stop();
}

//-----------------------------------------------------------
//写字节数据
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
void I2CBus_WriteByte( unsigned char mDevice,unsigned int mLocation,unsigned char mData )
{
    InI2CBus_WrStart( mDevice, mLocation );
   
    InI2CBus_WrData( mData );
   
    InI2CBus_Stop();
}

//-----------------------------------------------------------
//写short数据
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
void I2CBus_WriteShort( unsigned char mDevice,unsigned int mLocation,unsigned short mData )
{
    InI2CBus_WrStart( mDevice, mLocation );
   
    InI2CBus_WrData( mData );
    InI2CBus_WrData( mData>>8 );
   
    InI2CBus_Stop();
}


//-----------------------------------------------------------
//写int数据
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
void I2CBus_WriteInt( unsigned char mDevice,unsigned int mLocation,unsigned int mData )
{
    InI2CBus_WrStart( mDevice, mLocation );

    InI2CBus_WrData( mData );
    InI2CBus_WrData( mData>>8 );
    InI2CBus_WrData( mData>>16 );
    InI2CBus_WrData( mData>>24 );
   
    InI2CBus_Stop();
}

//-----------------------------------------------------------
//写数组
//mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
//-----------------------------------------------------------
void I2CBus_WriteFromBuf( unsigned char mDevice, unsigned int mLocation, unsigned char *pWrBuffer, unsigned int mLength )
{
    InI2CBus_WrStart( mDevice, mLocation );
   
    while( mLength-- ){
        InI2CBus_WrData( *pWrBuffer++ );
    }
    InI2CBus_Stop();
}

//-----------------------------------------------------------
//复位I2C,连续输出9个1
//输入SCK的回调函数指针、SDA的回调函数指针、延时数据
//-----------------------------------------------------------
void I2CBus_Init( void (*IO_SCK)(unsigned int ), unsigned char (*IO_SDA)( unsigned int ), unsigned char mDelay  )
{
    unsigned int i;
   
    this.IO_SCK = IO_SCK;
    this.IO_SDA = IO_SDA;
    this.mDelay = mDelay;
   

    SDA(1);
    for( i=0; i<9; i++ )
    {
        SCK(1);
        InI2CBus_Delay( this.mDelay );
        SCK(0);
        InI2CBus_Delay( this.mDelay );
    }
    InI2CBus_Stop();

}

//-----------------------------------------------------------
//析构
//-----------------------------------------------------------
void I2CBus_Destory( void ){}

//-----------------------------------------------------------
//测试延时用
//-----------------------------------------------------------
void I2CBus_DebugDelay( void )
{
    while(1){
        SDA(1);
        InI2CBus_Delay( this.mDelay );
        SDA(0);
        InI2CBus_Delay( this.mDelay );
    }
}


H文件
//-----------------------------------------------------------
//I2C驱动
//-----------------------------------------------------------

#ifndef _I2CBusH
    //-----------------------------------------------------------
    //读字节
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern unsigned char I2CBus_ReadByte( unsigned char mDevice, unsigned int mLocation );

    //-----------------------------------------------------------
    //读半字
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern unsigned short I2CBus_ReadShort( unsigned char mDevice, unsigned int mLocation );

    //-----------------------------------------------------------
    //读int
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern unsigned int I2CBus_ReadInt( unsigned char mDevice, unsigned int mLocation );

    //-----------------------------------------------------------
    //读数组
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern void I2CBus_ReadToBuf( unsigned char mDevice, unsigned int mLocation, unsigned char *pRdBuffer, unsigned int mLength );

    //-----------------------------------------------------------
    //写字节数据
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern void I2CBus_WriteByte( unsigned char mDevice,unsigned int mLocation,unsigned char mData );

    //-----------------------------------------------------------
    //写short数据
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern void I2CBus_WriteShort( unsigned char mDevice,unsigned int mLocation,unsigned short mData );

    //-----------------------------------------------------------
    //写int数据
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern void I2CBus_WriteInt( unsigned char mDevice,unsigned int mLocation,unsigned int mData );

    //-----------------------------------------------------------
    //写数组
    //mDevice:器件地址,最高位=1表示8位地址,否则为16位地址
    //-----------------------------------------------------------
    extern void I2CBus_WriteFromBuf( unsigned char mDevice, unsigned int mLocation, unsigned char *pWrBuffer, unsigned int mLength );

    //-----------------------------------------------------------
    //复位I2C,连续输出9个1
    //输入SCK的回调函数指针、SDA的回调函数指针、延时数据
    //-----------------------------------------------------------
    extern void I2CBus_Init( void (*IO_SCK)(unsigned int ), unsigned char (*IO_SDA)( unsigned int ), unsigned char mDelay  );

    //-----------------------------------------------------------
    //析构
    //-----------------------------------------------------------
    extern void I2CBus_Destory( void );

    //-----------------------------------------------------------
    //测试延时用
    //在SDA输出延时程序产生的方波
    //-----------------------------------------------------------
    extern void I2CBus_DebugDelay( void );
#endif

 


签名:

 


农民代表
 
 

 农民讲习所 发表于 2006-11-9 08:41 侃单片机 ←返回版面   

一旦适用了映射缓冲,使用单字节写还是多字节写就不重要了

 


签名:

 


农民代表
 
 

 农民讲习所 发表于 2006-11-9 09:42 侃单片机 ←返回版面   

上面是通用I2C驱动程序,下面是I2C应用部分,也提供大家参考

//-----------------------------------------------------------
//I2C驱动
//使用了通用I2CBus模块
//-----------------------------------------------------------
#define _I2CH

#i nclude "..\works.h"

//-----------------------------------------------------------
//SCK回调函数
//-----------------------------------------------------------
void InI2C_SCK( unsigned int mData )
{
    if( mData ){
        rGPEDAT |= (1<<14);
    }
    else {
        rGPEDAT &= ~(1<<14);
    }
}

//-----------------------------------------------------------
//SDA回调函数
//逻辑0、1输出到IO口,0xff返回IO状态
//-----------------------------------------------------------
unsigned char InI2C_SDA( unsigned int mData )
{
    switch( mData ){
        case 0:   
                rGPEDAT &= ~(1<<15);
                break;
               
        case 0xff:
                if( rGPEDAT&(1<<15) )mData = 1;
                else mData = 0;
                break;

        default:
                rGPEDAT |= (1<<15);
                break;
    }
    return mData;
}

//-----------------------------------------------------------
//初始化
//-----------------------------------------------------------
void I2C_Init(void)
{
    //初始化IO口为OpenDrain
    InI2C_SCK(1);
    InI2C_SDA(1);
    rGPECON = (rGPECON & ~0xf0000000) | 0x50000000;
   
    I2CBus_Init( InI2C_SCK, InI2C_SDA, 200 );
}

//-----------------------------------------------------------
//析构
//-----------------------------------------------------------
void I2C_Destory(void)
{
    I2CBus_Destory();
   
    rGPECON &= ~0xf0000000;
}

H文件:
//-----------------------------------------------------------
//EEPROM器件
//-----------------------------------------------------------
#i nclude "..\Universal\I2CBus.h"

#define DEVICE0        0                            //物理地址Device
#define AT24C128

#ifdef FM24CL16
    #define EEPROM_ReadByte(addr)                    I2CBus_ReadByte( (addr>>8)|0x80, addr&0xff )
    #define EEPROM_ReadShort(addr)                    I2CBus_ReadShort( (addr>>8)|0x80, addr&0xff )
    #define EEPROM_ReadInt(addr)                    I2CBus_ReadInt( (addr>>8)|0x80, addr&0xff )
    #define EEPROM_ReadToBuf(addr, p, Length)        do{ I2CBus_ReadToBuf( (addr>>8)|0x80, addr&0xff, p, Length );}while(0)
    #define EEPROM_WriteByte(addr,data)                do{ I2CBus_WriteByte( (addr>>8)|0x80, addr&0xff, data );}while(0)
    #define EEPROM_WriteShort(addr,data)            do{ I2CBus_WriteShort( (addr>>8)|0x80, addr&0xff, data );}while(0)
    #define EEPROM_WriteInt(addr,data)                do{ I2CBus_WriteInt( (addr>>8)|0x80, addr&0xff, data );}while(0)
    #define EEPROM_WriteFromBuf(addr, p, Length)    do{ I2CBus_WriteFromBuf( (addr>>8)|0x80, addr&0xff, p, Length );}while(0)
#endif

#ifdef AT24C128
    #define EEPROM_ReadByte(addr)                    I2CBus_ReadByte( DEVICE0, addr )
    #define EEPROM_ReadShort(addr)                    I2CBus_ReadShort( DEVICE0, addr )
    #define EEPROM_ReadInt(addr)                    I2CBus_ReadInt( DEVICE0, addr )
    #define EEPROM_ReadToBuf(addr, p, Length)        do{ I2CBus_ReadToBuf( DEVICE0, addr, p, Length );}while(0)
    #define EEPROM_WriteByte(addr,data)                do{ I2CBus_WriteByte( DEVICE0, addr, data );}while(0)
    #define EEPROM_WriteShort(addr,data)            do{ I2CBus_WriteShort( DEVICE0, addr, data );}while(0)
    #define EEPROM_WriteInt(addr,data)                do{ I2CBus_WriteInt( DEVICE0, addr, data );}while(0)
    #define EEPROM_WriteFromBuf(addr, p, Length)    do{ I2CBus_WriteFromBuf( DEVICE0, addr, p, Length );}while(0)
#endif

#ifndef _I2CH
    //-----------------------------------------------------------
    //初始化
    //-----------------------------------------------------------
    extern void I2C_Init(void);

    //-----------------------------------------------------------
    //析构
    //-----------------------------------------------------------
    extern void I2C_Destory(void);
#endif

 


* - 本贴最后修改时间:2006-11-9 9:44:29 修改者:农民讲习所

 


签名:

 


农民代表
 
 

 IC1008 发表于 2006-11-9 09:48 侃单片机 ←返回版面   

学习了

我当时用mega16L写的程序上电老是发现24c02错误
最好启动了 相关电源的检测(例如低电压复位芯片),防止程序乱跑
问题就没有了 正如00大侠所说的
电源我觉得是很大的麻烦的
我公司的程序是按页连续写的

 


 

 wangshujun 发表于 2006-11-9 10:04 侃单片机 ←返回版面   

根本要确保电源状态可以预知

1、检测系统供电是否正常,当供电中断后不再开始新的写入操作。
2、检测mcu供电是否正常,当过低时强制复位mcu保证不会误操作。
3、系统供电停止信号产生后保障足够的时间后再发生mcu复位(足够完成已经开启的写操作)。

 


 

 squarelook 发表于 2006-11-9 15:57 侃单片机 ←返回版面   

我是这样用的

比如我保存A参数和B参数,每次保存我的格式是ABAB,下次保存的时候在邻居位置保存新的ABAB,然后把旧的ABAB擦掉,这样怎么上下电折磨它都没问题。不要单单考虑读写2401程序本身的问题,这种器件在单片机系统应用中各种因素加起来不可能不发生数据紊乱,关键是怎么把紊乱的数据想办法还原,实际应用的经验更重要的!


* - 本贴最后修改时间:2006-11-9 16:01:55 修改者:squarelook


 


 

 hotpower 发表于 2006-11-9 18:33 侃单片机 ←返回版面   

菜农就为匠人忽悠几句吧~~~

匠人猜想过的几中可能原因:

1、上拉电阻是采用CPU内部上拉电阻,是否太大了?
2、快速频繁地断电/上电,是否会打乱读写的时序?并凑巧拼接出一个错误的读写命令?
3、中断的打搅?(可能性不大吧?)

菜农认为1:
    最好再外加上拉电阻,5V时在4.7K左右,3.3V在3.3K左右.这样可加大驱动能力和加速边沿的翻转.
菜农认为2:
    这个是最关键的原因所在.
    首先应该提供电源的保护机制,即能及时知晓外部电源是否具备写入EEPROM数据的能量.
    如果有掉电中断,那么在系统完全失去能量前会有一端时间的.这个时间与系统的电容存储的电能等有关.在此时间里只能写入一部分的EEPROM数据,若写入的数据很小,可能全部写入成功.所以在外部EEPROM的环境下,最好加大电容甚至要加法拉电容,以便增大写入数据块的长度.
    在无掉电保护机制的环境下,可以采用迂回战术来弥补无保护机制的问题.主要应该做到以下考虑:
    1.上电后不应该立即对EEPROM进行写操作!
    2.在EEPROM中找个空闲位置,写入EEPROM正常标志,一般为0x55aa.
      这个标志有很多的意义:
      当读出不为0x55aa时,可认为是掉电或EEPROM为空白片或EEPROM为盗版片.我们可以采取任何的手段进行处理.
      在其他外围也不正常时,我们可认为是真掉电而进入休眠.否则,我们认为是EEPROM空白即可对其初始化.
      注意:必须对EEPROM初始化即写入全部的默认配置数据后,才能写入0x55aa标志!!!因为可能在没初始化后又再次掉电!!!
      这样做后才能保证EEPROM初始化数据的完整及可靠(可信).
    3.每次写入前最好先读出数据,若与写入数据相同就不要招惹EEPROM!!!
      这样在提高寿命的同时,也变相地把EEPROM当RAM使用了.
      最好在此再读0x55aa标志(可能老头很烦人),以变相地确定电源没掉电,至少能短期地保证后面数据写入的安全.
    4.写入数据后应该再次读出,若写入失败就应该再次重试3次以上,否则通知老板该EEPROM坏了.
    5.在写入前应该设置一个全局的写入成功标志为假.在写入和校验成功后,再设置其为真.
      如果在写入期间掉电,那么在启动程序时就应该处理其标志,这样可以"断点续写".
菜农认为3:
    此点并不是太重要,因为一般的I2C总线的SDA/SCL不会再被其他功能复用的,除非他是匠人~~~
    菜农主张必须在一处操作硬件,数据都应该放入缓冲区内处理,各模块无权操作I2C总线.必须由"专人负责"!!!
    这在菜农的设计中一直是这样坚持的,因为婆婆多了肯定坏事.


就忽悠到这里吧,菜农要喂肚子了~~~但认为最重要的是:
0x55aa,法拉电容,上拉电阻,数据校验,容错处理....


* - 本贴最后修改时间:2006-11-9 18:36:15 修改者:hotpower

 


签名:

●█〓██▄▄▄▄▄▄ ●●●●●●→ ''''╭WWWW╮
▄▅██████▅▄▃▂ 灌水入坛传播非典 ( ●_●)
██████████████ '''',,,;,;,;'''/▇\''
◥⊙▲⊙▲⊙▲⊙▲⊙▲⊙▲◤ 东戳西顶一片天/MMMM\
 
点击遨游水上蔬菜批发市场


打造21IC晕汁晕味晕菜的BLOG
 
 

刷新 社员投票 PAGE 1 / 1 共17篇 返回主题列表 返回前个操作 首页 前页 后页 尾页  


回复主题:讨论一下24C01中数据出错(丢失)的问题吧(HOTPOWER请进!!)


    版面: 侃单片机  ←返回版面
 
 


  用户名: 程序匠人
  Email:   回复请Email通知 如果不填写则取注册Email
* 主题:  (还可以输入0字节)  
  表情:  
                 
                 
  内容(最多34KB):  签名  设置     ALT+S发送 
        New!
  

  链接地址:   
  链接标题:   
  链接图片:  [上传图片/文件(300K以内(JPG|GIF|RAR|PDF))]上传管理   
  注意:怎样使用ABC代码
      带有*号的内容为必填内容 

 


 
 

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

本社区文章归作者和本公司所有 严禁复制 出版用于任何商业目的。

 版权所有 2000-2006 

看《匠人手记》,与匠人同行!北航出版,正在热卖!

  • 标签:I2C E2PROM EEPROM 可靠性 24C 
  • 悄悄话
    SQUANUKX(游客)发表评论于2008-4-1 19:41:00  个人主页 | 引用 | 返回 | 删除 | 回复

    SQUANUKX(游客)此留言是悄悄话!

    看《匠人手记》,与匠人同行!北航出版,正在热卖!

    Re:关于24C01中数据出错(丢失)的问题的讨论
    xdtyhbq发表评论于2006-11-17 20:10:00  个人主页 | 引用 | 返回 | 删除 | 回复

    xdtyhbq我个人认为:问题出在复位之前,

    看《匠人手记》,与匠人同行!北航出版,正在热卖!

    发表评论:
    载入中...

    芯片专题

    器件专题

    软件专题

    硬件专题

    综合专题

    项目专题

    原创专题

    器件检测
    LCD LED
    按键 触摸键
    E2PROM
    电池 电机
    电阻 电容 电感

    指令系统
    软件算法
    编程规范
    滤波算法
    串行通讯

    PCB设计
    I2C PWM
    红外遥控
    充电技术
    中断 ADC 

    匠人手记
    匠人夜话
    网络心路
    一周热点串烧
    从零开始玩PIC
    DIY旋转时钟

    广告5号位 [投放]


    学习板、开发板、编程器、下载器、仿真器(查看详情……)

    广告3号位 [投放]

    站内搜索


    站外搜索


    百度  google
    mp3  歌词 
    图片  FLASH 
    知道  文档
    新闻  词典 
    地图  mp3 
    软件  天网 
    雅虎  爱问 
    搜狗  讯雷 
    网讯  华军 
    天空 

    21IC器件搜索
    百宝箱分站
  • 《匠人的百宝箱》21IC站
  • 《匠人的百宝箱》21IC笔记团队
  • 《匠人手记》21IC书友会
  • 《匠人的百宝箱》MCUBLOG站
  • 《匠人的百宝箱》MCUBLOG笔记团队
  • 《匠人的百宝箱》EDN站
  • 《匠人手记》EDN书友会
  • 《匠人的百宝箱》与非网站
  • 《匠人的百宝箱》新浪站
  • 《匠人的百宝箱》百度站
  • 《匠人的百宝箱》网易126站
  • 《匠人的百宝箱》网易163站
  • 《匠人的百宝箱》互动出版网站
  • 广告4号位 [投放]

     
     

    匠人原创

    推荐阅读

    往日酷贴