文章目錄
IIC 簡介
IIC(Inter-Integrated Circuit)總線是一種由NXP(原PHILIPS)公司開發的兩線式串行總線,用於連接微控制器及其外圍設備。多用於主控制器和從器件間的主從通信,在小數據量場合使用,傳輸距離短,任意時刻只能有一個主機等特性。
在 CPU 與被控 IC 之間、IC 與 IC 之間進行雙向傳送,高速 IIC 總線一般可達 400kbps 以上。
IIC的物理層
IIC一共有隻有兩個總線: 一條是雙向的串行數據線SDA,一條是串行時鐘線SCL
-
SDA(Serial data)是數據線,D代表Data也就是數據,Send Data 也就是用來傳輸數據的
-
SCL(Serial clock line)是時鐘線,C代表Clock 也就是時鐘 也就是控制數據發送的時序的
所有接到I2C總線設備上的串行數據SDA都接到總線的SDA上,各設備的時鐘線SCL接到總線的SCL上。I2C總線上的每個設備都自己一個唯一的地址,來確保不同設備之間訪問的準確性。
IIC主要特點:
通常我們爲了方便把IIC設備分爲主設備和從設備,基本上誰控制時鐘線(即控制SCL的電平高低變換)誰就是主設備。**
-
IIC主設備功能:主要產生時鐘,產生起始信號和停止信號
-
IIC從設備功能:可編程的IIC地址檢測,停止位檢測
-
IIC的一個優點是它支持多主控(multimastering), 其中任何一個能夠進行發送和接收的設備都可以成爲主總線。一個主控能夠控制信號的傳輸和時鐘頻率。當然,在任何時間點上只能有一個主控。
-
支持不同速率的通訊速度,標準速度(最高速度100kHZ),快速(最高400kHZ)
-
SCL和SDA都需要接上拉電阻 (大小由速度和容性負載決定一般在3.3K-10K之間) 保證數據的穩定性,減少干擾。
-
IIC是半雙工,而不是全雙工 ,同一時間只可以單向通信
-
爲了避免總線信號的混亂,要求各設備連接到總線的輸出端時必須是漏極開路(OD)輸出或集電極開路(OC)輸出。這一點在等下我們會講解
IIC的高阻態
漏極開路(Open Drain)即高阻狀態,適用於輸入/輸出,其可獨立輸入/輸出低電平和高阻狀態,若需要產生高電平,則需使用外部上拉電阻
高阻狀態:高阻狀態是三態門電路的一種狀態。邏輯門的輸出除有高、低電平兩種狀態外,還有第三種狀態——高阻狀態的門電路。電路分析時高阻態可做開路理解。
我們知道IIC的所有設備是接在一根總線上的,那麼我們進行通信的時候往往只是幾個設備進行通信,那麼這時候其餘的空閒設備可能會受到總線干擾,或者干擾到總線,怎麼辦呢?
爲了避免總線信號的混亂,IIC的空閒狀態只能有外部上拉, 而此時空閒設備被拉到了高阻態,也就是相當於斷路, 整個IIC總線只有開啓了的設備纔會正常進行通信,而不會干擾到其他設備。
IIC器件地址: 每一個IIC器件都有一個器件地址,有的器件地址在出廠時地址就設定好了,用戶不可以更改,比如OV7670的地址爲0x42。有的器件例如EEPROM,前四個地址已經確定爲1010,後三個地址是由硬件鏈接確定的,所以一IIC總線最多能連8個EEPROM芯片。
IIC物理層總結:
I2C 總線在物理連接上非常簡單,分別由SDA(串行數據線)和SCL(串行時鐘線)及上拉電阻組成。通信原理是通過對SCL和SDA線高低電平時序的控制,來產生I2C總線協議所需要的信號進行數據的傳遞。在總線空閒狀態時,SCL和SDA被上拉電阻Rp拉高,使SDA和SCL線都保持高電平。
I2C通信方式爲半雙工,只有一根SDA線,同一時間只可以單向通信,485也爲半雙工,SPI和uart通信爲全雙工。
主機和從機的概念:
主機就是負責整個系統的任務協調與分配,從機一般是通過接收主機的指令從而完成某些特定的任務,主機和從機之間通過總線連接,進行數據通訊。
-
發佈主要命令的稱爲主機
-
接受命令的稱爲從機
半雙工和全雙工:
IIC的協議層
I2C 總線在傳送數據過程中共有三種類型信號, 它們分別是:開始信號、結束信號和應答信號。
- 開始信號:SCL 爲高電平時,SDA 由高電平向低電平跳變,開始傳送數據。
- 結束信號:SCL 爲高電平時,SDA 由低電平向高電平跳變,結束傳送數據。
- 應答信號:接收數據的 IC 在接收到 8bit 數據後,向發送數據的 IC 發出特定的低電平脈衝,表示已收到數據。CPU 向受控單元發出一個信號後,等待受控單元發出一個應答信號,CPU 接收到應答信號後,根據實際情況作出是否繼續傳遞信號的判斷。若未收到應答信號,由判斷爲受控單元出現故障。
這些信號中,起始信號是必需的,結束信號和應答信號,都可以不要。
IIC 總線時序圖
下面我們來詳細的介紹下IIC的通信協議流程:
初始(空閒)狀態
因爲IIC的 SCL 和SDA 都需要接上拉電阻,保證空閒狀態的穩定性
所以IIC總線在空閒狀態下SCL 和SDA都保持高電平
代碼:
void IIC_init() //IIC初始化
{
SCL=1; //首先把時鐘線拉高
delay_us(4);//延時函數
SDA=1; //在SCL爲高的情況下把SDA拉高
delay_us(4); //延時函數
}
開始信號:
SCL保持高電平,SDA由高電平變爲低電平後,延時(>4.7us),SCL變爲低電平。
代碼表示:
//產生IIC起始信號
//1.先拉高SDA,再拉高SCL,空閒狀態
//2.拉低SDA
void IIC_Start() //啓動信號
{
SDA=1; //確保SDA線爲高電平
delay_us(5);
SCL=1; //確保SCL高電平
delay_us(5);
SDA=0; //在SCL爲高時拉低SDA線,即爲起始信號
delay_us(5);
}
停止信號
停止信號:SCL保持高電平。SDA由低電平變爲高電平。
//產生IIC停止信號
//1.先拉低SDA,再拉低SCL
//2.拉高SCL
//3.拉高SDA
//4.停止接收數據
void IIC_Stop(void)
{
IIC_SCL=0;
IIC_SDA=0; //STOP:當SCL高時,數據由低變高
delay_us(4);
IIC_SCL=1;
IIC_SDA=1; //發送I2C總線結束信號
delay_us(4);
}
在起始條件產生後,總線處於忙狀態,由本次數據傳輸的主從設備獨佔,其他I2C器件無法訪問總線;而在停止條件產生後,本次數據傳輸的主從設備將釋放總線,總線再次處於空閒狀態。
數據有效性
IIC信號在數據傳輸過程中,當SCL=1高電平時,數據線SDA必須保持穩定狀態,不允許有電平跳變,只有在時鐘線上的信號爲低電平期間,數據線上的高電平或低電平狀態才允許變化。
SCL=1時 數據線SDA的任何電平變換會看做是總線的起始信號或者停止信號。
也就是在IIC傳輸數據的過程中,SCL時鐘線會頻繁的轉換電平,以保證數據的傳輸
應答信號
每當主機向從機發送完一個字節的數據,主機總是需要等待從機給出一個應答信號,以確認從機是否成功接收到了數據,
應答信號:主機SCL拉高,讀取從機SDA的電平,爲低電平表示產生應答
- 應答信號爲低電平時,規定爲有效應答位(ACK,簡稱應答位),表示接收器已經成功地接收了該字節;
- 應答信號爲高電平時,規定爲非應答位(NACK),一般表示接收器接收該字節沒有成功。
**每發送一個字節(8個bit)**在一個字節傳輸的8個時鐘後的第九個時鐘期間,接收器接收數據後必須回一個ACK應答信號給發送器,這樣才能進行數據傳輸。
應答出現在每一次主機完成8個數據位傳輸後緊跟着的時鐘週期,低電平0表示應答,1表示非應答,
//主機產生應答信號ACK
//1.先拉低SCL,再拉低SDA
//2.拉高SCL
//3.拉低SCL## 標題
void I2C_Ack(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA數據可以發生改變
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
//主機不產生應答信號NACK
//1.先拉低SCL,再拉高SDA
//2.拉高SCL
//3.拉低SCL
void I2C_NAck(void)
{
IIC_SCL=0; //先拉低SCL,使得SDA數據可以發生改變
IIC_SDA=1; //拉高SDA,不產生應答信號
delay_us(2);
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
}
IIC數據傳送
數據傳送格式
SDA線上的數據在SCL時鐘“高”期間必須是穩定的,只有當SCL線上的時鐘信號爲低時,數據線上的“高”或“低”狀態纔可以改變。輸出到SDA線上的每個字節必須是8位,數據傳送時,先傳送最高位(MSB),每一個被傳送的字節後面都必須跟隨一位應答位(即一幀共有9位)。
當一個字節按數據位從高位到低位的順序傳輸完後,緊接着從設備將拉低SDA線,回傳給主設備一個應答位ACK, 此時才認爲一個字節真正的被傳輸完成 ,如果一段時間內沒有收到從機的應答信號,則自動認爲從機已正確接收到數據。
IIC寫數據:
多數從設備的地址爲7位或者10位,一般都用七位。
八位設備地址=7位從機地址+讀/寫地址,
再給地址添加一個方向位位用來表示接下來數據傳輸的方向,
-
0表示主設備向從設備(write)寫數據,
-
1表示主設備向從設備(read)讀數據
IIC的每一幀數據由9bit組成,
如果是發送數據,則包含 8bit數據+1bit ACK,
如果是設備地址數據,則8bit包含7bit設備地址 1bit方向
在起始信號後必須傳送一個從機的地址(7位) 1~7位爲7位接收器件地址,第8位爲讀寫位,用“0”表示主機發送數據(W),“1”表示主機接收數據 (R), 第9位爲ACK應答位,緊接着的爲第一個數據字節,然後是一位應答位,後面繼續第2個數據字節。
IIC發送一個字節數據:
//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);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
IIC讀取一個字節數據:
//讀1個字節,ack=1時,發送ACK,ack=0,發送nACK
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;
}
IIC發送數據
Start: IIC開始信號,表示開始傳輸。
DEVICE_ADDRESS:: 從設備地址,就是7位從機地址
R/W: W(write)爲寫,R(read)爲讀
ACK: 應答信號
WORD_ADDRESS : 從機中對應的寄存器地址 比方說訪問 OLED中的 某個寄存器
DATA: 發送的數據
STOP: 停止信號。結束IIC
主機要向從機寫數據時:
- 主機首先產生START信號
- 然後緊跟着發送一個從機地址,這個地址共有7位,緊接着的第8位是數據方 向位(R/W),0表示主機發送數據(寫),1表示主機接收數據(讀)
- 主機發送地址時,總線上的每個從機都將這7位地址碼與自己的地址進行比較,若相同,則認爲自己正在被主機尋址,根據R/T位將自己確定爲發送器和接收器
- 這時候主機等待從機的應答信號(A)
- 當主機收到應答信號時,發送要訪問從機的那個地址, 繼續等待從機的應答信號
- 當主機收到應答信號時,發送N個字節的數據,繼續等待從機的N次應答信號,
- 主機產生停止信號,結束傳送過程。
IIC讀數據:
主機要從從機讀數據時
- 主機首先產生START信號
- 然後緊跟着發送一個從機地址,注意此時該地址的第8位爲0,表明是向從機寫命令,
- 這時候主機等待從機的應答信號(ACK)
- 當主機收到應答信號時,發送要訪問的地址,繼續等待從機的應答信號,
- 當主機收到應答信號後,主機要改變通信模式(主機將由發送變爲接收,從機將由接收變爲發送)所以主機重新發送一個開始start信號,然後緊跟着發送一個從機地址,注意此時該地址的第8位爲1,表明將主機設 置成接收模式開始讀取數據,
- 這時候主機等待從機的應答信號,當主機收到應答信號時,就可以接收1個字節的數據,當接收完成後,主機發送非應答信號,表示不在接收數據
- 主機進而產生停止信號,結束傳送過程。
以AT24C02爲例子
T24C02是一個2K位串行CMOS E2PROM,有一個16字節頁寫緩衝器。該器件通過IIC總線接口進行操作,有一個專門的寫保護功能, 如果WP管腳連接到Vcc,所有的內容都被寫保護只能讀。當WP管腳連接到Vss or GND 或懸空允許器件進行正常的讀/寫操作。
可以看出對於不同大小的24Cxx,具有不同的從器件地址。由於24C02爲2k容量,也就是說只需要參考圖中第一行的內容:
芯片的尋址:
AT24C02是的固定地址是1010A2A1A0R/W,A2A1A0這三位是由引腳確定的,一般都是000,
也就是說如果是寫24C02的時候,從器件地址爲10100000(0xA0);讀24C02的時候,從器件地址爲10100001(0xA1)。
片內地址尋址:
芯片尋址可對內部256B中的任一個進行讀/寫操作,其尋址範圍爲00~FF,共256個尋址單位。
對應的修改 A2A1A0 三位數據即可
//IIC發送數據
//address 要寫入的地址
//date 要寫入的數據
void write_add(uchar address,uchar date)
{
IIC_Start();
IIC_Send_Byte(0xA0);
delay(2);
IIC_Send_Byte(address);
delay(2);
IIC_Send_Byte(date);
delay(2);
IIC_Stop();
}
//IIC讀取數據
// address 要讀取數據的地址
uchar read_add(uchar address) //指定地址讀一個字節數據
{
uchar add;
IIC_Start();
IIC_Send_Byte(0xA0);
delay(2);
IIC_Send_Byte(address);
delay(2);
IIC_Start();
IIC_Send_Byte(0xA1);
delay(2);
dd=IIC_Read_Byte();
IIC_Stop();
return add;
}
軟件IIC和硬件IIC
IIC分爲軟件IIC和硬件IIC
軟件IIC:軟件IIC通信指的是用單片機的兩個I/O端口模擬出來的IIC,用軟件控制管腳狀態以模擬I2C通信波形,軟件模擬寄存器的工作方式。
硬件IIC:一塊硬件電路,硬件I2C對應芯片上的I2C外設,有相應I2C驅動電路,其所使用的I2C管腳也是專用的,硬件(固件)I2C是直接調用內部寄存器進行配置。
硬件I2C的效率要遠高於軟件的,而軟件I2C由於不受管腳限制,接口比較靈活。