搜索
bottom↓
回复: 12

求助:ATMEGA8 TWI读写AT24C64不通

[复制链接]

出0入0汤圆

发表于 2007-12-14 13:53:19 | 显示全部楼层 |阅读模式
求助:ATMEGA8 TWI读写AT24C64不通

不知道怎么回事,TWI怎么都不通。




#define __TWI_C__

#include  "config.h"

#define TWI_START()            TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
#define TWI_RESTART()          TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
#define TWI_STATUS()           (TWSR&0xf8)
#define TWI_LOADDATA(x)        TWDR=(x),TWCR=(1<<TWINT)|(1<<TWEN)
#define TWI_STOP()              TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO)

#define TWI_WAIT() while((TWCR&(1<<TWINT))==0)

void twi_init(void)  //72K bps
{
  
    TWCR= 0X00; //disable twi
    TWBR= 0x20; //set bit rate
    TWSR= _BV(TWPS1)|_BV(TWPS0);  
    TWCR= _BV(TWEN); //enable twi
}


#define TWI_ReStart() TWI_Start()

uint8 TWI_Start(void)
{
  TWI_START();
  TWI_WAIT();
  return TWI_STATUS();  
}

void TWI_Stop()
{
   TWI_STOP();
  TWI_WAIT();
}


uint8 TWI_SendData(uint8 data)
{
  TWI_LOADDATA(data);
  TWI_WAIT();
  return TWI_STATUS();  
}

uint8 TWI_ReceiveData(uint8 *pdata,uint8 ack)
{
  uint8 temp=_BV(TWINT)|_BV(TWEN);
  if(ack)
  {
    temp|=_BV(TWEA);
  }
  TWCR=temp;
  TWI_WAIT();
  pdata[0]=TWDR;
  return TWI_STATUS();
}


#ifdef TWI_SLAW
uint8 TWI_WriteByte(uint16 addr ,uint8 data)
#else
uint8 TWI_WriteByte(uint8 TWI_SLAW, uint16 addr ,uint8 data)
#endif
{
          if(TWI_Start()!=TW_START) return 1;
          if(TWI_SendData(TWI_SLAW)!=TW_MT_SLA_ACK) return 2;
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 3;
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 4;
          if(TWI_SendData(data)!=TW_MT_DATA_ACK) return 5;        

          TWI_Stop();
          return 6;
}


#ifdef TWI_SLAR
uint8 TWI_ReadeByte(uint16 addr, uint8 *pdata)
#else
unsigned char TWI_ReadeByte(uint8 TWI_SLAR,  uint16 addr, uint8 *pdata)
#endif

      {
          if(TWI_Start()!=TW_START) return 0;
          if(TWI_SendData(TWI_SLAR&0xfe)!=TW_MT_SLA_ACK) return 1;
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 2;
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 3;
          if(TWI_ReStart()!=TW_REP_START)return 4;
          if(TWI_SendData(TWI_SLAR)!=TW_MT_SLA_ACK) return 5;
          if(TWI_ReceiveData(&pdata[0],0)!=TW_MT_DATA_ACK) return 6;           
          TWI_Stop();
          return 7;
      }



在TWI_WAIT()里死了

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

 楼主| 发表于 2007-12-14 14:51:24 | 显示全部楼层
用示波器看SCL大部分时间都是低电平.
用了10K的上拉电阻啊。

IO口初始时SDA和SCL的PORT和DDR怎么设置?

出0入0汤圆

 楼主| 发表于 2007-12-14 16:00:23 | 显示全部楼层
继续求助:
          if(TWI_SendData(addr>>8)!=TW_MT_SLA_ACK) return 3;  
          if(TWI_SendData(addr)!=TW_MT_SLA_ACK) return 4;  
这两句应该有问题,改成
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 3;
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 4;
结果死机,TWI_SendData(addr>>8)数据一直发不出去??
把AT24C64拔掉,上电只是写失败,程序可以正常运行。
把AT24C64插上,上电就会死机。

死机是出在TWI_WAIT()里面,一直等待TWINT置位,成了死循环。
#define TWI_WAIT()             while((TWCR&(1<<TWINT))==0)  



#ifdef TWI_SLAW
uint8 TWI_WriteByte(uint16 addr ,uint8 data)
#else
uint8 TWI_WriteByte(uint8 TWI_SLAW, uint16 addr ,uint8 data)
#endif
{
          if(TWI_Start()!=TW_START) return 1;                 //启动TWI总线
          if(TWI_SendData(TWI_SLAW)!=TW_MT_SLA_ACK) return 2;  //发送器件写地址0XA0
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 3;  //发送写数据地址高8位
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 4;     //发送写数据地址低8位
          if(TWI_SendData(data)!=TW_MT_DATA_ACK) return 5;     //发送数据  

          TWI_Stop();                                        //停止TWI总线
          return 6;
}

出0入0汤圆

 楼主| 发表于 2007-12-14 17:19:06 | 显示全部楼层
#define TWI_WAIT()             while((TWCR&(1<<TWINT))==0)

TWI_WAIT()里面,一直等待TWINT置位,成了死循环。
不知道怎么回事,AT24C64没有应答??


出0入0汤圆

发表于 2007-12-15 01:33:42 | 显示全部楼层
是否写得太快了。
tWR一般要求10mS

出0入0汤圆

 楼主| 发表于 2007-12-15 10:06:15 | 显示全部楼层
多谢楼上。好像不是这个问题。
我的测试程序1S写一次,再1S读一次。


继续求助。
我把TWI.c和TWI.h方上来,帮忙看一下程序哪里有问题。
点击此处下载ourdev_188692.rar(文件大小:1K)

出0入12汤圆

发表于 2007-12-15 10:45:38 | 显示全部楼层
我的也没有调通过,后来用软的。
继续等待高手。

出0入0汤圆

 楼主| 发表于 2007-12-15 11:00:57 | 显示全部楼层
#ifdef TWI_SLAW
uint8 TWI_WriteByte(uint16 addr ,uint8 data)
#else
uint8 TWI_WriteByte(uint8 TWI_SLAW, uint16 addr ,uint8 data)
#endif
{  
          if(TWI_Start()!=TW_START) return 1;  
          if(TWI_SendData(TWI_SLAW)!=TW_MT_SLA_ACK) return 2;  
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 3;  
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 4;  
          if(TWI_SendData(data)!=TW_MT_DATA_ACK) return 5;         

          TWI_Stop();
          return 6;  
}  
写的时候死机。




#ifdef TWI_SLAR
uint8 TWI_ReadeByte(uint16 addr, uint8 *pdata)
#else
unsigned char TWI_ReadeByte(uint8 TWI_SLAR,  uint16 addr, uint8 *pdata)
#endif

      {
          if(TWI_Start()!=TW_START) return 0;
          if(TWI_SendData(TWI_SLAR&0xfe)!=TW_MT_SLA_ACK) return 1;
          if(TWI_SendData(addr>>8)!=TW_MT_DATA_ACK) return 2;
          if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 3;
          if(TWI_ReStart()!=TW_REP_START)return 4;
          if(TWI_SendData(TWI_SLAR)!=TW_MT_SLA_ACK) return 5;
          if(TWI_ReceiveData(&pdata[0],0)!=TW_MT_DATA_ACK) return 6;           
          TWI_Stop();
          return 7;
      }
读的时候不会死机,第一次读返回值是5,再度返回值一直为0。

出0入0汤圆

 楼主| 发表于 2007-12-15 13:15:32 | 显示全部楼层
#define TEST_ADDR 0X011F
#define TEST_DATA 0X35

uint8 TEST_ARRY[8];

void TWI_Test(void)
{
    TWI_START();
    _delay_loop_2(1000);
    TEST_ARRY[0]=TWI_STATUS();//0X08
   
         
      TWI_LOADDATA(TWI_SLAW);      
    _delay_loop_2(1000);
    TEST_ARRY[1]=TWI_STATUS();//0XF8,这里旧不对了


          TWI_Stop();

}

出0入12汤圆

发表于 2007-12-16 14:05:44 | 显示全部楼层
我的twi调出来了(目标不是24cxx),可能和你类似,sda和scl一直都是小于1伏,用的内部上拉,没用外部上拉
现在拉了两个2k电阻,高电平拉到了4伏,波形出来了,返回的状态寄存器也对了。

发完这个帖子,刚好100分了

出0入0汤圆

 楼主| 发表于 2007-12-16 14:41:21 | 显示全部楼层
楼上能不能把程序贴出来看看,
TWI不知道怎么回事,怎么都不通。

出0入12汤圆

发表于 2007-12-17 23:07:34 | 显示全部楼层
两个机传数:
借鉴了 谢树宏 的自动代码生成软件。
从:
主程序,两个功能:给一个开始信号和准备数据,程序略。
中断里面:
SIGNAL(SIG_2WIRE_SERIAL)
{
        unsigned char uc;
        uc=TWSR & 0xf8;
         if(uc==0xa8)//从机识别出自已的SLA+R命令,并返回了ACK
                 {
                 //开始准备数据
                 if(sta)
                         {
                         TWDR=buffer[rp++];
                         TWCR|=_BV(TWINT);
                         }
                else
                        {
                        sta=1;
                        fst=1;
                         need=1;
                        TWCR=0x44;//不改变TWINT,但是禁止再次中断,等待主程序准备好数据
                        }
                 }
         else if(uc==0xb8)//从机已向主机发送数据且收到ACK
                 {
                if(rp==512)
                        {
                        need=1;
                        TWCR=0x44;//不改变TWINT,但是禁止再次中断,等待主程序准备好数据
                        }
                else
                        {
                         //继续送下一个数据
                        TWDR=buffer[rp++];
                        TWCR|=_BV(TWINT);
                        }
                 }
         else if(uc==0xc0)//从机已向主机发送数据且收到NOT ACK
                 {
                 //数据送完
                 //TWCR|=_BV(TWINT);
                 sta=0;
                TWCR=_BV(TWINT)|_BV(TWEA)|_BV(TWSTO)|_BV(TWEN)|_BV(TWIE);
                 }
         else if(uc==0xc8)//从机已向主机发送数据且收到ACK(TWAE=0)
                 {
                 //停止
                 //TWCR|=_BV(TWINT);
                 sta=0;
                 TWCR=_BV(TWINT)|_BV(TWEA)|_BV(TWSTO)|_BV(TWEN)|_BV(TWIE);
                 }
         else //未知错误
                 {
                 sta=0;
                TWCR=_BV(TWINT)|_BV(TWEA)|_BV(TWSTO)|_BV(TWEN)|_BV(TWIE);
                 }
}

主:
主程序,两个功能:给一个开始信号和保存数据,程序略。
中断里面:
SIGNAL(SIG_2WIRE_SERIAL)
{
        unsigned char uc;
        uc=TWSR & 0xf8;
        if(uc==0x08)//START已发送
                {
                TWDR=TWAR | 0x01;
                //TWDR= 0x85;;
                TWCR=(TWCR|_BV(TWINT))&~_BV(TWSTA);
                full=0;
                pages=0;
                }
        else if(uc==0x10)//RESTART已发送
                {
                TWDR=TWAR | 0x01;;
                //TWDR= 0x82;;
                TWCR=(TWCR|_BV(TWINT))&~_BV(TWSTA);
                full=0;
                pages=0;
                }
        else if(uc==0x38)//SLA+W发送或SLA+R发送或仲裁失败
                {
                TWCR|=_BV(TWSTA) | _BV(TWINT);
                }
        else if(uc==0x40)//SLA+R已发送,并收到ACK
                {
                TWCR|=_BV(TWINT) | _BV(TWEA);
                }
        else if(uc==0x48)//SLA+R已发送,并收到NOT ACK
                {
               
                TWCR|=_BV(TWSTA) | _BV(TWSTO) | _BV(TWINT);
                //TWCR|= _BV(TWSTO) | _BV(TWINT);
                }
        else if(uc==0x50)//数据已接收,并返回ACK
                {
                buffer[wp++]=TWDR;
                if(--filelength>1)
                        {
                        TWCR|=_BV(TWINT) | _BV(TWEA);
                        }
                else
                        {
                        TWCR&= ~_BV(TWEA);
                        }
                if(wp==528)
                        {
                        TWCR&=~_BV(TWIE);
                        full=1;
                        }
                }
        else if(uc==0x58)////数据已接收,并返回NOT ACK
                {
                buffer[wp++]=TWDR;
                TWCR|=_BV(TWINT) | _BV(TWSTO);
                full=1;
                }
}

不过看到你已经调出来了,恭喜。

出0入0汤圆

 楼主| 发表于 2007-12-17 23:11:10 | 显示全部楼层
多谢,已经搞定。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-17 14:11

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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