IIC接口AT24C02存儲芯片的操作


  從今天早上開始看AT24C02的手冊,憑着有些撮的英語水平,24頁的資料,愣是啃了半天,上午的時光就過去了。

  AT24C02是一款EEPROM芯片,IIC接口,就是兩條線:SDA與SCL;不過對於單單操縱這款芯片而言,沒有設計到IIC總線協議之中所謂的仲裁。因而,大體看下了芯片手冊,心中就知道大概怎么操作了。

  另外,24C02的2K是指2Kbit。一般的話,存儲器都用字節來衡量,所以其實24c02只有256byte。是不是比較小?這256byte又分成了32pages,每頁有8byte。

  現在來看看該如何編寫代碼,首先得知道起始與停止條件

                       

所謂起始條件:在SCL高電平期間,SDA的一個下降沿;

所謂停止條件:在SCL高電平期間,SDA的一個上升沿;

當然起始和停止條件與普通的位傳送是不同的,位傳送的時序如圖所示

 

可以看到,在SCL的高電平期間,SDA是不允許變化的;而只有在SCL的電平期間,SDA才能夠出現變化;

當傳輸完1字節之后,可能需要有一個應答信號。說到這兒,就需要明白幾個概念:發送器、接受器、主器件、從器件。

發送器:在總線上發送數據的器件。

接受器:在總線上接受數據的器件。

主器件:控制信息交互的器件,產生SCL時鍾信息,產生起始與停止條件。

從器件:受從器件控制的器件。

那這兒的應答信號,就是總線上的接受器每接受到一個字節后產生的應答。如圖所示:

 

需要注意的是,在等待應答信號之前,需要將SDA置高,即釋放掉總線。

24c02寫的方式有兩種:字節寫、頁寫(就是連續寫多個字節)。

掌握了字節寫,對於頁寫就容易的多了。

字節寫的時序如圖所示:

字節寫的時序:首先是起始條件(由MCU產生),接着單片機向總線上傳送器件地址,總線上地址相同的器件會有一個ACK(即應答信息),然后向器件寫入字地址(告訴24c02想把信息寫在那個地址,24c02剛好有256個字節,8bit的字地址信息剛好表示),同樣會有一個應答信息,緊接着需要寫入需要傳送的數據(8位),同理會有一個應答信息。最后,需要主器件產生一個停止條件。Ok,寫字節就結束了,是不是很簡單,頁寫只不過是在這一步沒有發送停止條件,而是接着發數據,這個時候24c02會知道你要寫下一個字節,它會自動的加地址。

再來看看如何讀取,讀取有三種方式:當前地址讀、隨機讀(我得承認這個名字不是太好)、順序讀。

當前地址讀取是指你可以讀取到芯片內部地址計數器(最近一次操作留下的值)加上1的地址上的值。看清楚是加上1地址上的值,不過不太明白有何用處。

接下來的隨機讀取跟是讓我迷惑(剛看手冊時候),隨機的意思不就是產生一個無腦的地址,然后去讀取,這樣的話,讀取有什么意義?不過我想錯了,你可以看看時序圖:

 

看到了,先發寫命令了,也傳送了字地址,然后沒有發寫的內容。轉而,重新開始發起始條件、器件地址(這次最后一位是讀),然后再接受總線傳送來的數據,此后主控器作為接受方,不用發應答信號,直接發一個停止條件,就ok了。

所以要想指定一個地址,就可以用隨機讀這個方法。不過隨機讀說法不太形象,改為指定地址讀跟容易理解。

順序讀跟頁寫是對應的,只是在隨機讀或當前地址讀后面接着接受數據。

 

寫了三頁,貌似不是很長。那就貼上代碼,來充長。

個人喜歡寫一個頭文件,然后,再寫一個c文件。

頭文件部分:

#ifndef __hal_24c02_h__

#define __hal_24c02_h__

 

#include"reg52.h"

#include"hal.h"

#include"datatype.h"

#include"delay.h"

 

sbit scl=P3^7;//IIC時鍾線

sbit sda=P3^6;//IIC數據線

 

#define SCL scl

#define SDA sda

 

//起始條件,SCL高電平時候,SDA的一個下降沿

#define HAL_24C02_START() {SDA=1;SCL=1;SDA=0;}

//停止條件,SCL高電平時候,SDA的一個上升沿

#define HAL_24C02_STOP() {SDA=0;SCL=1;SDA=1;}

#define HAL_24C02_BYTE_ADDR(addr) hal_24c02_send_char(addr)

#define HAL_24C02_ACK() hal_24c02_acknowledge(0)

 

void hal_24c02_init();

void hal_24c02_send_char(uchar val);

uchar hal_24c02_receive_char();

void hal_24c02_search_device(bit a2,bit a1,bit a0,bit rw);

void hal_24c02_acknowledge(bit mcu);

 

//學會使用以下兩個函數即可

//需要注意寫完之后,等待5ms之后,再去讀取

void hal_24c02_byte_write(bit a2,bit a1,bit a0,uchar byte_addr,uchar byte_data);

uchar hal_24c02_byte_read(bit a2,bit a1,bit a0,uchar byte_addr);

 

#endif

 

 

C文件部分:

#include"hal_24c02.h"

 

//初始化,需將時鍾線和數據線拉高

void hal_24c02_init()

{

         SCL=1;

         SDA=1;

}

 

//IIC協議要求從高位開始傳送,傳送1字節

void hal_24c02_send_char(uchar val)

{       

         uchar i;

         SCL=0;//此時,SCL被拉低,才允許SDA變化

         for(i=0;i<8;i++)

         {

                    if(val&(0x80>>i))

                           SDA=1;

                    else

                           SDA=0;

                   SCL=1;//拉高SCL,不允許SDA變化

                   delay_ms(1);

                   SCL=0;//拉低SCL,開始下1bit傳送

         }

         //不包括應答脈沖,此時,SCL被拉低,SDA未被釋放

         SDA=1;//釋放數據線

         //SCL處於低電平;SDA處於高電平

}

 

uchar hal_24c02_receive_char()

{

          //SCL低電平 SDA高電平

          uchar tmp=0,i;

          for(i=0;i<8;i++)

          {

                 SCL=1;

                   if(SDA)

                            tmp=tmp|(0x80>>i);

                   SCL=0;

          }

          return tmp;

          //SCL低電平 SDA高電平

}

 

//a2、a1、a0:表示器件地址

//rw:1 代表讀操作;0 代表寫操作

void hal_24c02_search_device(bit a2,bit a1,bit a0,bit rw)

{

         uchar tmp;

         tmp=0xa0|(a2?0x08:0x00)|(a1?0x04:0x00)|(a0?0x02:0x00)|rw;

         hal_24c02_send_char(tmp);

}

 

//參數mcu=1,表示由主機主動產生應答信號,此時還需要將SDA拉低

//參數mcu=0,表示非主機參數應答信號,此時主機只需要產生SCL脈沖

//返回1:表示有應答;0:無應答

void hal_24c02_acknowledge(bit mcu)

{

         //SCL處於低電平;SDA處於高電平

         if(mcu)      SDA=0;//產生1應答信號

         SCL=1;

         delay_ms(1);

         while(SDA);//等待應答

         SCL=0;

         if(mcu)      SDA=1;//釋放總線

         //SCL處於低電平;SDA處於高電平

}

 

//參數a2,a1,a0:器件地址

//參數byte_addr:字節地址

//參數byte_data:需要寫的數據

void hal_24c02_byte_write(bit a2,bit a1,bit a0,uchar byte_addr,uchar byte_data)

{

          HAL_24C02_START()

          hal_24c02_search_device(a2,a1,a0,0);

          HAL_24C02_ACK();

          HAL_24C02_BYTE_ADDR(byte_addr);

          HAL_24C02_ACK();

          hal_24c02_send_char(byte_data);

          HAL_24C02_ACK();

          HAL_24C02_STOP()

}

 

//參數a2 a1 a0為器件地址;

//參數byte_char為需要讀取的字節地址

//返回一個uchar型

uchar hal_24c02_byte_read(bit a2,bit a1,bit a0,uchar byte_addr)

{

          uchar val=0;

          HAL_24C02_START()

          hal_24c02_search_device(a2,a1,a0,0);//偽寫

          HAL_24C02_ACK();

          HAL_24C02_BYTE_ADDR(byte_addr);//偽寫的目的,就是為了傳送地址

          HAL_24C02_ACK();

          HAL_24C02_START();

          hal_24c02_search_device(a2,a1,a0,1);//真讀

          HAL_24C02_ACK();

          val=hal_24c02_receive_char();

          //NO ACK

          HAL_24C02_STOP()

          return val;

}

 

 

 


免責聲明!

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



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