搜索
bottom↓
回复: 18

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

[复制链接]

出0入0汤圆

发表于 2007-11-14 23:24:42 | 显示全部楼层 |阅读模式
如下面例程,我调用写一个字节函数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);
   
}

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

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2007-11-15 01:57:44 | 显示全部楼层
有没有接上拉电阻?

出0入0汤圆

 楼主| 发表于 2007-11-15 07:25:32 | 显示全部楼层
有啊,10k上拉电阻.

出0入0汤圆

 楼主| 发表于 2007-11-15 08:22:40 | 显示全部楼层
顶一下,没有人帮我啊.

出0入0汤圆

发表于 2007-11-15 08:52:24 | 显示全部楼层
顶一下收藏起来!

支持LZ

出0入0汤圆

发表于 2007-11-15 09:01:18 | 显示全部楼层
to 【楼主位】 apolloj :
   要根据datasheet读写时序来读写。
我觉得你漏掉了ack和no ack,导致不能连续调用。
加上后应该没问题了。

出0入0汤圆

 楼主| 发表于 2007-11-15 09:44:13 | 显示全部楼层
如下面,我读了两个byte,取回值都是正确的.如果是ACK的问题,第二个byte应该是错的,
请问你说的ACK 是指ATMEGA128要发出ACK信号给AT24C256吗? 是不是 (1<<TWEA)这位位使能?

波形如下图:




//------从机地址-----
    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);

出0入0汤圆

发表于 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);
}

出0入0汤圆

 楼主| 发表于 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);
}

出0入0汤圆

发表于 2007-11-15 11:38:40 | 显示全部楼层
顶 手上有两片24c256 什么时候用m128试一下 呵呵偷懒了

出0入0汤圆

发表于 2007-11-15 18:37:51 | 显示全部楼层
在我的新书第16章中,使用M16读写24C256.一共有4个例程:采用CVAVR内部函数、自己写的用I/O模拟I2C的、采用TWI中断的,已经任意读写的中间层函数的设计等。

出0入0汤圆

 楼主| 发表于 2007-11-17 17:31:55 | 显示全部楼层
已经搞定了,24c256用来保存1000段程式,每页2个段,每段29个byte.很好用.就是有个问没有测试,就是写上半页,下半面的数据会被变成0xff吗?

出0入0汤圆

发表于 2008-6-11 22:32:01 | 显示全部楼层
学到了,谢谢楼上的朋友

出0入0汤圆

发表于 2009-7-15 15:54:25 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-7-17 22:27:39 | 显示全部楼层
努力挖.......

出0入0汤圆

发表于 2009-9-25 15:26:13 | 显示全部楼层
谢谢七楼提示,一个困扰我三天的问题。

出0入0汤圆

发表于 2011-9-19 22:58:28 | 显示全部楼层
先记号一下,现在在用16调,一天了,还没出来

出0入0汤圆

发表于 2012-5-26 19:11:12 | 显示全部楼层
关注中,我的是51啊,没成功,很郁闷

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-8-26 20:47

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

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