标题: 求指点:单片机向EEPROM内写入一个数,然后再把他读出来验证写入成功。但结果是255 [打印本页]

作者: Amlee    时间: 2020-3-15 14:05
标题: 求指点:单片机向EEPROM内写入一个数,然后再把他读出来验证写入成功。但结果是255
求大神指点:我想向EEPROM内写入一个数,然后再把他读出来验证写入成功,以此来学习IIC通讯协议的用法。但是读出来的结果是255,不管怎么调试都没用。哪位高手有逻辑分析仪能帮我看看是哪里出错了吗?

单片机源程序如下:
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define At24c02ADDR 0xa0                             //At24c02EEPROM地址宏定义
#define I2cWrite 0
#define I2cRead 1
sbit SCL=P2^1;
sbit SDA=P2^0;
sbit dula=P2^6;
sbit wela=P2^7;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,                        //编码表
                    0x7d,0x07,0x7f,0x6f,0x77,0x7c,
                                        0x39,0x5e,0x79,0x71,0x00     };
bit AcKFlag;
uchar bai,shi,ge;
void delay(uint z)                   //定义 延时函数
{
uint x,y;
for(x=0;x<100;x++)
         for(y=0;y<z;y++);
}

void delay5us()                  //定义  延时函数
{
_nop_();
}

void I2Cstart()                 //定义  起始信号函数
{
SDA=1;
SCL=1;
delay5us();
SDA=0;
delay5us();
}

void I2Cstop()                 //定义  停止信号函数
{
SCL=0;
SDA=0;
SCL=1;
delay5us();
SDA=1;
delay5us();
}

bit ReadAck()                //定义  主机读从机应答信号函数
{
SCL=0;
SCL=1;                           
delay5us();
if(SDA)
{                                         //非应答
          SCL=0;                         //拉低SCL(据波形图)
        return(1);
}
else
{
  SCL=0;
  return(0);
}


}

void SendAck(bit i)          //定义  主机发送应答
{
SCL=0;
if(i)
         SDA=1;
else
         SDA=0;
SCL=1;                                  //SCL拉高,读取数据
delay5us();                  //延时保持数据稳定
SCL=0;                                  //SCL拉低占用总线继续通信
SDA=1;                                  //释放sda         ,否则主机会一直占用sda
}

void I2cSendByte(uchar DAT)        //定义 写入数据操作逻辑函数
{
        uchar i;
        for(i=0;i<8;i++)
        {
                 SCL=0;
                delay5us();
                if(DAT&0x80)
                        SDA=1;
                else
                        SDA=0;
                SCL=1;
                delay5us();
                DAT<<=1;
        }
        SCL=0;                                    //拉低时钟总线,继续通信
        SDA=1;                                   //释放数据总线,允许其他设备传递数据
}

void At24c02write(uchar ADDR,DAT)        //定义  写入函数
{
  I2Cstart();                                  //起始信号
  I2cSendByte(At24c02ADDR+I2cWrite);  //发送从机地址+写信号
          if(ReadAck())
           AcKFlag=1;           //主机读应答信号:结果为无应答
          else
           AcKFlag=0;           //主机读应答信号:结果为有应答
  I2cSendByte(ADDR);           //调用写入数据操作逻辑函数:发送想要写入的内存地址
          if(ReadAck())
           AcKFlag=1;           
          else
           AcKFlag=0;           
  I2cSendByte(DAT);           //调用写入数据操作逻辑函数:发送要写入的数据
             if(ReadAck())
           AcKFlag=1;           
          else
           AcKFlag=0;
  I2Cstop();                      //停止信号
}

uchar I2cReadByte()           //读取从机内存数据逻辑子函数
{
uchar i,DAT;
for(i=0;i<8;i++)
         {
          DAT<<=1;
          SCL=0;                   //读数据时SDA由从机控制,主机只要控制scl时序,接收sda上的数据即可
          SCL=1;
          if(SDA)
                  DAT|=0x01;
          delay5us();
        }
return(DAT);
}

uchar At24c02Read(uchar ADDR)  //定义  读出函数
{
  uchar DAT;
  I2Cstart();                                  //起始信号
  I2cSendByte(At24c02ADDR+I2cWrite);  //发送从机(EEPROM)地址+写信号(此处发写信号是为了发送想要读取的内存单元的地址)
          if(ReadAck())
           AcKFlag=1;           //主机读应答信号:结果为无应答
          else
           AcKFlag=0;           //主机读应答信号:结果为有应答
  I2cSendByte(ADDR);           //发送想要读的内存地址
  ReadAck();                             //主机读应答信号(不管是否应答)
  I2Cstart();                   //重复起始信号
  I2cSendByte(At24c02ADDR+I2cRead);  //发送从机地址+读信号
  if(ReadAck())                   //判断应答信号
           AcKFlag=1;           
          else
           AcKFlag=0;
  DAT=I2cReadByte();   //调用 读取从机内存数据逻辑子函数 读一个字节
  SendAck(1);                   //主机发送应答信号:非应答(非应答函数内包括,占用总线继续通信与释放数据总线允许其他设备调用的信号,故调用的子函数内部不必写
  I2Cstop();                   //发送停止信号
  return(DAT);                   //返回函数值
}

void display(uchar num)
{

bai=num/100;
shi=num%100/10;
ge=num%10;

while(1)
{
                wela=1;
                P0=0xdf;
                wela=0;
        dula=1;
                P0=table[bai];
                dula=0;
                        P0=0xff;
                delay(3);

        
                dula=1;
                P0=table[shi];
                dula=0;
                        P0=0xff;
                wela=1;
                P0=0xbf;
                wela=0;
                delay(3);

        
                dula=1;
                P0=table[ge];
                dula=0;
                        P0=0xff;
                wela=1;
                P0=0x7f;
                wela=0;
                delay(3);
}
}
void main()
{
At24c02write(0x02,6);
delay5us();
delay5us();                           //延时一会,待从机将先前接收的数据处理完毕,否则可能会读取失败
display(At24c02Read(0x02));
while(1);

}


作者: csmyldl    时间: 2020-3-15 17:39
读出是255,证明是数据未写进去,重点检查写入程序
作者: eastjack    时间: 2020-3-16 08:31
用示波器看i2c时序实现对不对
作者: 3ABC    时间: 2020-3-16 17:23
可能是读写时序没处理好吧,建议换汇编语言来处理这部分程序,可能更精准些。
作者: xianming    时间: 2020-3-19 12:52
可能是应答出了问题
作者: hi毁人不倦    时间: 2020-3-19 14:01
数据超过了?
作者: Kingsely    时间: 2020-3-20 09:49
这个是时序不对,利用示波器/逻辑分析仪检查波形,根据手册说明调整时序即可
作者: cheney03    时间: 2020-9-17 13:58
有可能是时序有问题,时序必须严格对照数据手册
作者: 飞天芭蕾    时间: 2021-8-13 14:40
时序问题,可采用示波器复现修正
作者: sustlixin    时间: 2021-8-14 09:30
这个读写函数,我自己写过,你按着时序写了,然后用示波器看一下,感觉不是很难的
作者: 贵庚子    时间: 2021-9-2 09:37
你把时间多延迟一会,就是写入数据后,延迟时间稍微长一点,再读取数据
作者: 188610329    时间: 2021-9-2 14:54
首先IIC必须用上拉电阻,其次,Eeprom的写保护,要确保关闭。最后,确认一下设备地址,是否正确?
作者: shumivan    时间: 2021-9-13 11:48
肯定是时序的问题了,
作者: sgd985437    时间: 2021-9-13 14:27
1、检查IO口置高置低是否正常,万用表量一下。
2、检查IO口的读是否正常,是否能读到0   1  电平。
3、单片机如果不是准双向,需要在读之前设置为输入,读之后立刻设置为输出。
4、还是不行  那就是时序不对  或者延时不对。
作者: 188610329    时间: 2021-9-13 14:36
sgd985437 发表于 2021-9-13 14:27
1、检查IO口置高置低是否正常,万用表量一下。
2、检查IO口的读是否正常,是否能读到0   1  电平。
3、单 ...

此帖 楼主 于2020年 3 月 发的帖子,至今1年半,只有63黑币。这种僵尸贴,就没有必要翻出来回复了吧?而且也不是结论性的答复,也不会对其他坛友有任何参考价值。




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1