[原创] AT24C02的一点异常

panda_man   2012-6-9 16:20 楼主

今天帮人调试了下AT24C02的程序,最终可以成功写入和读取,但是问题是读取的数值总是比关掉电源时的数值小2,而且在0~9这段期间不能成功写入,初始化都为9,例如在数值为3时断掉电源,假若成功保存,应该在重新开启电源时读取数值3,但结果显示的却是9。求大侠解释,谢谢~!个人怀疑是程序中的延时导致的。
以下是程序:
#include<reg51.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define PCF8591 0x90
#define AT24C02 0xa0
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
uchar code tablewe[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdF,0xbF,0x7F};
uchar AD_CHANNEL;
sbit sda=P2^0;
sbit scl=P2^1;
bit ack; //应答检验位
bit flag;
int dis[8],D[5],k;
char temp[];
char *p;
int num=0;
sbit led=P2^7;

void delay() //延时 5us
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
void delay_1ms(uchar i)
{
uchar j;
while(i--)
for(j=0;j<110;j++);
}
void start()
{
sda=1; //大于4.7us
delay();
scl=1;
delay();
sda=0; //大于4us
delay();
scl=0;
_nop_();
_nop_();

}
void stop()
{
scl=0;
_nop_();
_nop_();
sda=0;
_nop_();
_nop_();
scl=1;
delay(); // 大于4us
sda=1;
delay(); // 大于4.7us
}
void response(uchar a)
{
if(a==0) //在此发出应答或非应答信号 sda=0为应答 sda=1为非应答
sda=0;
else
sda=1;
delay();
scl=0;
_nop_();
_nop_();
scl=1; //延时大于4us
delay();
scl=0;
_nop_();
_nop_();
}

void write_byte(uchar sdadata)
{
uchar j;
for(j=0;j<8;j++)
{
sdadata=sdadata<<1;
scl=0;
delay(); // 允许数据线电平变化

sda=CY; //将PSW最高位MSB 送走
delay();

scl=1; //拉高时钟线 数据有效
delay();
}
scl=0;
_nop_();
_nop_();
sda=1;
delay();// 释放总线,接受应答信号
scl=1;
delay();

if(sda==1)
ack=0;
else
ack=1;

scl=0; //钳住I2C总线,允许应答时 。SDA发生电平变化
_nop_();
_nop_();
}
uchar read_byte()
{
uchar m,data_read;
data_read=0;
sda=1;
for(m=0;m<8;m++)
{
scl=0;
delay(); // 在这5us里,发送数据

scl=1;
delay();

data_read=(data_read<<1)|sda;

}
scl=0;
delay();
return data_read;
}
char send(uchar qijian_address,uchar suba,uchar *data1,uchar no) // 发函数 no为字节数
{
uchar i;
start();
write_byte(qijian_address);
if(ack==0)
return(0);
write_byte(suba); //suba为器件内部储存单元地址
if(ack==0)
return(0);
for(i=0;i<no;i++) //页方式输入
{
write_byte(*data1);
if(ack==0)
return(0);
data1++;
}
stop();
return(1);
}
uchar receive(uchar qijian_address,uchar address,uchar no) //
{
uchar *data2,i;

start();
write_byte(qijian_address); //指定器件接收
if(ack==0)
return(0);
write_byte(address); //指定器件储存单元地址
if(ack==0)
return(0);

start();
write_byte(qijian_address+1);
if(ack==0)
return(0);

for(i=0;i<no-1;i++) //页方式输入 每页8个字节 详情请百度页地址空间的“上卷”现象
{ //解决上卷现象的方法
*data2=read_byte();
response(0);
data2++;
}
*data2=read_byte(); //第8个字节后要用非应答而不能应答 所以上面的循环只循环7次
response(1); //发送非应答

stop(); //关闭总线
return data2;
}
void init() //初始化 释放总线
{
scl=1;
delay();
sda=1;
delay(); // init
}
/*bit DACconversion(unsigned char address,unsigned char c,unsigned char Val)
{
start(); //启动总线
write_byte(address); //发送器件地址
if(ack==0)
return(0);
write_byte(c); //发送控制字节
if(ack==0)
return(0);
write_byte(Val); //发送DAC的数值
if(ack==0)
return(0);
stop(); //结束总线
return(1);
}*/
void dispaly(int number)
{
int i;

dis[0]=table[number%10000/1000];
dis[1]=table[number%1000/100]|0x80;
dis[2]=table[number%100/10];
dis[3]=table[number%10];

dis[4]=table[number%10000/1000]; //千位
dis[5]=table[number%1000/100]|0x80; //百位带小数点
dis[6]=table[number%100/10]; //十位
dis[7]=table[number%10]; //个位

for(i=0;i<8;i++)
{
P0=dis;
P1=tablewe;
delay_1ms(1);
}
}
void main()
{

delay_1ms(1);
init();
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
num=receive(AT24C02,4,8);
while(1)
{
dispaly(num);
if(flag==1)
{
*p=num;
send(AT24C02,4,p,8);
flag=0;
}
}
}
void time()interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
k++;
if(k==20)
{
k=0;
num++;

if(num==100)
num=0;
flag=1;
}

}

回复评论 (3)

同样的问题也出现我项目中, 是用2402保存程序需要数据,客户说出现数据烧录不正确的情况,后来和芯片原厂进行沟通,他们提出修改烧写方法,结果问题得到解决,但是仿真时候会出错,实际测试OK,具体原因正在分析中!希望该答案对你有帮助,下面为具体解决办法,以后有问题多交流,我QQ260568227

      1、目前每写一个数据是16Bit,改成每次只写8Bit有效数据,另一个8BitFFH替代;

        如:待写数据是05A0h  ,保存到0AE0h地址。分成往0AE0h地址写两次数据,分别写:05FFhFFA0h两个,此种情况,仿真会出错,但是不影响实际板子

      2、每写一个16Bit数据后,需延时20ms

 

点赞  2012-6-11 16:08

24c02

后来查了一些资料:页写入方式允许在一个写周期内(10ms左右)对一个字节到一页的若干字节进行编程写入,AT24C02的页面大小为8B。采用页写入方式可以提高写入效率,但也容易发生事故。
还有一个“上卷”现象:片内地址再接收到每一个数据字节后自动+1,故装载一页以内数据字节时,只需输入首地址,如果写到此页的最后一个字节,主器件继续发送数据,数据将重新从该页的首地址写入,进而造成原来的数据丢失。
不知道这个属不属于上卷现象
点赞  2012-6-11 23:22

调试

再检查一遍。发现有个地方错了。可以解决初始化为9的问题。
void write_byte(uchar sdadata)
{
uchar j;
for(j=0;j<8;j++)
{
sdadata=sdadata<<1;
scl=0;
delay(); // 允许数据线电平变化

sda=CY; //将PSW最高位MSB 送走
delay();

scl=1; //拉高时钟线 数据有效
delay();
}
scl=0;
_nop_();
_nop_();
sda=1;
delay();// 释放总线,接受应答信号
scl=1;
delay();

if(sda==1)
ack=0;
else
ack=1;

scl=0; //钳住I2C总线,允许应答时 。SDA发生电平变化
_nop_();
_nop_();
}
uchar read_byte()
{
uchar m,data_read;
data_read=0;
sda=1;
for(m=0;m<8;m++)
{
scl=0;
delay(); // 在这5us里,发送数据

scl=1;
delay();

data_read=(data_read<<1)|sda;

}
scl=0;
delay();
return data_read;////////////这句应改为return *data_read;
}
但神奇的一幕是  修改后。却不能保存了。。而且。更神奇的是。。把原本的这个程序一摸一样的复制烧写进去后。。却出现乱码。。一摸一样的程序  之前虽然有问题。但至少能保存  也能正常显示。。现在却显示也不正常
点赞  2012-6-12 22:21
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复