EEPROM存儲芯片24C02


1、24C02簡介

  24C02是一個2Kbit的串行EEPROM存儲芯片,可存儲256個字節數據。工作電壓范圍為1.8V到6.0V,具有低功耗CMOS技術,自定時擦寫周期,1000000次編程/擦除周期,可保存數據100年。24C02有一個16字節的頁寫緩沖器和一個寫保護功能。通過I2C總線通訊讀寫芯片數據,通訊時鍾頻率可達400KHz。

  可以通過存儲IC的型號來計算芯片的存儲容量是多大,比如24C02后面的02表示的是可存儲2Kbit的數據,轉換為字節的存儲量為2*1024/8 = 256byte;有比如24C04后面的04表示的是可存儲4Kbit的數據,轉換為字節的儲存量為2*1024/8 = 512byte;以此來類推其它型號的存儲空間。

  24C02的管腳圖如下:

  VCC和VSS是芯片的電源和地,電壓的工作范圍為:+1.8V~+6.0V。

  A0、A1、A2是IC的地址選擇腳。

  WP是寫保護使能腳。

  SCL是I2C通訊時鍾引腳。

  SDA是I2C通訊數據引腳。

2、24C02的設備地址和寫保護功能

   I2C主機在與24C02通訊時,需要發送一個設備地址進行尋址,在I2C總線上,每一個從機設備的地址都是唯一的。

  24C02的設備地址包含兩部分,第一部分是bit7~bit4是固定的“1010”,第二部分bit3~bit1位由A2、A1、A0組成。主機在與24C02進行通訊時,除了發送設備地址還需要發送數據的讀寫方向位R/W,24C02的是設備地址與R/W位組成了一個字節的數據。如下圖:

   上圖列出了幾個存儲IC的設備地址與R/W位組成的字節。由圖中可以看到,存儲IC地址的bit7~bit4位固定為“1010”;bit3~bit1位由A2、A1、A0引腳的電平狀態決定,如果Ax接的是電源(高電平),那么Ax=1,如果Ax接的是地,那么Ax=0,即由A2、A1、A0可以組合成8種設備地址,也就是說在同一個I2C總線上可以同時掛載8個24C02芯片。一般如果I2C總線上只有一片24C02芯片的話,A2、A1、A0引腳都接到地。

  由於24C02只有256個字節的存儲空間,所以只需要1個字節就可以尋址完24C02的存儲空間,但是無法尋址完更大容量的存儲IC,比如24C04的存儲容量是512字節,需要9個bit的地址位才能尋址完。由上圖可以看到,24C04的設備地址內是沒有A0參數的,被a8代替了,這個a8就是24C04的第9個bit的地址位,也就是說24C04的A0引腳是不起作用的,這樣也就造成了在I2C總線上只能同時掛載4個24C04芯片。其它存儲器如24C08、24C16也可以這么類推。

  24C02的WP引腳是寫保護引腳,當WP引腳接高電平的時,24C02只能進行讀取操作,不能進行寫操作。只有當WP引腳懸空或接低電平時,24C02才能進行寫操作。

3、24C02數據讀取操作

  在這里只是對24C02的讀寫進行一些說明和一些注意的實現,不會涉及具體的程序代碼,只是進行代碼概述,工程代碼已經上傳到個人GitHub中,感興趣的可以去GitHub中下載查看,GitHub代碼地址如下:

https://github.com/h1019384803/STM32F103ZET6_I2C.git。這是一個使用STM32F103ZET6的IO模擬I2C操作24C02的工程。

  MCU通過使用I2C讀取24C02任意存儲空間地址內的數據,代碼如下:  

 1 uint8_t AT24CXX_READ_ONE_BYTE(uint16_t address)  2 {  3  uint8_t dat;  4     
 5  I2C_START();  6     AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);  7     if(AT24CXX_ERR != 0)//沒有響應直接退出
 8  {  9         AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF); 10         if(AT24CXX_ERR != 0) 11  { 12  I2C_START(); 13             
14             AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_READ_CMD); 15             if(AT24CXX_ERR != 0) 16  { 17                dat = I2C_READ_BYTE(0); 18  I2C_STOP(); 19  } 20  } 21  } 22     
23     return dat; 24 }

  第5行主機產生一個I2C起始信號,第6行發送設備地址和寫數據位給24C02,第9行是發送需要讀取的地址給24C02,第12行主機產生一個重復起始信號,第14行設備地址和讀數據位給24C02,第17行是讀取24C02相應地址存儲的數據。第18行是主機產生I2C結束信號。

  在上面的程序代碼中,AT24CXX_ERR是用來獲取24C02的應答信號,如果主機與24C02的通訊正常,主機每發送一個字節給24C02,24C02都會反饋一個應答信號給主機,如果24C02沒有反饋應答信號,那么說明24C02正在進行其它操作或者通訊異常導致無法通訊,主機會產生一個結束信號來結束操作。在I2C_WRITE_BYTE()函數內部有一個等待應答信號的操作,如果沒有收到應答信號,在I2C_WRITE_BYTE()函數內會產生一個停止信號來結束當前操作。AT24CXX_ERR用來判斷接下來的操作是否執行,如果AT24CXX_ERR=0說明沒有收到應答信號,直接退本次讀取操作;如果AT24CXX_ERR!=0說明有收到應答信號,繼續讀取操作。

  24C02內部有一個地址計數器,主機發送要讀寫的存儲空間地址給24C02,就相當於改變24C02的內部地址計數器的值,主機每讀寫一個字節24C02之后,它內部地址計數器的值就會自動加1。也就是說如果當前地址是N,那么主機讀取完一個字節的數據之后,再次讀的話就變為了讀取N+1地址的數據。

  這里需要注意的一點是,24C02的內部地址計數器的地址只能從0~255之間遞增,這是因為24C02的存儲控制只有256個字節,地址計數器只能在0~255(共256個地址)內變化。如果連續讀取使得地址計數器超過255,那么地址計數器就會從0地址開始循環。比如說當前內部計數器地址為255,主機在讀取一個字節數據之后會導致內部計數器地址變為0,那么主機再次讀取數據的時候讀取得到的是24C02地址0的數據。

  MCU使用I2C連續讀取24C02內多個存儲空間地址數數的代碼如下:

 1 void AT24CXX_READ_BUFF(uint16_t address,uint8_t *buffer,uint16_t Len)  2 {  3  uint16_t i;  4     
 5  I2C_START();  6     AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);  7     if(AT24CXX_ERR != 0)//沒有響應直接退出
 8  {  9         AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF); 10         if(AT24CXX_ERR != 0) 11  { 12  I2C_START(); 13             AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_READ_CMD); 14             if(AT24CXX_ERR != 0) 15  { 16                 for(i=0;i<Len;i++) 17  { 18                     buffer[i] = I2C_READ_BYTE(0); 19  } 20  } 21             
22             if(AT24CXX_ERR != 0) 23  { 24  I2C_STOP(); 25  } 26  } 27  } 28 }

  上面的代碼,大部分跟讀取一個字節的程序代碼是一樣的,不一樣的是第16~19行,這里用一個for循環來連續讀取24C02內的數據,這里並沒有對超范圍讀取數據進行限制,所以在使用的時候需要注意不要連續讀取超過24C02的存儲空間,就算超過也不會有問題,只是會重新開始從0地址讀取。

4、24C02數據寫入操作

  MCU使用I2C寫入一個字節數據到24C02任意存儲空間地址內的代碼如下:

 1 void AT24CXX_WRITE_ONE_BYTE(uint16_t address,uint8_t dat)  2 {  3  I2C_START();  4     AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD);  5     if(AT24CXX_ERR != 0)//沒有響應直接退出
 6  {  7         AT24CXX_ERR = I2C_WRITE_BYTE(address & 0xFF);  8         if(AT24CXX_ERR != 0)  9  { 10             AT24CXX_ERR = I2C_WRITE_BYTE(dat); 11             if(AT24CXX_ERR != 0) 12  { 13  I2C_STOP(); 14  } 15  } 16  } 17 }

  第3行主機產生一個I2C起始信號,第4行發送設備地址和寫數據位給24C02,第7行是發送需要寫入數據的地址給24C02,第10行是將要寫入的數據發送給24C02。第18行是主機產生I2C結束信號。上面大部分操作跟讀取是一樣的,不一樣的只是最后將讀取操作改為了寫入操作。

  如果需要連續寫入數據,可以如下:

1     for(i = 0;i < 256;i ++) 2  { 3         AT24C02_BUFF[i] = i; 4  AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]); 5     }

  但是在實際使用的過程中,發現只有一部分AT24C02_BUFF[]數組里面的數據被寫入到了24C02當中,有一些數據沒有寫進24C02。這是因為24C02擦寫數據沒有那么快,需要一定的時間,在24C02正在擦寫數據的過程中,是不會應答主機的通訊的,所以如果主機在寫入一個數據之后又立馬寫入另一個數據,就會導致24C02跟不上主機的通訊速度從而導致無法寫入數據。

  需要注意的是24C02並不是在主機發送數據給24C02之后就立馬擦寫數據的,24C02是在主機產停止信號之后才開始擦寫數據的,並且在擦寫數據完成之前不會響應主機的其它操作。

  可以通過一定的延時函數來等待24C02擦寫完成,代碼如下:

    for(i = 0;i < 256;i ++) { AT24C02_BUFF[i] = i; AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]); HAL_Delay(1); }

  通過調用HAL_Delay()函數進行延時,具體的延時時間可以通過調試來決定,這里使用1ms的延時時間,具體24C02擦寫數據需要多久並不清楚。

  除了通過延時函數進行等待24C02擦寫完成,也可以通過發送設備地址給24C02,然后查詢是否有應答信號返回來判斷24C02是否擦寫完成。24C02在擦寫數據時是不會反饋應答信號給主機的,這樣就可以通過不斷的發送數據給24C02,然后查詢應答信號來判斷24C02是否擦寫完成,一旦擦寫完成就可以進行下一個數據的寫入。代碼如下:

 1 void Wait_AT24CXX_WRITE_OK(void)  2 {  3  uint8_t Wait_Cnt;  4 
 5     Wait_Cnt = 50;  6     do
 7  {  8  I2C_START();  9         AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD); 10         if(AT24CXX_ERR != 0) 11  { 12             I2C_STOP();//接收到響應信號退出
13             break; 14  } 15             
16     }while(Wait_Cnt--); 17 
18 }

  Wait_Cnt是一個次數限制變量,不能無限的在里面等待,不然遇到異常就有可能造成程序卡死。

  程序通過發送起始信號、發送設備地址和寫數據方向給24C02,如果24C02反饋了一個應答信號給主機,主機就產生一個停止信號,然后退出當前循環。應用代碼如下:

1     for(i = 0;i < 256;i ++) 2  { 3         AT24C02_BUFF[i] = i; 4  AT24CXX_WRITE_ONE_BYTE(i,AT24C02_BUFF[i]); 5         Wait_AT24CXX_WRITE_OK();//可以通過發送設備地址給從機,通過從機反饋的響應信號來判斷從機是否可以正常通訊
6     }

5、24C02頁寫入

  24C02有一個頁寫入功能,可以連續寫入16個字節的數據。

  24C02可以以頁來划分存儲空間,每16個字節組成一個頁,24C02的存儲空間大小為256個字節,所以24C02總共有16個頁。如:

  頁0:地址從0x00~0x0F

  頁1:地址從0x10~0x1F

  ......

  頁15:地址從0xF0~0xFF  

  24C02可以在一個頁內連續的寫入數據,但是需要注意的是如果寫入的數據超過頁大小,那么就會覆蓋頁初始地址的值,比如說連續寫入3個數據,第1個數據寫入到地址0x0F當中,第2個數據由於溢出頁的限制,會被寫入到地址0x00當中,第3個數據會被寫入到地址0x01當中。

  以個人的理解,24C02內部有一個16byte的數據緩存器,在上面的介紹中知道,主機在發送數據給24C02的時候,24C02是不會擦寫數據的,只有當主機發送停止信號之后24C02才會擦寫數據。那么當主機發送數據給24C02時,只是將數據寫入到了24C02內部的緩存器中,只有當主機發送結束信號之后,24C02才將緩存器內的數據寫入到內部存儲空間。

  由24C02的數據緩存器只有16個byte(每個型號的存儲IC的頁大小是不一樣的也就是緩存器大小是不不一樣的)。所以如果寫入的數據超過緩存器的大小就會覆蓋之前寫入的數據。

  使用頁寫入連續將數據寫入24C02的代碼如下:  

 1 void AT24CXX_WRITE_BUFF(uint16_t address,uint8_t *Buffer,uint16_t Len)  2 {  3  uint8_t i;  4  uint16_t re_main;  5     
 6     if(address >= 256)//對輸入的地址進行限制,24C02只有256個字節的存儲空間,其它型號的存儲器IC可以通過查資料
 7  {  8         return;  9  } 10     
11     re_main = 256 - address;//計算出還有多少存儲空間
12     
13     if(Len > re_main)//如果要寫入的數據量超過剩余存儲空間,則只寫入剩余存儲空間數量的數據
14  { 15         Len = re_main; 16  } 17     
18     re_main = 16 - address%16;//計算當前頁還可以寫入多少個數據
19     
20     if(Len <= re_main)//如果要寫入的數據小於等於當前頁剩余的存儲空間,則只寫入Len個字節數據就好,不需要跨頁操作
21  { 22         re_main = Len; 23  } 24     
25     do
26  { 27  I2C_START(); 28         AT24CXX_ERR = I2C_WRITE_BYTE(AT24CXX_WIRTE_CMD); 29         if(AT24CXX_ERR == 0)//沒有響應直接退出
30  { 31             break; 32  } 33         
34         I2C_WRITE_BYTE(address & 0xFF); 35         for(i = 0;i < re_main;i ++)//最多連續寫入一個頁數據的大小
36  { 37             AT24CXX_ERR = I2C_WRITE_BYTE(Buffer[i]); 38  } 39         
40  I2C_STOP(); 41         Wait_AT24CXX_WRITE_OK();//等待24C02完成擦寫數據動作 
42         
43         if(re_main != Len) 44  { 45             address += re_main;//已經寫入re_main個數據,
46             Buffer += re_main; 47             Len -= re_main; 48             
49             re_main = 16;//寫一個頁的的大小也是16個字節
50             
51             if(Len <= re_main) 52  { 53                 re_main = Len; 54  } 55  } 56         else
57  { 58             break;//數據寫入完成退出
59  } 60  } 61     while(1); 62 }

  AT24CXX_WRITE_BUFF()函數的思路如下:

  首先判斷輸入的地址是否超過存儲IC的存儲空間,如果超過則退出,如第6~9行。

  計算出輸入的地址到存儲器存儲的結束地址剩余多少空間,如果要寫入的數據比剩余空間還多,那么剩余多少空間就寫入多少空間,需要寫入的多余部分就去掉,如第11~16行。

  計算當前頁還可以寫入多少數據,如果當前頁剩余的空間比Len要寫入的數據長度還大,那么只要寫入當前頁就足夠了,不需要再跨頁寫入數據。如第18~23行。

  通過一個while(1)循環連續寫入數據到24C02中。

  第27~41行是將re_main個數據寫入到24C02當中,由於是在一個頁內操作,所以可以連續寫入,寫完之后在產生一個結束信號然后等待24C02擦寫完成。

  如果不需要跨頁寫入就已經將數據全部寫完,那么就可以直接break退出while循環,如第58行。

  如果需要跨頁寫入數據,還需要將地址、buffer、Len減去已經寫入的數據量,然后下一個頁可以寫入整個頁的數據量,也就是16個字節,通過比較判斷一個頁的剩余空間是否能夠寫完剩余的Len數據,如果不行就重復循環操作,如果可以寫完,在寫完之后就退出while循環。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM