AT24C02使用詳解


---恢復內容開始---

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

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

先看IIC

 

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

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

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

 

/*******************************************************************
                     起動總線函數               
函數原型: void  Start_I2c();  
功能:     啟動I2C總線,即發送I2C起始條件.  
********************************************************************/
void Start_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();
}

 

void Stop_I2c()
{
  SDA=0;      /*發送結束條件的數據信號*/
  _Nop();       /*發送結束條件的時鍾信號*/
  SCL=1;      /*結束條件建立時間大於4μs*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  SDA=1;      /*發送I2C總線結束信號*/
  _Nop();
  _Nop();
  _Nop();
  _Nop();
}

 


 

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

下面是程序

void  SendByte(unsigned char  c)
{
    unsigned char  BitCnt;
    //SCL=0; 起始信號最后是SCL=0;所以不用寫了
    for(BitCnt=0;BitCnt<8;BitCnt++)  /*要傳送的數據長度為8位*/
    {
      if((c<<BitCnt)&0x80)/*判斷發送位*/
      {
        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;//沒有接收到應答信號     
    else 
        ack=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();發送停止信號

 接收程序如下

unsigned char   RcvByte()
{
  unsigned char  retc;
  unsigned char  BitCnt;
  
  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決定)
********************************************************************/
void Ack_I2c(bit a)
{
  if(a==0)SDA=0;              /*在此發出應答或非應答信號 */
  else SDA=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 
**/
unsigned char WriteData(unsigned char Data,unsigned char Address)
{
    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 
**/
unsigned char ReadData(unsigned char Address)
{
    unsigned char Data =0;
    
    Start_I2c();
    SendByte(0xa0);//最后一位為0
    if(ack==0)return(0);
    
    SendByte(Address);              //發送地址
    if(ack==0)return(0);
    
    Start_I2c();
    
    SendByte(0xa1);//最后一位為1
    if(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 
**/
unsigned char PageWrite(unsigned char *Data,unsigned char Address,unsigned char cnt)
{
    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 
**/
unsigned char PageRead(unsigned char *Data,unsigned char Address,unsigned char cnt)
{
    Start_I2c();
    SendByte(0xa0);//最后一位為0
    if(ack==0)return(0);
    
    SendByte(Address);              //發送要讀的地址
    if(ack==0)return(0);
    
    Start_I2c();
    
    SendByte(0xa1);//最后一位為1
    if(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

 


免責聲明!

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



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