下面,我就说说那个让我做了5天的实验吧。代码其实还有点问题,有待以后改进。
实验目的:通过IIC总线读写EEPROM (AT24C08A)
相关的内容见赵老师的博客:http://blog.csdn.net/zhaocj/article/details/5477152
赵老师的程序是读写at24c02a,而我的板子上的是AT24C08A,但是原理是一样的。
想要读写某一芯片就必须好好看看它的芯片手册,否则可能会出现很奇怪的问题。
我从芯片手册上得知AT24C08A的容量为8Kbits,换算成字节就是1KB,不过开发板的使用手册上说AT24C08A有256B容量。这是为什么呢?
大家看看AT24C08A的芯片手册,原文有这么一句话:
The AT24C08A only uses the A2 input for hardwire addressing and a total of two 8K devices maybe addressed on a single bus system. The A0 and A1 pins are no connects.
这段话我翻译了一下,如下:
AT24C08A只使用A2引脚用来硬接线寻址,在同一个总线上总共有两个8K的AT24C08A能被寻址。A0,A1引脚悬空。
也就是说,当总线上有两片AT24C08A时,使用A2来决定选中哪一片。比如:A2=0时选中第一片,A2=1时选中第二片。
但是,mini2440开发板上是这样连接AT24C08A芯片的:
从图中可以看到:A2 A1 A0全部接地。
AT24C08A芯片手册中还有这么一句:
The 8K is internally organized with 4 blocks of 256 pages of 4-bytes each.Random word addressing requires a 10 bit data word address.
大体意思是:AT24C08A分成4块,一块64页,一共256页,每一页4B。(所以一块的大小是256B),随机寻址需要10位的地址。
其中我觉得A1 A0使用来选择哪一块的。但是mini2440开发板将A1 A0接地,所以只能寻址第一块的空间,所以才说AT24C08A容量有256B(其余的256B*3的空间没有使用)正确的解释看下面:
好了,我在吧我修改的代码附上,其中我有疑问的用问号标注,希望有朋友能和我共同探讨。
===========2013-5-15==========
今天有看了看芯片手册,结合韦老师的视频,发现原来的理解稍微有点偏差:
芯片手册有如下说明:
The 8K EEPROM only uses the A2 device address bit with the next 2 bits being for memory page addressing.
The A2 bit must compare to its corresponding hard-wired input pin.
The A1 and A0 pins are no connect.
学过IIC的童鞋知道,通信开始的时候要发一个开始信号,接着发从设备的地址,对于at24c08a来说,地址为 1 0 1 0 A2 P1 P0 r/w 这8位。
其中P1 P0 用来选择4页中的一页(块)。
所以即使A2 A1 A0都接地,但是,在发送从设备地址的时候,可以指定读哪一个页,就可以访问到全部1KB空间了。
//AT24C08A页写(最多写16个字节)
//输入参数依次为设备内存地址、IIC数据缓存数组和要写入的数据个数
void wr24c08a(unsigned char page, unsigned char wordAddr,unsigned char *buffer,int sizeofdate )
{
int i;
flag =1; //应答标志设置为1,表示没有进入IIC中断
IICDS = page;
//IICCON &= ~0x10; //清中断标志
IICSTAT = 0xf0; //主设备发送模式
uart0_puts("\n\rwait for ack after start signal........\n\r");
while(flag == 1){ //等待从设备应答,
uart0_puts("flag=1\n\r"); //如果将这句话注释条,程序就不能继续运行了。这是为什么????下面也是这样。
delay(10); //一旦进入IIC中断,设置flag=0之后,即可跳出该死循环
}
uart0_puts("receive the ack from the device\n\r");
uart0_puts("write device memory address\n\r");
flag = 1;
IICDS = wordAddr; //写入从设备内存地址
IICCON &= ~0x10; //恢复IIC传送
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
uart0_puts("get ack\n\r");
//连续写入数据
uart0_puts("write data to EEPROM\n\r");
for(i=0;i<sizeofdate;i++){
flag = 1;
IICDS = *(buffer+i);
IICCON &= ~0x10;
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
}
uart0_puts("finish writing\n\r");
IICSTAT = 0xd0; //发出stop命令,结束该次通讯
IICCON = 0xaf; //为下次IIC通讯做准备
delay(100); //等待
}
//AT24C08A的序列读,sizeofdate最大为256
//输入参数依次为设备内存地址、IIC数据缓存数组和要读取的数据个数
void rd24c08a(unsigned char page, unsigned char wordAddr,unsigned char *buffer,int sizeofdate)
{
int i;
unsigned char temp;
uart0_puts("\n\rDUMMY WIRTE\n\r");
flag =1;
IICDS = page;
// IICCON &= ~0x10; //清中断标志
IICSTAT = 0xf0; //主设备发送模式
uart0_puts("send device address\n\r");
while(flag)
delay(100);
uart0_puts("get ack\n\r");
uart0_puts("send word address \n\r");
flag = 1;
IICDS = wordAddr;
IICCON &= ~0x10;
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
uart0_puts("get ack\n\r");
uart0_puts("DUMMY WRITE FINISH.\n\r");
uart0_puts("host receive mode,send start signal again\n\r");
flag = 1;
IICDS = page; //
IICCON &= ~0x10;
IICSTAT = 0xb0; //主设备接收模式
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
uart0_puts("get ack\n\r");
uart0_puts("first data is device address\n\r");
flag = 1;
temp = IICDS; //读取从设备地址
IICCON &= ~0x10;
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
uart0_puts("get ack,decice address is \n\r" );
//连续读
uart0_puts("read data\n");
for(i=0;i<sizeofdate;i++){
flag = 1;
if(i==sizeofdate-1) //如果是最后一个数据
IICCON &= ~0x80; //不再响应
*(buffer+i) = IICDS;
IICCON &= ~0x10;
while(flag){
uart0_puts("flag=1\n\r");
delay(10);
}
}
uart0_puts("finish reading\n\r");
IICSTAT = 0x90; //结束该次通讯
IICCON = 0xaf; //
delay(100);
}
注意:如果要进行连续的读写操作,那么两次操作之间要加上一个延时,如delay(3000);