关于24C02的头痛的问题,有哪位碰到过这些问题,请指点一下

2020-01-20 19:01发布

关于24C02迷惑的问题
  我想多次向24C02写入多个数据,源程序都写好,在送入数据时,如果每次写入4个数据,有时可以显示正常,有时不正常,如果每次写入6个数,则显示就出现不可预料的问题。请问单次向24C02写入数据个数有什么限制吗?附上源程序,测试过源程序没有什么问题,就是在一次向24C02写入数据个数上有问题,看了别人很多贴貌似是与24C02一页写入的数据个数限制有关,具体有什么关系,问题出在哪调试了好久都没有弄明白。请大侠帮忙看看,谢谢

这是24C02的读写程序,测试貌似没有问题,也许是这其中问题我没发现,请指导
/********************************************************************************************************************/
//*******************************************************************

//***IIC总线芯片为24C02,读写程序。
//*******************************************************************
#include "reg52.h"
#include<intrins.h>
#define  uchar unsigned char        
#define  uint  unsigned int
#define  nop  _nop_()       /* 定义空操作指令 */
sbit SCL=P3^4;                                /*24C01 CSL接脚=89C51 T0 P3.4*/
sbit SDA=P3^5;                                /*24C01 SDA接脚=89C51 T1 P3.5*/
bit TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no); /* 向有子地址器件写入6字节数据函数 */
bit TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no);  /* 向有子地址器件读取6字节数据函数 */
bit acknow;                                 /* 应答标志位 acknow=1 表示正常响应 acknow=0 表示未响应 */

void delay (unsigned int value)                /*延时副程式*/
{
      while (value!=0) value--;                /*10US延时*/
}
                       



void Start();                           /* 起动总线函数 */
void Stop();                            /* 结束总线函数 */
void SendByte(uchar c);                 /* 8951发数据或地址给8583 字节数据发送函数 */
uchar RcvByte();                        /* 8951从24C01读数据字节数据接收函数 */
void Ack(bit a);                        /* 主机8951应答子函数 */




/*******************************************************************/
//   24C02芯片读写        起动总线函数               
//函数原型: void  Start();  
//功能:     启动总线,发送24c02启动条件.  
//==================================================================
void Start()
{//SDA=0;

  // SCL=0;
   SDA=1;           /*发送起始条件的数据信号*/
   nop;
   SCL=1;
   nop;            /*起始条件建立时间大于4.7us,延时*/
   nop;
   nop;
   nop;
   nop;   
   SDA=0;           /*发送起始信号*/
   nop;            /* 起始条件锁定时间大于4us*/
   nop;
   nop;
   nop;
   nop;      
   SCL=0;           /*钳住总线,准备发送或接收数据 */
   nop;
   nop;
  
}
//==================================================================
//                      结束总线函数               
//函数原型: void  Stop();  
//功能:     结束总线,发送24c02结束条件.  
//==================================================================
void Stop()
{
// SCL=0;
  SDA=0;          /*发送结束条件的数据信号*/
  nop;           /*发送结束条件的时钟信号*/
  SCL=1;          /*结束条件建立时间大于4us*/
  nop;
  nop;
  nop;
  nop;
  nop;
  SDA=1;          /*发送总线结束信号*/
  nop;
  nop;
  nop;
  nop;

}
//==================================================================
//                 89X52发数据或地址给24c02 字节数据发送函数               
//函数原型: void  SendByte(uchar c);
//功能:   将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
//        此状态位进行操作.(不应答或非应答都使acknow=0)     
//               发送数据正常,acknow=1; acknow=0表示被控器无应答或损坏。
//==================================================================
void  SendByte(uchar c)
{ uchar count;
for(count=0;count<8;count++)  /*要传送的数据长度为8位*/
    {if((c<<count)&0x80)
         SDA=1;                /*判断发送位*/
     else  
         SDA=0;               
     nop;
     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
      nop;
      nop;             /*保证时钟高电平周期大于4us*/
      nop;
      nop;
      nop;         
     SCL=0;
    }
    nop;
    nop;
    SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
    nop;
    nop;   
    SCL=1;
    nop;
    nop;
    nop;
    if(SDA==1)
      acknow=0;        /* 24c02无应答 */     
    else
      acknow=1;        /* 发送数据正常 */
    SCL=0;
    nop;
    nop;
}
//==================================================================
//                 89X52从24c02读数据字节数据接收函数               
//函数原型: uchar  RcvByte();
//功能:            用来接收从器件传来的数据,并判断总线错误(不发应答信号),
//          发完后请用应答函数应答从机。  
//==================================================================
uchar  RcvByte()
{uchar retc=0;
uchar count;
SDA=1;                             /*置数据线为输入方式*/
for(count=0;count<8;count++)
   {    nop;           
        SCL=0;                  /*置时钟线为低,准备接收数据位*/
        nop;
        nop;                 /*时钟低电平周期大于4.7us*/
        nop;
        nop;
        nop;
        SCL=1;                  /*置时钟线为高使数据线上数据有效*/
        nop;
        nop;
        retc=retc<<1;
        if(SDA==1)
        retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
        nop;
        nop;
  }
  SCL=0;   
  nop;
  nop;
  return(retc);
}
//==================================================================
//                     主机89X52应答子函数
//函数原型:  void Ack(bit a);
//功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
//==================================================================
void Ack(bit a)
{if(a==0)                  
     SDA=0;                  /*在此发出应答或非应答信号 */
  else                       /* 应答 a=0  非应答 a=1 */
     SDA=1;
  nop;
  nop;
  nop;      
  SCL=1;
  nop;
  nop;                    /*时钟低电平周期大于4us*/
  nop;
  nop;
  nop;  
  SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  nop;
  nop;   
}
//==================================================================
//                 用户接口函数                                   
// 有无子地址表示是否向芯片的特定地址写数据  
//          向有子地址器件写入6字节数据函数  对应数据资料中的写模式            
//函数原型: bit  TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no);  
//功能:     从启动总线到发送从地址,子地址,数据,结束总线的全过程,从器件
//          地址slaaddress,子地址subaddress,发送内容是s指向的内容,no=字节数
//          如果返回1表示操作成功,否则操作有误。
//注意:    使用前必须已结束总线。
//==================================================================
bit TSendAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no) /* 向有子地址器件写入6字节数据函数 */
{uchar i;
   Start();                               /*启动总线*/
   SendByte(slaaddress);        /*发送器件地址*/
   if(acknow==0)
  return(0);
   SendByte(subaddress);        /*发送器件子地址*/
   if(acknow==0)
  return(0);
   for(i=0;i<no;i++)
   {
     SendByte(* s);
                            /*发送数据*/
        if(acknow==0)
    return(0);
        s++;
   }   
   Stop();                                  /*结束总线*/
   return(1);
}
//==================================================================
//                    向有子地址器件读取4字节数据函数               
//函数原型: bit  TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no);  
//功能:     从启动总线到发送从地址,子地址,读数据,结束总线的全过程,从器件
//          地址slaaddress,子地址subaddress,读出的内容放入s, no=字节数
//           如果返回1表示操作成功,否则操作有误。
//注意:    使用前必须已结束总线。
//==================================================================
bit TRcvAddress(uchar slaaddress,uchar subaddress,uchar * s,uchar no)
{ uchar i;
   Start();                             /*启动总线*/
   SendByte(slaaddress);                /*发送器件从地址*/
  // if(acknow==0)
  // return(0);
   SendByte(subaddress);               /*发送器件子地址*/
   if(acknow==0)
   return(0);
   Stop();                   /*结束总线*/
   Start();                         /*重新启动总线*/
   SendByte(slaaddress+1);
  // if(acknow==0)
  // return(0);
   for(i=0;i<no-1;i++)
    {* s=RcvByte();               /*接收数据*/
     Ack(0);                     /*发送应答位*/
     s++;
    }                  
     * s=RcvByte();               /*接收数据*/
     Ack(1);
     Stop();                   /*结束总线*/
     return(1);
}
//==================================================================

/********************************************************************/
void main()
{        
     uchar  k,f,stad=0;
     uchar out[6]={8,9,6,7,5,4};
     Lcminit();                /*液晶初始化*/
     delay_10ms(10);        /*延时100ms*/
     Lcmcls();                   /*全屏清零*/
     for(k=0;k<63;k++){
        stad=k*4;
        TSendAddress(0xa0,stad,&out,4);//连续存储每次存储四个字节
        delay_10ms(10);
     }
   
while(1){
   for(f=0;f<63;f++) {
           uchar st=f*4;
           TRcvAddress(0xa0,st,&out1,4);//读出四个字节
           delay_10ms(50);
           for(i=0;i<40;i++) print1();//显示读出的数据
          Lcmcls();
          for(i=0;i<50;i++)print2();//显示读出的数据
          Lcmcls();
   }
}
将写入和读出改为每次6个字节就不会出现预想的结果了。
路过的请指点一写入与读出数据个数是否有规定,如果没有请哪位有时间的帮忙看看程序是否有问题。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
16条回答
easytime
2020-01-21 02:27
The data word address lower three (1K/2K) or four (4K, 8K, 16K) bits are internall
incremented following the receipt of each data word. The higher data word address bit
are not incremented, retaining the memory page row location. When the word address
internally generated, reaches the page boundary, the following byte is placed at th
beginning of the same page. If more than eight (1K/2K) or sixteen (4K, 8K, 16K) dat
words are transmitted to the EEPROM, the data word address will "roll over"and pre
ous data will be overwritten.

24c02的文档里详细说明,一个page就是8个字节。你写的时候,如果有超过这个边界,它就会翻卷回来写的,比如你从0x06开始写6个数据,那么结果写的地址就是0x06,0x07,0x00,0x01。。。翻卷回来把之前的覆盖了,所以你要注意边界问题。这只是讨论页写的注意事项,不代表你的程序的工作也都是没问题了。比如时序,地址等等,你也可以用逻辑分析仪抓捕这个过程,看看问题到底在哪里。


(原文件名:iic_full_chain.jpg)

一周热门 更多>