天天看點

51單片機入門 - EEPROM(24C02的使用)

部落客福利:100G+電子設計學習資源包!

​​http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect​​ --------------------------------------------------------------------------------------------------------------------------

24C02:256 個位元組的 EEPROM。一般情況下,EEPROM 擁有 30 萬到 100 萬次的壽命。基于 I2C 通信協定的器件。I2C 是一個通信協定,它擁有嚴密的通信時序邏輯要求,而EEPROM 是一個器件,隻是這個器件采樣了 I2C 協定的接口與單片機相連而已,二者并沒有必然的聯系,EEPROM 可以用其它接口, I2C 也可以用在其它很多器件上。

1、EEPROM寫資料流程

第一步,首先是 I2C 的起始信号,接着跟上首位元組,也就是我們前邊講的 I2C 的器件地

址,并且在讀寫方向上選擇“寫”操作。

第二步,發送資料的存儲位址。24C02一共 256 個位元組的存儲空間,位址從 0x00~0xFF,我們想把資料存儲在哪個位置,此刻寫的就是哪個位址。

第三步,發送要存儲的資料第一個位元組、第二個位元組„„注意在寫資料的過程中,

EEPROM 每個位元組都會回應一個“應答位 0”,來告訴我們寫 EEPROM 資料成功,如果沒有回應答位,說明寫入不成功。

在寫資料的過程中,每成功寫入一個位元組,EEPROM 存儲空間的位址就會自動加 1,當加到 0xFF 後,再寫一個位元組,位址會溢出又變成了 0x00。

2、EEPROM讀資料流程

第一步,首先是 I2C 的起始信号,接着跟上首位元組,也就是我們前邊講的 I2C 的器件位址,并且在讀寫方向上選擇“寫”操作。這個地方可能有同學會詫異,我們明明是讀資料為何方向也要選“寫”呢?剛才說過了,24C02 一共有 256 個位址,我們選擇寫操作,是為了把所要讀的資料的存儲位址先寫進去,告訴 EEPROM 我們要讀取哪個位址的資料。這就如同我們打電話,先撥總機号碼(EEPROM 器件位址),而後還要繼續撥分機号碼(資料位址),而撥分機号碼這個動作,主機仍然是發送方,方向依然是“寫”。

第二步,發送要讀取的資料的位址,注意是位址而非存在EEPROM 中的資料,通知EEPROM 我要哪個分機的資訊

第三步,重新發送 I2C 起始信号和器件位址,并且在方向位選擇“讀”操作。

這三步當中,每一個位元組實際上都是在“寫”,是以每一個位元組EEPROM 都會回應一個“應答位 0”。

第四步,讀取從器件發回的資料,讀一個位元組,如果還想繼續讀下一個位元組,就發送一個“應答位ACK(0)”,如果不想讀了,告訴 EEPROM,我不想要資料了,别再發資料了,那就發送一個“非應答位NAK(1)”。

和寫操作規則一樣,我們每讀一個位元組,位址會自動加 1,那如果我們想繼續往下讀,給EEPROM 一個 ACK(0)低電平,那再繼續給 SCL 完整的時序,EEPROM 會繼續往外送資料。如果我們不想讀了,要告訴 EEPROM 不要資料了,那我們直接給一個NAK(1)高電平即可。這個地方大家要從邏輯上了解透徹,不能簡單的靠死記硬背了,一定要了解明白。梳理一下幾個要點:

A、在本例中單片機是主機,24C02 是從機;

B、無論是讀是寫, SCL 始終都是由主機控制的;

C、寫的時候應答信号由從機給出,表示從機是否正确接收了資料;

#include <reg52.h>

 

extern void I2CStart();

extern void I2CStop();

extern unsigned char I2CReadACK();

extern unsigned char I2CReadNAK();

extern bit I2CWrite(unsigned char dat);

 

/* E2讀取函數,buf-資料接收指針,addr-E2中的起始位址,len-讀取長度 */

void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)

{

  do                         //用尋址操作查詢目前是否可進行讀寫操作

  {

    I2CStart();

    if(I2CWrite(0x50 << 1)) //應答則跳出循環,非應答則進行下一次查詢

    {

      break;

    }

    I2CStop();

  }

  while(1);

  I2CWrite(addr);            //寫入起始位址

  I2CStart();                //發送重複啟動信号

  I2CWrite((0x50 << 1) | 0x01); //尋址器件,後續為讀操作

  while (len > 1)           //連續讀取len-1個位元組

  {

    *buf++ = I2CReadACK(); //最後位元組之前為讀取操作+應答

    len--;

  }

  *buf = I2CReadNAK();      //最後一個位元組為讀取操作+非應答

  I2CStop();

}

/* E2寫入函數,buf-源資料指針,addr-E2中的起始位址,len-寫入長度 */

void E2Write(unsigned char *buf, unsigned char addr, unsigned char len)

{

  while (len > 0)

  {

    //等待上次寫入操作完成

    do                        //用尋址操作查詢目前是否可進行讀寫操作

    {

      I2CStart();

      if(I2CWrite(0x50 << 1)) //應答則跳出循環,非應答則進行下一次查詢

      {

        break;

      }

      I2CStop();

    }

    while(1);

    //按頁寫模式連續寫入位元組

    I2CWrite(addr);           //寫入起始位址

    while(len > 0)

    {

      I2CWrite(*buf++);     //寫入一個位元組資料

      len--;                //待寫入長度計數遞減

      addr++;               //E2位址遞增

      if ((addr & 0x07) == 0) //檢查位址是否到達頁邊界,24C02每頁8位元組,

      {

        //是以檢測低3位是否為零即可

        break;            //到達頁邊界時,跳出循環,結束本次寫操作

      }

    }

    I2CStop();

  }

}