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);
} 有没有接上拉电阻? 有啊,10k上拉电阻. 顶一下,没有人帮我啊. 顶一下收藏起来!
支持LZ to 【楼主位】 apolloj :
要根据datasheet读写时序来读写。
我觉得你漏掉了ack和no ack,导致不能连续调用。
加上后应该没问题了。 如下面,我读了两个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); 是的,注意读最后一个字节后返回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);
} 谢谢 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);
} 顶 手上有两片24c256 什么时候用m128试一下 呵呵偷懒了 在我的新书第16章中,使用M16读写24C256.一共有4个例程:采用CVAVR内部函数、自己写的用I/O模拟I2C的、采用TWI中断的,已经任意读写的中间层函数的设计等。 已经搞定了,24c256用来保存1000段程式,每页2个段,每段29个byte.很好用.就是有个问没有测试,就是写上半页,下半面的数据会被变成0xff吗? 学到了,谢谢楼上的朋友 学习 努力挖....... 谢谢七楼提示,一个困扰我三天的问题。 先记号一下,现在在用16调,一天了,还没出来 关注中,我的是51啊,没成功,很郁闷 牛人!学习了
页:
[1]