IIC通訊協議詳解


 

IIC概述

IIC:兩線式串行總線,它是由數據線SDA時鍾線SCL構成的串行總線,可發送和接收數據。

在CPU與被控IC之間、IC與IC之間進行雙向傳送,高速IIC總線一般可達400kbs以上。

時鍾線SCL:在通信過程起到控制作用。 
數據線SDA:用來一位一位的傳送數據。 

 

IIC分為軟件IIC和硬件IIC

軟件IIC:軟件IIC通信指的是用單片機的兩個I/O端口模擬出來的IIC,用軟件控制管腳狀態以模擬I2C通信波形,軟件模擬寄存器的工作方式。

硬件IIC:一塊硬件電路,硬件I2C對應芯片上的I2C外設,有相應I2C驅動電路,其所使用的I2C管腳也是專用的,硬件(固件)I2C是直接調用內部寄存器進行配置。

補充

1.硬件I2C的效率要遠高於軟件的,而軟件I2C由於不受管腳限制,接口比較靈活。
2.IIC是半雙工通信方式

 

 

IIC通信協議

IIC通信過程由開始、結束、發送、響應、接收五個部分構成。

 1、(在發送、接收數據的時候)當SCL為高電平時,SDA線不允許變化;當SCL線為低電平時,SDA線可以任意0、1變化。 
 2、(在任意時候)只有當SCL為高電平時,IIC電路才對SDA線上的電平(0或者1)進行記錄,當SCL線為低電平時,無論SDA是高還是低,IIC電路都不對SDA進行采樣。

 

空閑狀態

在介紹上面五個部分前,我們首先說說空閑狀態,什么是空閑狀態,就是沒有通信時的狀態初始狀態

I2C總線的SDA和SCL兩條信號同時處於高電平時,規定為總線的空閑狀態。此時各個器件的輸出級場效管均處在截止狀態,即釋放總線,由兩條信號線各自的上拉電阻把電平拉高。

 

開始信號與停止信號

開始信號:當SCL為高期間,SDA由高到低的跳變;啟動信號是一種電平跳變時序信號,而不是一個電平。
停止信號:當SCL為高期間,SDA由低到高的跳變;停止信號也是一種電平跳變時序信號,而不是一個電平信號。

 

開始信號程序

//產生IIC起始信號
//1.設置SDA輸出
//2.先拉高SDA,再拉高SCL,空閑狀態
//3.拉低SDA
//4.准備接收數據
void IIC_Start(void)
{
    SDA_OUT();     //sda線輸出
    IIC_SDA=1;            
    IIC_SCL=1;
    delay_us(4);
     IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
    delay_us(4);
    IIC_SCL=0;//鉗住I2C總線,准備發送或接收數據 
}    
 

 

 停止信號程序

 
//產生IIC停止信號
//1.設置SDA輸出
//2.先拉低SDA,再拉低SCL
//3.拉高SCL
//4.拉高SDA
//5.停止接收數據
void IIC_Stop(void)
{
    SDA_OUT();//sda線輸出
    IIC_SCL=0;
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     delay_us(4);
    IIC_SCL=1; 
    IIC_SDA=1;//發送I2C總線結束信號
    delay_us(4);                                   
}
 

 

 

應答信號

發送器每發送一個字節,就在時鍾脈沖9期間釋放數據先,由接收器反饋一個應答信號。應答信號為低電平時,規定為有效應答位(ACK簡稱應答位),表示接收器已經成功接收了該字節;應答信號為高電平時,規定為非應答位(NACK),一般表示接收器接收該字節沒有成功。

對於反饋有效應答位ACK的要求是,接收器在第9個時鍾脈沖之前的低電平期間將SDA線拉低,並且確保在該時鍾的高電平期間位穩定的低電平。如果接收器是主控器,則在它收到最后一個字節后,發送一個NACK信號,以通知被控發送器結束數據發送,並釋放SDA線,以便主控接收器發送一個停止信號P

 每當主機向從機發送完一個字節的數據,主機總是需要等待從機給出一個應答信號,以確認從機是否成功接收到了數據,從機應答主機所需要的時鍾仍是主機提供的,應答出現在每一次主機完成8個數據位傳輸后緊跟着的時鍾周期,低電平0表示應答,1表示非應答:

 

 應答信號程序

 
//產生ACK應答
//這里就很清楚了,產生應答:SCL在SDA一直為低電平期間完成低高電平轉換
void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}
//不產生ACK應答    
//這里就很清楚了,不產生應答:SCL在SDA一直為高電平期間完成低高電平轉換
void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}    
 

 

 

發送數據

在I2C總線上傳送的每位數據都有一個時鍾脈沖相對應(或同步控制),即在SCL串行時鍾的配合下,SDA逐位地串行傳送每一位數據。數據位的傳輸是邊沿觸發。
 
//IIC發送一個字節
//返回從機有無應答
//1,有應答
//0,無應答            

//IIC_SCL=0;
//在SCL上升沿時准備好數據,進行傳送數據時,拉高拉低SDA,因為傳輸一個字節,一個SCL脈沖里傳輸一個位。
//數據傳輸過程中,數據傳輸保持穩定(在SCL高電平期間,SDA一直保持穩定,沒有跳變)
//只有當SCL被拉低后,SDA才能被改變
//總結:在SCL為高電平期間,發送數據,發送8次數據,數據為1,SDA被拉高,數據為0,SDA被拉低。
//傳輸期間保持傳輸穩定,所以數據線僅可以在時鍾SCL為低電平時改變。
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
    SDA_OUT();         
    IIC_SCL=0;//拉低時鍾開始數據傳輸
    for(t=0;t<8;t++)
    {              
        //IIC_SDA=(txd&0x80)>>7;
        //獲取數據的最高位,然后左移7位
        //如果某位為1,則SDA為1,否則相反
        if((txd&0x80)>>7)
            IIC_SDA=1;
        else
            IIC_SDA=0;
        txd<<=1;       
        delay_us(2);   //對TEA5767這三個延時都是必須的
        IIC_SCL=1;
        delay_us(2); 
        IIC_SCL=0;    
        delay_us(2);
    }     
}       
 

單片機發送完一個字節后面必須跟一個等外應答函數:

思路:先讓SDA=1,再判斷在一定時間內SDA是否變為0,從而識別出外設有沒有發送應答信號。

 
//等待應答信號到來
//返回值:1,接收應答失敗
//        0,接收應答成功
//1.設置SDA為輸入
//2.拉高SDA
//3.拉高SCL
//4.等待接收器返回應答信號,如果數據線SDA一直為高,就一直等待,並返回1(無效應答),如果數據線SDA為低,返回0(有效應答)
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA設置為輸入  
    IIC_SDA=1;delay_us(1);       
    IIC_SCL=1;delay_us(1);     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0;//時鍾輸出0        
    return 0;  
} 
 

 

 

接收數據

發送數據是一位一位發送,接收數據也是一位一位接收進來,最后返回應答信號:

 
//讀1個字節,ack=1時,發送ACK,ack=0,發送nACK   

//先拉低SCL,延時后拉高
//讀取數據
//是否發送應答
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();//SDA設置為輸入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        delay_us(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
        delay_us(1); 
    }                     
    if (!ack)
        IIC_NAck();//發送nACK
    else
        IIC_Ack(); //發送ACK   
    return receive;
}

 

 


免責聲明!

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



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