打印

昨天遇到一个奇怪的问题,希望有知道完美解决方案的支持

[复制链接]
2026|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhaoyu2005|  楼主 | 2007-4-14 11:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
调试电路板时发现24C02的连续读有问题,具体现象是:有时对有时错,反复检查程序没有问题,后来换了几片24C02,连续读就很正常,再后来发现是先前24C02内部的地址问题造成的,先单独读一个字节,再连续读就很正常,但是这个片子放到编程器上读却很正常,有遇到的吗?

相关帖子

沙发
ayb_ice| | 2007-4-14 13:20 | 只看该作者

应该还是程序的问题

应该还是程序的问题,程序应该能应对各种不正常情况...

使用特权

评论回复
板凳
平常人| | 2007-4-14 13:23 | 只看该作者

很多种原因:程序、I2C总线匹配、供电、电源滤波等

使用特权

评论回复
地板
zhaoyu2005|  楼主 | 2007-4-17 10:55 | 只看该作者

总线上就一个24C02,也滤波了

还有就是错的很有规律,数据连续读对的次数和错的次数成很规律的交替

使用特权

评论回复
5
农民讲习所| | 2007-4-17 10:58 | 只看该作者

是否跨页问题?

02是8字节一页,连续读和写都只能在一页中完成.

使用特权

评论回复
6
tdwmcu| | 2007-4-17 11:15 | 只看该作者

可能是时序问题

你的时序可能处于边界状态,24C02稍微有点差别可能会造成错误

使用特权

评论回复
7
lyjian| | 2007-4-17 12:30 | 只看该作者

晕,读是不涉及到页的,连续读完一个芯片都可以

使用特权

评论回复
8
zhaoyu2005|  楼主 | 2007-4-17 15:22 | 只看该作者

不是跨页的问题

应该不是时序的问题,当时也考虑是延时不够,特意将延时加到约500uS,这样的话就是用3V供电的慢速器件也够了,仍旧不行,否则俺也不会上来求助大家了,现在到是能用,就是得每次连读之前先单字节读一次,俺感觉这不是正道,想采用彻底的正道解决

使用特权

评论回复
9
ayb_ice| | 2007-4-17 15:28 | 只看该作者

程序帖出来...

使用特权

评论回复
10
hyhmh| | 2007-4-17 15:34 | 只看该作者

可能是I2C总线操作的问题

上次读后没有正确完成设置逻辑电平
或本次启动信号无效

使用特权

评论回复
11
xuxyl2| | 2007-4-18 09:05 | 只看该作者

10楼的回答可能是正确的,比如你没有很好的发一个STOP条件

使用特权

评论回复
12
zhaoyu2005|  楼主 | 2007-4-19 10:04 | 只看该作者

STOP肯定发了,也想到是停止无效,特意多加了了一次

还是不行,程序在下边,请斧正

//
//******************************************
//-------------------------------------------
//char read02(char adr);            //读24c02指定地址内容
//void write02(char adr,char dt);   //把参数写入24c02指定地址
//char read8583(char adr);          //读8583指定地址内容 
//void write8583(char adr,char dt); //写参数到8583指定地址
//-------------------------------------------
//
//
// 
//00000000000000000000000000000000000000000000
//以下部分未用
                                        //
//读adr开始,num个字节,返回数组pm[]       //
//char read8(char adr,char num,char pm[])  //
//自己注意分页问题                         //
//                                         //
//写数组pm[]到adr开始,num个字节,         //
//void write8(char adr,char num,char pm[]) //
//                                         //
//数组长度小于8。                                         //
//                                         // 
//                                         //
//-----------------------------------------//

#define  w02   0xa0    //写器件地址
#define  r02   0xa1    //读器件地址
#define  Iio   TRISC4  //sda方向


char read02(char adr);    //读指定器件,指定地址地址
void write02(char adr,char dt);

void read02series(char adr,char num);   //连续读adr后num个字节.存prm
void write02series(char adr,char num);        //连续写adr地址后num个字节,地址和prm[]顺序一致

char rad (char);      
void trx (char,char);   //返回1=应答有效,  0=应答超时
void start (char);
void stop (char);
void ack (char);
void no_ack (char t);
void i2c_delay(char time);
//-----------------------------------





/*

//----------------------------------
void read02series(char adr,char num)
{


}
//-----------------
void write02series(char adr,char num)
{
  

}
//------------------
*/




//adr 起始地址   num 数据长度  数组用general[],
void read02series(char adr,char num)
{
      char i,dt,n=0;

       start(50);
       trx(w02,50);
       trx(adr,50);  //02地址
       start(50);
       trx(r02,50);    //
       n=0;
       
      for(;num!=0;num--)
       {
        clrwdt;
        dt=rad(50);
        show0=dt;
        show0=n;
        general[n++]=dt; //
        
        if(num!=0) ack(50);        
       }
      no_ack(50);    //非应答      
      stop(50);
}
//---------------------------------
//连续写adr地址后num个字节,地址和prm[]顺序一致
void write02series(char adr,char num)
{
    char i,dt,n=0;
       
    Sprotect=0;    //24写保护
    
    start(20);
    trx(w02,20);
    trx(adr,20);  //02地址
    for(;num!=0;num--)
     {     
       clrwdt;            
       trx(general[n++],20);
       adr++; 
      if(adr%8==0)
       {
        stop(20);
        delay(5000); 
        start(20);
        trx(w02,20);
        trx(adr,20);  //02地址        
       }            
     }    
     stop(20);
     delay(5000);
     Sprotect=1;    
}
//----------------------------------

//===================================
//
//写1字节
void write02(char adr,char dt)
{
      Sprotect=0;
      clrwdt;
      start(20);
      trx(w02,20);
      trx (adr,20);  //02地址
      trx(dt,20);    //数据
      stop(20);
      delay(1000);  //需要延时才能发下一字节.  
      Sprotect=1;    
}
//------------------------------
//读1字节
char read02(char adr)
{
     char dt;
     clrwdt;
     start (20);
     trx (w02,20);
     trx (adr,20);   //读02地址
     start(20);
     trx(r02,20);    //
     dt=rad(20);    //读数据
     no_ack(20);    //非应答
     stop(20); 

     
     return dt;       
}
//-----------------------------



//--------------------------------
//接收一个字节
char rad (char t)
{       
      char  i,dt=0;
            
      Iio=1;
             
      for(i=8;i!=0;i--)
         {       

           Scl=1;       
           dt<<=1;       
           delay(t);
           if(Sda)
              dt|=0x1;
           //else
              //dt|=0x0;   
           Scl=0;
           delay(t);
          
          } 

      return (dt);       
                    
}       
//----------------------

//--------------------
//返回0=应答有效,  1=应答超时
void trx (char data,char t)
{       
      char i;
      int  n=0;

      Iio=0;  
      Iictimeover=0;         //清除应答超时标志
       for(i=8;i!=0;i--)
         {

             Sda=data>>7;
             data<<=1;

           Scl=1;
           delay(t);
           Scl=0;
           delay(t);
             
         }
//等待应答     
      Sda=0;
      delay(t);
      Iio=1;
      nop;
      nop;      
      Scl=1;
     // delay(t);      
      

      n=50;           //1ms无返回,及认为超时
      while(Sda&!Iictimeover)   //返回0=应答有效,  1=应答超时
         {              //避免在此死循环,造成复位.
          if(--n==0){Iictimeover=1;}
         }
      Scl=0;   
      delay(t);


//-------------------

//------------------------------

//---------------
void start (char t)
{  //开始
   Iio=0;
    Sda=1;delay(t);
    Scl=1;delay(t);
    Sda=0;delay(t); 
    Scl=0;delay(t);   
}
//-------------
void stop (char t)
{  //停止
   Iio=0; 
   delay(t); Sda=0;
   delay(t); Scl=1;
   delay(t); Sda=1;

}
//-------------
void ack (char t)
{        //应答
    Iio=0;
    delay(t); Sda=0;
    delay(t); Scl=1;
    delay(t); Scl=0; 
}
//--------------
void no_ack (char t)
{
    Iio=0;
    delay(t); Sda=1;
    delay(t); Scl=1;
    delay(t); Scl=0; 
}
//-------------

//-------------

使用特权

评论回复
13
ayb_ice| | 2007-4-19 10:38 | 只看该作者

随便说说

你的void read02series(char adr,char num)函数有点乱,
帮你修改下
void read02series(char adr,char num)
{
    char i,dt,n=0;

    start(50);
    trx(w02,50);
    trx(adr,50);  //02地址
    start(50);
    trx(r02,50);    //
    n=0;

    for(;num!=0;num--)
    {
        clrwdt;
        general[n++]=rad(50);
        if(num == 1){
            no_ack(50);    //非应答
        }else{
            ack(50);
        }
    }
    stop(50);
}
另外感觉你的程序逻辑上总有些不是很好如:
  n=50;           //1ms无返回,及认为超时
      while(Sda&!Iictimeover)   //返回0=应答有效,  1=应答超时
         {              //避免在此死循环,造成复位.
          if(--n==0){Iictimeover=1;}
         }
      Scl=0;
Iictimeover标志完全可以省略,因为n==0时Iictimeover=1,还没有仔细看你的程序。。。

使用特权

评论回复
14
zhaoyu2005|  楼主 | 2007-4-20 15:44 | 只看该作者

Iictimeover平时是0,在应答超时后置1

ayb_ice,大侠,谢谢,终于解决问题了,
if(num == 1){
            no_ack(50);    //非应答
        }else{
            ack(50);
就是这一点的问题,但是怎么也没有怀疑到是这儿的问题,也就没有仔细检查,只考虑时序方面的问题,原来的程序连读最后一个字节先给应答,再非应答停止,应该也能停止的,对后面的读应该没影响的,怎么就有影响了?

使用特权

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

本版积分规则

78

主题

2940

帖子

9

粉丝