下面,我就說說那個讓我做了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);