打印

为什么AT24C04写入的数据和读出的数据不一致呢?

[复制链接]
6918|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
doublers|  楼主 | 2011-8-8 21:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*
实验目的:

1、向EEPROM--24C04的第0个单元写入数字“3,第1个单元写入数字“5”操作;
2、读出EEPROM--24C04的第0个单元的值,并把这个值赋予第0个数码管的寄存器Reg_duan[0];
3、读出EEPROM--24C04的第1个单元的值,并把这个值赋予第1个数码管的寄存器Reg_duan[1];
4、把从EEPROM--24C04中读出来的值用两个数码管显示出来。

硬件电路:

1、24C04的A0,A1,A2,WP接地,SDA接P3.5,SCL接P3.4;
2、P0口接8位数码管的段,P2接数码管的位脚。
*/

#include <reg52.h>
#include <intrins.h>             //  _nop_();

#define OP_WRITE 0xa0       // 对这个器件进行写入操作,前7位为地址位最后一位为读写操作位,0代表写
#define OP_READ  0xa1        // 对这个器件进行器件进行读取操作

#define uint unsigned int  
#define uchar unsigned char

uchar data led_code[] ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xC0};    //0-9段值
uchar code led_wei [] ={ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };                           //8位数码管位选
uchar Reg_duan[8];     //8位数码管的寄存器

sbit SCL = P3 ^ 4;
sbit SDA = P3 ^ 5;

uchar read_out;          //存放从24C04中读出来的数据

//-----------------------------延时函数4.34us-----------------------------
void Delaynop(void)
{
  _nop_();
  _nop_();
  _nop_();
  _nop_();
}

//-----------------------------延时函数ms-----------------------------
void Delayms(uint ms)
{
  uchar k;
  while (ms--)
  {
    for (k = 0; k < 114; k++)
      ;
  }
}

//-----------------------------启动函数-----------------------------
//在 SCL 高电平期间 SDA 发生负跳变
void IIC_start()
{
  SDA = 1;
  SCL = 1;
  Delaynop();   //延时最少为4.7us
  SDA = 0;
  Delaynop();
  SCL = 0;      //一般情况下清零,因为他在低电平是数据才能变化
}

//-----------------------------停止函数-----------------------------
//在 SCL 高电平期间 SDA 发生正跳变
void IIC_stop()
{
  SDA = 0;
  SCL = 1;
  Delaynop();
  SDA = 1;
  Delaynop();
  SCL = 0;
}

//-----------------------------初始化函数-----------------------------
void IIC_init()
{
  SCL = 0;
  SDA = 1;     //初始化后SCL = 0,SDA = 1释放数据线
}

//-----------------------------发送应答位函数-----------------------------
//在 SDA 低电平期间 SCL 发生一个正脉冲,应答位为0
void IIC_ack()
{
  SDA = 0;
  SCL = 1;
  Delaynop();
  SCL = 0;
  SDA = 1;
}

//-----------------------------读一个字节函数-----------------------------
//从AT24C04读数据到MCU
uchar Readbyte()
{
  uchar i, read_data;
  SDA = 1;                        //置SDA为输入方式
  for (i = 0; i < 8; i++)
  {
    SCL = 1;                       //使SDA数据有效
    read_data <<= 1;          //调整接收位
    if (SDA)                         //读SDA
      read_data++;
    SCL = 0;                      //继续接收数据
  }
  return (read_data);
}

//-----------------------------写一个字节函数-----------------------------
//从MCU移出数据到AT24C04
void Writebyte(uchar write_data)
{
  uchar i;
  for (i = 0; i < 8; i++)                     // 循环移入8个位
  {
    SDA = (bit)(write_data &0x80);   //将发送位送入SDA数据线
    SCL = 1;
    Delaynop();
    SCL = 0;                                   //SDA数据线上数据变化
    write_data <<= 1;                      //调整发送位   
  }
}

//-----------------------------在指定地址addr处写入1个数据函数-----------------------------
void Write_byte(uchar addr, uchar dat)
{
  IIC_start();                     //起始位
  Writebyte(OP_WRITE);    //写0xa0,广播器件,并告诉要写
  IIC_ack();
  Writebyte(addr);             //写存储地址
  IIC_ack();
  
  Writebyte(dat);              //写数据
  IIC_ack();
  Delaynop();
   
  IIC_stop();                    //发送结束
}

//-----------------------------在指定地址addr处读出1个数据函数-----------------------------
void Read_byte(uchar addr)
{
  IIC_start();
  Writebyte(OP_WRITE);     //写0xa0,广播器件,并告诉要写,先写入地址
  IIC_ack();
  Writebyte(addr);             //写读取地址
  IIC_ack();
  IIC_start();
  Writebyte(OP_READ);      //写0xa1,广播器件,并告诉要读
  IIC_ack();
  read_out=Readbyte();     //读出数据写入相应显存单元
  IIC_ack();
  Delaynop();
  
  IIC_stop();                    //发送结束
}

//-------------------------------------------------------------------------------------------
void main(void)
{
  IIC_init();  
  Write_byte(0, 3);      //在AT24C04的第0个单元写入3
  Delayms(10);            //延时10ms,等待芯片自动编程完毕
  Write_byte(1, 5);      //在AT24C04的第1个单元写入5
  Delayms(10);            //延时10ms,等待芯片自动编程完毕
  
  Read_byte(0);          //读出AT24C04的第0个单元中的数据
  Delayms(10);
  Reg_duan[0]=read_out;    //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器

  Read_byte(1);                  //读出AT24C04的第1个单元中的数据
  Delayms(10);
Reg_duan[1]=read_out;     //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器


    while (1)
    {
     uchar i;
     for(i=0;i<2;i++)
      {
        P0 = led_code[Reg_duan];     //送数码管的段码
        P2 = led_wei ;                       //送数码管的位码
        Delayms(2);
      }
    }
}



/*
问题:为什么AT24C04写入的数据和读出的数据不一致呢?

将主函数中的相关语句改成这样

  Write_byte(0, 3);         //在AT24C04的第0个单元写入3
  Delayms(10);              //延时10ms,等待芯片自动编程完毕
  //Write_byte(1, 5);      //在AT24C04的第1个单元写入5
  //Delayms(10);           //延时10ms,等待芯片自动编程完毕
  
  Read_byte(0);                    //读出AT24C04的第0个单元中的数据
  Delayms(10);
  Reg_duan[0]=read_out;     //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器

  //Read_byte(1);                 //读出AT24C04的第1个单元中的数据
  //Delayms(10);
//Reg_duan[1]=read_out;    //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器

或改成这样
  //Write_byte(0, 3);       //在AT24C04的第0个单元写入3
  //Delayms(10);             //延时10ms,等待芯片自动编程完毕
  Write_byte(1, 5);         //在AT24C04的第1个单元写入5
  Delayms(10);               //延时10ms,等待芯片自动编程完毕
  
  //Read_byte(0);          //读出AT24C04的第0个单元中的数据
  //Delayms(10);
  //Reg_duan[0]=read_out;    //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器

  Read_byte(1);                    //读出AT24C04的第1个单元中的数据
  Delayms(10);
Reg_duan[1]=read_out;      //把AT24C04的第0个单元中的数据赋给第0号数码管的寄存器

即仅仅读写AT24C04的第0个单元或第1个单元,可以正确执行,但是要同时读写这两个单元,像程序中那样就会出错,
显示出来的数据总有一位不是写进去的数值。

这是为什么呢?

相关帖子

沙发
gaoyuaug| | 2012-12-16 15:09 | 只看该作者
楼上问题处理得有结果了么?我又遭遇到了

使用特权

评论回复
板凳
ohy3686| | 2012-12-16 16:38 | 只看该作者
SDA和SCL接上拉电阻了吗?

使用特权

评论回复
地板
NE5532| | 2012-12-16 20:29 | 只看该作者
显示程序单独测试过了没?

使用特权

评论回复
5
rqiang| | 2012-12-16 22:37 | 只看该作者
延时时间20ms好的

使用特权

评论回复
6
开启电子| | 2012-12-16 23:02 | 只看该作者
WP不宜直接接地、容易出问题,尝试下用IO控制。

使用特权

评论回复
7
ayb_ice| | 2012-12-17 08:04 | 只看该作者
应该是程序有问题吧

使用特权

评论回复
8
lu50211| | 2012-12-18 11:23 | 只看该作者
void delay(uchar j) //延时
{
        uchar i;
        for(;j>0;j--)
        for(i=20;i>0;i--);
}
//========================================
//====       AT24C02驱动函数        ====//
void at_start(void)//开始信号
{
        at_scl=1;
        at_sda=1;
        delay(1);
        at_sda=0;               
}
void at_stop(void)//停止信号
{
        at_scl=1;
        at_sda=0;
        delay(1);
        at_sda=1;       
}
void at_ack(void)//应答信号
{
    uchar i;
    at_scl=1;
        while(at_sda&&i<50)
    {
        i++;   
    }
        at_scl=0;
}
void at_send_bit_data(uchar temp_data)//写一字节数据
{
        uchar i;
        for(i=8;i>0;i--)
        {
                at_scl=0;
                if(temp_data&0x80)
                {
                        at_sda=1;       
                }       
                else
                {
                        at_sda=0;       
                }
        at_scl=1;
        delay(1);
                at_scl=0;
                temp_data<<=1;
        }       
}
uchar at_read_bit_data()//读一字节数据
{
        uchar i,temp_data;       
        for(i=8;i>0;i--)
        {
                temp_data<<=1;
        at_scl=0;
                if(at_sda)
                {
                        temp_data|=0x01;       
                }       
                else
                {
                        temp_data&=0xfe;       
                }
        at_scl=1;
        delay(1);
                at_scl=0;
        }
        return temp_data;
}
void at_write_data(uchar address,uchar date)//写数据
{
        at_start();
        at_send_bit_data(0xa0);//   write=0xa0;read=0xa1;
        at_ack();
        at_send_bit_data(address);
        at_ack();
        at_send_bit_data(date);
        at_ack();
        at_stop();                       
}
uchar at_read_data(uchar address)//读数据
{
        uchar temp_date;
        at_start();
        at_send_bit_data(0xa0);//   write=0xa0;read=0xa1;
        at_ack();
        at_send_bit_data(address);
        at_ack();
        at_start();
        at_send_bit_data(0xa1);//   write=0xa0;read=0xa1;
        at_ack();
        temp_date=at_read_bit_data();
        at_ack();
        at_stop();       
        return temp_date;
}

at_write_data(0x00,on_off_cnt);//把一字节数据on_off_cnt写到0x00地址中

on_off_cnt=at_read_data(0x00);//从地址0x00中读出一字节数据到on_off_cnt

使用特权

评论回复
9
ayb_ice| | 2012-12-18 11:47 | 只看该作者
停止信号不对,应该这样
void at_stop(void)//停止信号
{
        at_sda=0;
        at_scl=1;
//        at_sda=0;
        delay(1);
        at_sda=1;        
}

另外读数据时还要注意应答信号与非应答信号的区别

使用特权

评论回复
10
xouou_53320| | 2012-12-23 17:53 | 只看该作者
2个问题
1.  A0脚应该悬空
2.  停止信号函数不对

使用特权

评论回复
11
anazel| | 2012-12-24 09:31 | 只看该作者
程序有问题

使用特权

评论回复
12
gaoyuaug| | 2012-12-24 12:40 | 只看该作者
我用的是1T芯片,加延时10MS就可以了

使用特权

评论回复
13
jeffery_wang| | 2014-11-11 15:37 | 只看该作者
程序没问题,每写一个字节后要延时10ms,至少也得1.25ms等待写完成!否则写错!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

37

帖子

0

粉丝