apolloj 发表于 2007-11-14 23:24:42

ATMEGA128 TWI/I2C接口访问AT24C256 难题.

如下面例程,我调用写一个字节函数AT24C64WritePage()成功写入AT24C256,用示波器看,写一个字字节波形正确.
然后调用AT24C256ReadPage() 读个这个字节,能够成功读出并返回正确值,但用示波器看,发出结束指今后,总线SDA没有被拉高,一直为低.而且再次调用AT24C64WritePage() 或 AT24C256ReadPage() 则不能退出.请大家指点一下,问题出在那了呢?谢谢.

void AT24C256StartPage(uint page)
{
   uchar i;
    //------开始-----
   TWCR = (1<<TWINT)|(1<<TWSTA)| (1<<TWEN);
   while (!(TWCR & (1<<TWINT)));
   i=TWSR;
   if ((i & 0xF8) != 0x08) return;
   UART_putHex(i&0xf8);
   
    //------从机地址-----
    TWDR = 0xa0;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
    i=TWSR;
    if ((i & 0xF8) != 0x18) return;
   UART_putHex(i&0xf8);
   
    //------存储器地址H-----
    TWDR = (page*64)/256;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
    i=TWSR;
    if ((i & 0xF8) != 0x28) return;
   UART_putHex(i&0xf8);
   
    //------存储器地址L-----
    TWDR = (page*64)%256;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x28) return;
    UART_putHex(i&0xf8);

}


void AT24C256ReadPage(unsigned char page,unsigned char *p,unsigned char size)
{
    uchar i;

    AT24C256StartPage((page>>1));

   
    //------开始-----
    TWCR = (1<<TWINT)|(1<<TWSTA)| (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
   i=TWSR;
    if ((i & 0xF8) != 0x10) return;
    UART_putHex(i&0xf8);
                       
   //------从机地址-----
    TWDR = 0xa1;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x40) return;
    UART_putHex(i&0xf8);

    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x50) return;
    UART_putHex(i&0xf8);
    *p = TWDR;


    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);

}

void AT24C256WritePage(uint page,unsigned char *p,unsigned char size)
{
   uchar i;

    AT24C256StartPage(page>>1);

            TWDR = *p;
            TWCR = (1<<TWINT) | (1<<TWEN);
            while (!(TWCR & (1<<TWINT))) ;
        i=TWSR;
            if ((i & 0xF8) != 0x28) return;
        UART_putHex(i&0xf8);

    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
   
}

xiaoxu191 发表于 2007-11-15 01:57:44

有没有接上拉电阻?

apolloj 发表于 2007-11-15 07:25:32

有啊,10k上拉电阻.

apolloj 发表于 2007-11-15 08:22:40

顶一下,没有人帮我啊.

feitian215 发表于 2007-11-15 08:52:24

顶一下收藏起来!

支持LZ

hxke 发表于 2007-11-15 09:01:18

to 【楼主位】 apolloj :
   要根据datasheet读写时序来读写。
我觉得你漏掉了ack和no ack,导致不能连续调用。
加上后应该没问题了。

apolloj 发表于 2007-11-15 09:44:13

如下面,我读了两个byte,取回值都是正确的.如果是ACK的问题,第二个byte应该是错的,
请问你说的ACK 是指ATMEGA128要发出ACK信号给AT24C256吗? 是不是 (1<<TWEA)这位位使能?

波形如下图:
http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_180946.JPG



//------从机地址-----
    TWDR = 0xa1;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x40) return;
    UART_putHex(i&0xf8);

    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x50) return;
    UART_putHex(i&0xf8);
    *p = TWDR;

   p++;
   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    while (!(TWCR & (1<<TWINT))) ;
   i=TWSR;
    if ((i & 0xF8) != 0x50) return;
    UART_putHex(i&0xf8);
    *p = TWDR;




    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);

hxke 发表于 2007-11-15 10:05:12

是的,注意读最后一个字节后返回noack,其他情况返回ack即可。

uchar ReadByteACK(void){                              //从器件读出一个字节,返回ACK
           TWCR= BIT(TWINT) | BIT(TWEA) | BIT(TWEN);
           while (!(TWCR & BIT(TWINT)));
        return(TWDR);
}
uchar ReadByteNOACK(void){                              //从器件读出一个字节,返回NOACK
           TWCR= BIT(TWINT) | BIT(TWEN);
           while (!(TWCR & BIT(TWINT)));
        return(TWDR);
}

apolloj 发表于 2007-11-15 10:21:27

谢谢 hxke
刚才搞定了,
原因是因为读最后一个字节的时候发送了ACK,就算ATMEGA128发送STOP,AT24C256也不释放SDA,导致下次操作TWI的总线冲突.正确的做法是读最后一个字节时,请使用NACK发送,即TWCR= BIT(TWINT) | BIT(TWEN);

正确读页程式如下:
void AT24C64ReadPage(unsigned char page,unsigned char *p,unsigned char size)
{
    AT24C64StartPage((page>>1));
   
    //------重新开始-----
    TWCR = (1<<TWINT)|(1<<TWSTA)| (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != IIC_RE_START) return;
                       
   //------从机地址-----
    TWDR = 0xa1;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
    if ((TWSR & 0xF8) != MR_SLA_ACK) return;

    //读数据
    for (;size>1;size--,p++)
    {
      TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
      while (!(TWCR & (1<<TWINT))) ;
      if ((TWSR & 0xF8) != MR_DATA_ACK) return;
      *p = TWDR;
    }

    //读最后一个数据,发送NACK
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT))) ;
    if ((TWSR & 0xF8) != MR_DATA_NOACK) return;
    *p = TWDR;

    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}

lanshuitianxia 发表于 2007-11-15 11:38:40

顶 手上有两片24c256 什么时候用m128试一下 呵呵偷懒了

machao 发表于 2007-11-15 18:37:51

在我的新书第16章中,使用M16读写24C256.一共有4个例程:采用CVAVR内部函数、自己写的用I/O模拟I2C的、采用TWI中断的,已经任意读写的中间层函数的设计等。

apolloj 发表于 2007-11-17 17:31:55

已经搞定了,24c256用来保存1000段程式,每页2个段,每段29个byte.很好用.就是有个问没有测试,就是写上半页,下半面的数据会被变成0xff吗?

star0928 发表于 2008-6-11 22:32:01

学到了,谢谢楼上的朋友

vv3g 发表于 2009-7-15 15:54:25

学习

wafendang 发表于 2009-7-17 22:27:39

努力挖.......

nbfeng 发表于 2009-9-25 15:26:13

谢谢七楼提示,一个困扰我三天的问题。

sunicecream 发表于 2011-9-19 22:58:28

先记号一下,现在在用16调,一天了,还没出来

fly_02827 发表于 2012-5-26 19:11:12

关注中,我的是51啊,没成功,很郁闷

waidianzi 发表于 2013-8-6 21:40:50

牛人!学习了
页: [1]
查看完整版本: ATMEGA128 TWI/I2C接口访问AT24C256 难题.