AT24C02使用詳解

這篇文章是寫給一個學弟看的,關于IIC,關于24C02的單字節寫入\讀取..頁寫入和讀取,,學弟總是害怕協議,,,我總是對人家說,本來就這樣的,協議就是人家這樣規定的,,,如果你早生幾十年你也可能規定個IIC協議......

我的單片機和24C02通信,,,我的單片機就叫主機,,,24C02叫從機

先看IIC

IIC協議規定開始傳輸數據的時候要先發一個起始信號,,,目的應該是告訴從機要開始通信了,準備準備

終止信號就是拜拜啦,再見!

起始信號就是 在SCL在高電平期間SDA來一個下降沿,,終止信號就是在SCL在高電平期間SDA來一個上升沿(所以協議上才會說,在正常傳輸數據的時候,只有在SCL為低電平的時候,數據線SDA的高低電平狀態才允許改變,要不然豈不是和起始信號或者終止信號沖突了)

/*******************************************************************

起動總線函數

函數原型: void? Start_I2c();

功能:? ? 啟動I2C總線,即發送I2C起始條件.

********************************************************************/voidStart_I2c()

{

SDA=1;/*發送起始條件的數據信號*/_Nop();

SCL=1;

_Nop();/*起始條件建立時間大于4.7us,延時*/_Nop();

_Nop();

_Nop();

_Nop();

SDA=0;/*發送起始信號*/_Nop();/*起始條件鎖定時間大于4μs*/_Nop();

_Nop();

_Nop();

_Nop();

SCL=0;/*鉗住I2C總線,準備發送或接收數據*/_Nop();

_Nop();

}

voidStop_I2c()

{

SDA=0;/*發送結束條件的數據信號*/_Nop();/*發送結束條件的時鐘信號*/SCL=1;/*結束條件建立時間大于4μs*/_Nop();

_Nop();

_Nop();

_Nop();

_Nop();

SDA=1;/*發送I2C總線結束信號*/_Nop();

_Nop();

_Nop();

_Nop();

}

發送完起始信號就能傳輸數據了

下面是程序

voidSendByte(unsignedcharc)

{

unsignedcharBitCnt;//SCL=0; 起始信號最后是SCL=0;所以不用寫了for(BitCnt=0;BitCnt<8;BitCnt++)/*要傳送的數據長度為8位*/{if((c<

SDA=1;

}else{

SDA=0;

}

_Nop();

SCL=1;/*置時鐘線為高,通知被控器開始接收數據位*/_Nop();

_Nop();/*保證時鐘高電平周期大于4μs*/_Nop();

_Nop();

_Nop();

SCL=0;

}

_Nop();

_Nop();

SDA=1;/*8位發送完后釋放數據線,準備接收應答位*/_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();if(SDA==1)/*判斷是否接收到應答信號*/ack=0;//沒有接收到應答信號elseack=1;//接收到應答信號SCL=0;

_Nop();

_Nop();

}

現在說一下接收,,,假設上面發送完0xaa以后,從機就返回給我們數據(11001100, 0xcc),當然SCL為低電平的時候模塊準備數據,,SCL為高電平的時候,從機就把數據放在了SDA上,這樣循環8次,一個8位數據就過來了

整體上應該是

Start_I2c();起始信號程序

SendByte(0xaa);

判斷下ack是不是等于1,應答了(是繼續執行還是停止看自己了)

Data = RcvByte();//接收數據

Ack_I2c(1);//發送非應答,就是SDA=1;,這個程序在下面

Stop_I2c();發送停止信號

接收程序如下

unsignedcharRcvByte()

{

unsignedcharretc;

unsignedcharBitCnt;

retc=0;

SDA=1;/*置數據線為輸入方式*/for(BitCnt=0;BitCnt<8;BitCnt++)

{

_Nop();

SCL=0;/*置時鐘線為低,準備接收數據位*/_Nop();

_Nop();/*時鐘低電平周期大于4.7μs*/_Nop();

_Nop();

_Nop();

SCL=1;/*置時鐘線為高使數據線上數據有效*/_Nop();

_Nop();

retc=retc<<1;if(SDA==1)retc=retc+1;/*讀數據位,接收的數據位放入retc中*/_Nop();

_Nop();

}

SCL=0;

_Nop();

_Nop();return(retc);

}

應答或者非應答程序如下

/********************************************************************

應答子函數

函數原型:? void Ack_I2c(bit a);

功能:? ? ? 主控器進行應答信號(可以是應答0或非應答1信號,由位參數a決定)

********************************************************************/voidAck_I2c(bit a)

{if(a==0)SDA=0;/*在此發出應答或非應答信號*/elseSDA=1;

_Nop();

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();/*時鐘低電平周期大于4μs*/_Nop();

_Nop();

_Nop();

SCL=0;/*清時鐘線,鉗住I2C總線以便繼續接收*/_Nop();

_Nop();

}

IIC其實就這樣了,主要看支持IIC通信的芯片的資料了,寫好這些就是IIC通用的了

資料鏈接

https://wenku.baidu.com/view/3fc8558002d276a200292ef9.html

現在看芯片資料如何寫進去一個字節

關于器件的地址

寫就是0xa0;;;;讀就是0xa1

所以寫函數就是

/**

* @brief? 向24C02寫數據

* @param? Data--數據

* @param? Address--地址

* @param? None

* @retval None

* @example

**/unsignedcharWriteData(unsignedcharData,unsignedcharAddress)

{

Start_I2c();

SendByte(0xa0);//最后一位為0寫入if(ack==0)return(0);

SendByte(Address);//發送地址if(ack==0)return(0);

SendByte(Data);//發送數據if(ack==0)return(0);

Stop_I2c();//結束總線return(1);

}

關于應答哈我的SendByte(unsigned char? c)函數里面發送完8位數據后就寫了應答,然后把應答標志給ack,,后面直接判斷的ack

現在想想為什么叫應答...直接說判斷從機正沒正確接收到數據就完了唄,就是把SDA拉高,然后把SCL拉高,等一會然后判斷SDA引腳有沒有被從機拉低,拉低了就說明好了......沒拉低從機可能接收的數據不正確

_Nop();

_Nop();

SDA=1;??????????????? /*8位發送完后釋放數據線,準備接收應答位*/

_Nop();

_Nop();

SCL=1;

_Nop();

_Nop();

_Nop();

if(SDA==1)/*判斷是否接收到應答信號*/

ack=0;//沒有接收到應答信號

else

ack=1;//接收到應答信號

SCL=0;

_Nop();

_Nop();

}

再看從任意地址讀一個數據

注意哈第一個發送的器件地址是0xa0,后面的是0xa1

所以程序如下

/**

* @brief? 從24C02讀出數據

* @param? None

* @param? Address--地址

* @param? None

* @retval 讀到的數據

* @example

**/unsignedcharReadData(unsignedcharAddress)

{

unsignedcharData =0;

Start_I2c();

SendByte(0xa0);//最后一位為0if(ack==0)return(0);

SendByte(Address);//發送地址if(ack==0)return(0);

Start_I2c();

SendByte(0xa1);//最后一位為1if(ack==0)return(0);

Data=RcvByte();

Ack_I2c(1);//發送非就答位Stop_I2c();//結束總線return(Data);

}

現在看頁寫

把程序先放上,對了寫的時候的開始地址最好是0,8,16,24,32,40,68,,,,8的倍數,要不然數據可能有錯誤,當然我用的芯片頁寫最多一次能寫入8個字節.....感覺有點少哈......可以在現在的基礎上再做一個函數實現哈,,或者用寫單字節的for循環下....

/**

* @brief? 向24C02寫數據----頁寫,,,最多一次寫入8個字節,多了會覆蓋前面的

* @param? Data--數據

* @param? StartAddress--開始的地址--最大255

* @param? None

* @retval None

* @example

**/unsignedcharPageWrite(unsignedchar*Data,unsignedcharAddress,unsignedcharcnt)

{

Start_I2c();

SendByte(0xa0);//最后一位為0寫入if(ack==0)return(0);

SendByte(Address);//發送地址if(ack==0)return(0);while(cnt--)

{

SendByte(*Data++);//發送數據if(ack==0)return(0);

DelayMs(10);

}

Stop_I2c();//結束總線return(1);

}

現在看頁讀

看程序

/**

* @brief? 從24C02讀出數據----頁讀

* @param? Data--數據指針

* @param? StartAddress--開始的地址--最大255

* @param? None

* @retval None

* @example

**/unsignedcharPageRead(unsignedchar*Data,unsignedcharAddress,unsignedcharcnt)

{

Start_I2c();

SendByte(0xa0);//最后一位為0if(ack==0)return(0);

SendByte(Address);//發送要讀的地址if(ack==0)return(0);

Start_I2c();

SendByte(0xa1);//最后一位為1if(ack==0)return(0);while(cnt--)

{*Data? =RcvByte();

Data++;

Ack_I2c(0);//發送應答位DelayMs(10);

}

Ack_I2c(1);//發送非應答位Stop_I2c();//結束總線return(1);

}

說一下讀的時候最好開始讀取的地址是8的倍數,讀取的數據個數也是8的倍數,,,我測試的如果不是這樣有時候,第二次頁讀的時候就會讀錯........

這芯片和8干上了............

還有一個立即讀,,,看明白就行,就是立即返回當前讀地址加1后的那個數據

源碼鏈接

鏈接:http://pan.baidu.com/s/1i4M7BId%20密碼:r9ov

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 在使用單片機的過程中,I2C 通信可以說是最被廣泛使用和采納的協議之一,采用 I2C 協議可以占用更少的資源,鏈接...
    noparkinghere閱讀 2,289評論 0 8
  • IIC通信實驗 IIC簡介 I2C(Inter-Integrated Circuit)字面上的意思是集成電路之間,...
    btskyrmb閱讀 1,990評論 0 2
  • i2c總線協議: 歷史:是飛利浦公司在80年代,為研發音視頻模塊的通訊而產生。因其具有的諸多優點,而沿用至今。 優...
    ibo閱讀 1,495評論 1 1
  • 串行通信的幾個名詞: 全雙工:數據線有2條,分別用來發送和接收。半雙工:數據線只有1條,用來發送和接收,分時復用。...
    X_xxieRiemann閱讀 1,707評論 0 0
  • 1、嵌入式系統的定義 (1)定義:以應用為中心,以計算機技術為基礎,軟硬件可裁剪,適應應用系統對功能、可靠性、成本...
    榮卓然閱讀 1,871評論 0 5