找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5177|回复: 14
收起左侧

I2C通讯主机随便发个AT24C02的设备地址都能读取数据是怎么回事?

[复制链接]
ID:467739 发表于 2019-7-25 15:37 | 显示全部楼层 |阅读模式
STC89C52和AT24C02进行I2C通讯时,STC89C52主机向从机AT24C02随便发个设备地址,都能读写数据,是怎么回事喔?
具体情况:我的AT24C02的设备地址线A0 A1 A2都接地了的,数据手册上说的AT24C02的设备地址格式:(前四位固定)1010 A2 A1 A0 R/W,由于AT24C02的A0 A1 A2引脚我都在硬件上接地了的,正常情况我在进行读写数据时,发送的设备地址应该为(0xa0+R/W), 但是现在我在程序上随意改变设备地址的值(也就是A2 A1 A0的值),都能读写数据成功。
回复

使用道具 举报

ID:388197 发表于 2019-7-25 21:58 | 显示全部楼层
看看你程序里应答部分是怎么写的
回复

使用道具 举报

ID:123289 发表于 2019-7-26 09:18 | 显示全部楼层
当你序读取每一位的时候,总会认定的一个值,非0即1!
只不过读到的0/1是不是“目标设备”发出来的,就不好说了。
回复

使用道具 举报

ID:467739 发表于 2019-7-30 14:05 | 显示全部楼层
cjm82 发表于 2019-7-25 21:58
看看你程序里应答部分是怎么写的

/**
  * @brief  主机检测从机应答
  * @param  none
  * @retval return(1)应答,return(0)非应答
  */
bit Test_ACK()
{
        SCL=1;                         //拉高SCL线
        Delay_5us();
        if(SDA==1)                         //如果为1,则非应答
        {
                SCL=0;                 //拉低SCL线,使SDA线可以发送停止信号
                _nop_();
                I2C_Stop();           //发送停止信号
                return (0);           //非应答
        }
        else
        {
                SCL=0;                   //拉低SCL线
                _nop_();
                return (1);                //应答
        }               
}
应答程序部分就是这样写的,随便发个设备地址(A0A1A2三个引脚都接地了的),发现SDA都会被拉低。
回复

使用道具 举报

ID:467739 发表于 2019-7-30 18:59 | 显示全部楼层
yzwzfyz 发表于 2019-7-26 09:18
当你序读取每一位的时候,总会认定的一个值,非0即1!
只不过读到的0/1是不是“目标设备”发出来的,就不 ...

不能确定是不是目标设备发出的0/1, 我总线上就用了一个AT24C02芯片,这样是不是可以怀疑是芯片有问题
回复

使用道具 举报

ID:401564 发表于 2019-7-31 08:41 | 显示全部楼层
芯片有问题的情况并不多
你得写一个验证的程序,两个按键:写入并显示,读取并显示,地址可以是固定的某个地址
先向一个地址写入一个数据并显示
然后,断电,开机,不要写入,直接读取,数据是对的话,你的IIC代码就是对的
验证好程序之后,其它的再说
回复

使用道具 举报

ID:467739 发表于 2019-8-3 10:07 | 显示全部楼层
Y_G_G 发表于 2019-7-31 08:41
芯片有问题的情况并不多
你得写一个验证的程序,两个按键:写入并显示,读取并显示,地址可以是固定的某个 ...

你好,我用程序验证时,在I2C总线上只用一个AT24C02芯片,用的模拟I2C通讯;先写入一个数据到一个固定的地址,然后读取并显示在数码管上,下载运行时发现读取的结果正常,断电再上电,结果依然正常,然后去掉写入数据程序部分,只留下读取数据程序部分,再下载到开发板,发现读取的数据还是和之前写入的一样,断电再上电,读取结果依然正常,<<同时我又尝试将发送的器件地址改变,仅改变A0/A1/A2三位的数值,使它和硬件上连接的地址不相同,我开发板上的AT24C02芯片的A0A1A2都接地了的,重复上面的验证过程,发现结果还是一样,写入的数据和读取的数据相同, 但是 “将器件地址的高四位,也就是AT24C02固定的那四位1010,
1010 A0 A1 A2 R/W  也改变的话,就会读取和写入失败。”   >>
回复

使用道具 举报

ID:467739 发表于 2019-8-3 10:09 | 显示全部楼层
Y_G_G 发表于 2019-7-31 08:41
芯片有问题的情况并不多
你得写一个验证的程序,两个按键:写入并显示,读取并显示,地址可以是固定的某个 ...

对了,我用的芯片型号是,ATMEL 711 24C02 PU27 D
回复

使用道具 举报

ID:401564 发表于 2019-8-3 16:22 | 显示全部楼层
张松松 发表于 2019-8-3 10:09
对了,我用的芯片型号是,ATMEL 711 24C02 PU27 D

你能写入和读取,就说明读写的函数是正确的了
A0 A1 A2 这几个位在多个24C02并联使用时才会用到的,在24C02中,你只能改动R/W位,其它位是不能动的,1010是固定不变的,A0 A1 A2 这个是和24C02三个引脚的逻辑对应的,你接地了,就是000了,不能改,改了就找不到地址了
如果你是A0接了高电平,那么这三个应该就是:100
回复

使用道具 举报

ID:401564 发表于 2019-8-3 16:24 | 显示全部楼层
硬件电路上传看一下了
回复

使用道具 举报

ID:388197 发表于 2019-8-4 02:32 | 显示全部楼层
张松松 发表于 2019-7-30 14:05
/**
  * @brief  主机检测从机应答
  * @param  none

#define SCK_High GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define SCK_Low  GPIO_ResetBits(GPIOA,GPIO_Pin_1)

#define SDA_High GPIO_SetBits(GPIOA,GPIO_Pin_3)
#define SDA_Low  GPIO_ResetBits(GPIOA,GPIO_Pin_3)

#define SCK_read      GPIOA->IDR  & GPIO_Pin_1  
#define SDA_read      GPIOA->IDR  & GPIO_Pin_3  
typedef enum
{
  FALSE = 0,
  TRUE = !FALSE
} bool;

void I2C_delay()  
{     
   u8 i=100;     
   while(i)   
   {   
     i--;   
   }   
}  

bool I2C_Start()  
{  
    SDA_High;  
    SCK_High;  
    I2C_delay();  
    if(!SDA_read)
    {
        return FALSE;   //SDA线为低电平则总线忙,退出  
    }
    SDA_Low;  
    I2C_delay();  
    if(SDA_read)
    {
        return FALSE;   //SDA线为高电平则总线出错,退出  
    }
    SDA_Low;  
    I2C_delay();  
    return TRUE;  
}

void I2C_Stop()  
{  
    SCK_Low;  
    I2C_delay();  
    SDA_Low;  
    I2C_delay();  
    SCK_High;  
    I2C_delay();  
    SDA_High;  
    I2C_delay();  
}  

void I2C_Ack()  
{     
    SCK_Low;  
    I2C_delay();  
    SDA_Low;  
    I2C_delay();  
    SCK_High;  
    I2C_delay();  
    SCK_Low;  
    I2C_delay();  
}  

void I2C_NoAck()  
{     
    SCK_Low;  
    I2C_delay();  
    SDA_High;  
    I2C_delay();  
    SCK_High;  
    I2C_delay();  
    SCK_Low;  
    I2C_delay();  
}

bool I2C_WaitAck()   //返回TRUE有ACK,FALSE无ACK  
{  
    SCK_Low;  
    I2C_delay();  
    SDA_High;            
    I2C_delay();  
    SCK_High;  
    I2C_delay();  
    if(SDA_read)  
    {  
      SCK_Low;  
      return FALSE;  
    }  
    SCK_Low;  
    return TRUE;  
}

void I2C_SendByte(u8 SendByte) //数据从高位到低位//  
{  
    u8 i=8;  
    while(i--)  
    {  
      SCK_Low;  
      I2C_delay();  
      if(SendByte&0x80)
      {
        SDA_High;
      }
      else
      {
        SDA_Low;
      }
      SendByte<<=1;  
      I2C_delay();  
      SCK_High;  
      I2C_delay();  
    }  
    SCK_Low;  
}

u8 I2C_ReadByte(void)  //数据从高位到低位//  
{   
    u8 i=8;  
    u8 data=0;  
  
    SDA_High;               
    while(i--)  
    {  
      data<<=1;        
      SCK_Low;  
      I2C_delay();  
      SCK_High;  
      I2C_delay();   
      if(SDA_read)  
      {  
        data|=0x01;  
      }  
    }  
    SCK_Low;  
    return data;  
}
//===================24C02 读写程序===========================
bool AT24C02_WriteByte(u8 SendByte, u8 Address)  
{         
  if(!I2C_Start())
  {
    return FALSE;                                                           
  }
  I2C_SendByte(0xa0);     
  if(!I2C_WaitAck())  
  {  
    I2C_Stop();   
    return FALSE;  
  }  
  I2C_SendByte(Address);         
  I2C_WaitAck();      
  I2C_SendByte(SendByte);  
  I2C_WaitAck();     
  I2C_Stop();   
  Delay(15);                    //加个延时等待写完

  return TRUE;  
}

bool AT24C02_ReadByte(u8* data,u8 Adress)  
{         
  if(!I2C_Start())                       //如果总线忙,则返回失败.
    return FALSE;  
  I2C_SendByte(0xa0);            
  if(!I2C_WaitAck())                 //如果没有得到应答,则返回失败.
  {  
    I2C_Stop();   
    return FALSE;  
  }  
  I2C_SendByte(Adress);      
  I2C_WaitAck();  
  I2C_Start();  
  I2C_SendByte(0xa1);  
  I2C_WaitAck();  
  *data = I2C_ReadByte();     
  I2C_Stop();  
  return TRUE;  
}  


这个是我以前学I2C时的程序,和24C02的程序,不过是32的,你稍微改下,用在51也很简单,24C02的两个函数也就学习的时候用过下,后面基本没碰过.但前面的I2C程序我用过好几次,没发现问题.你可以参考下.
回复

使用道具 举报

ID:467739 发表于 2019-8-5 21:58 | 显示全部楼层
Y_G_G 发表于 2019-8-3 16:24
硬件电路上传看一下了

这是我开发板上的AT24C02电路图
电路图.png
回复

使用道具 举报

ID:467739 发表于 2019-8-5 22:30 | 显示全部楼层
Y_G_G 发表于 2019-8-3 16:22
你能写入和读取,就说明读写的函数是正确的了
A0 A1 A2 这几个位在多个24C02并联使用时才会用到的,在24 ...

我在面包板上接了两个AT24C02也试了下的,两片AT24C02芯片的硬件地址A0A1A2设置为不同,我在程序上分别向两块芯片发送数据,也是上面那种现象,A0A1A2随意改变,都能向芯片正确写入数据,并且正确读出。   
      同时我又发现一个诡异的现象,就是向第一块芯片的一个固定地址(程序里我选的储存地址是0x01,比如写个数据为0x27)写入数据,但是我没有向第二块芯片的储存地址0x01写入数据,接下来我直接读第二块芯片储存地址0x01里的数据,读出来的数据居然和我刚刚向第一块芯片储存地址0x01写入的数据相同(为了避免巧合我多次改变向第一块芯片写入的数据,发现实验现象和上面相同),也就是在向一块芯片写入数据时,两块芯片的相同储存地址里的内容都被写入数据了(A0A1A2随意改变也是这样)。
回复

使用道具 举报

ID:467739 发表于 2019-8-5 22:31 | 显示全部楼层
cjm82 发表于 2019-8-4 02:32
#define SCK_High GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define SCK_Low  GPIO_ResetBits(GPIOA,GPIO_Pin_1) ...

好的,thank you!!
回复

使用道具 举报

ID:467739 发表于 2019-8-5 22:51 | 显示全部楼层
Y_G_G 发表于 2019-8-3 16:22
你能写入和读取,就说明读写的函数是正确的了
A0 A1 A2 这几个位在多个24C02并联使用时才会用到的,在24 ...

感谢你的耐心回复喔!不准备纠结这个问题了,感觉还是我买的芯片有问题,后面有机会再换换芯片试试
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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