IIC 總線簡(jiǎn)介
I2C 總線是一種用于IC 器件之間連接的二線制總線。它通過(guò)SDA(串行數(shù)據(jù)線)及SCL(串行時(shí)鐘線)兩根線在連到總線上的器件之間傳送數(shù)據(jù),并根據(jù)地址識(shí)別每個(gè)器件:不管是單片機(jī)、存儲(chǔ)器、LCD 驅(qū)動(dòng)器還是鍵盤接口。I2C 能用于替代標(biāo)準(zhǔn)的并行總線,能連接各種集成電路和功能模塊。支持IIC 的設(shè)備有微控制器、ADC、DAC、儲(chǔ)存器、LCD 控制器、LED 驅(qū)動(dòng)器以及實(shí)時(shí)時(shí)鐘等。采用I2C 總線標(biāo)準(zhǔn)的單片機(jī)或IC 器件,其內(nèi)部不僅有I2C 接口電路,而且將內(nèi)部各單元電路按功能劃分為若干相對(duì)獨(dú)立的模塊,通過(guò)軟件尋址實(shí)現(xiàn)片選,減少了器件片選線的連接。CPU 不僅能通過(guò)指令將某個(gè)功能單元掛靠或摘離總線,還可對(duì)該單元的工作狀況進(jìn)檢測(cè),從而實(shí)現(xiàn)對(duì)硬件系統(tǒng)簡(jiǎn)單而靈活的擴(kuò)展與控制。I2C 總線接口電路結(jié)構(gòu)如下圖所示:
IIC 總線接口特性
1.單片機(jī)串行接口的發(fā)送和接收一般都各用一條線,如的TXD 和RXD,而I2C總線則根據(jù)器件的功能通過(guò)軟件程序使其可工作于發(fā)送或接收方式。
2.當(dāng)某個(gè)器件向總線上發(fā)送信息時(shí),它就是發(fā)送器(也叫主器件),而當(dāng)其從總線上接收信息時(shí),又成為接收器(也叫從器件)。
3.主器件用于啟動(dòng)總線上傳送數(shù)據(jù)并產(chǎn)生時(shí)鐘以開放傳送的器件,此時(shí)任何被尋址的器件均被認(rèn)為是從器件。I2C 總線的控制完全由掛接在總線上的主器件送出的地址和數(shù)據(jù)決定。
4.總線上主和從(即發(fā)送和接收)的關(guān)系不是一成不變的,而是取決于此時(shí)數(shù)據(jù)傳送的方向。
5.I2C 總線的數(shù)據(jù)傳送速率在標(biāo)準(zhǔn)工作方式下為100kbit/s,快速方式下最高傳送速率400kbit/s。
6.在I2C 總線上傳送信息時(shí)的時(shí)鐘同步信號(hào)是由掛接在SCL 時(shí)鐘線上的所有器件的邏輯“與”完成的。SCL 線上由高電平到低電平的跳變將影響到這些器件,一旦某個(gè)器件的時(shí)鐘信號(hào)下跳為低電平,將使SCL 線一直保持低電平,使SCL線上的所有器件開始低電平期。
7.當(dāng)所有器件的時(shí)鐘信號(hào)都上跳為高電平時(shí),低電平期結(jié)束,SCL 線被釋放返回高電平,即所有的器件都同時(shí)開始它們的高電平期。其后,第一個(gè)結(jié)束高電平期的器件又將SCL 線拉成低電平。這樣就在SCL 線上產(chǎn)生一個(gè)同步時(shí)鐘。可見,時(shí)鐘低電平時(shí)間由時(shí)鐘低電平期最長(zhǎng)的器件確定,而時(shí)鐘高電平時(shí)間由時(shí)鐘高電平期最短的器件確定。
8.在I2C 總線技術(shù)規(guī)范中,開始和結(jié)束信號(hào)(也稱啟動(dòng)和停止信號(hào))的定義如下圖所示。
9.當(dāng)時(shí)鐘線SCL 為高電平時(shí),數(shù)據(jù)線SDA 由高電平跳變?yōu)榈碗娖蕉x為“開始”信號(hào);
10.當(dāng)SCL 線為高電平時(shí),SDA 線發(fā)生低電平到高電平的跳變?yōu)椤敖Y(jié)束”信號(hào)。
11.開始和結(jié)束信號(hào)都是由主器件產(chǎn)生。
12.在開始信號(hào)以后,總線即被認(rèn)為處于忙狀態(tài);在結(jié)束信號(hào)以后的一段時(shí)間內(nèi),總線被認(rèn)為是空閑的。
IIC 總線數(shù)據(jù)傳送格式
1.在I2C 總線開始信號(hào)后,送出的第一個(gè)字節(jié)數(shù)據(jù)是用來(lái)選擇從器件地址的。
(1) 其中前7 位為地址碼;
(2) 第8 位為方向位(R/W)。方向位為“0”表示發(fā)送,即主器件把信息寫到所選擇的從器件;方向位為“1”表示主器件將從從器件讀信息。
2. 在I2C 總線上每次傳送的數(shù)據(jù)字節(jié)數(shù)不限,但每一個(gè)字節(jié)必須為8 位,而且每個(gè)傳送的字節(jié)后面必須跟一個(gè)認(rèn)可位(第9 位),也叫應(yīng)答位(ACK);
為了完成一個(gè)字節(jié)的傳輸,接收方應(yīng)該向發(fā)送方發(fā)送一個(gè)ACK位。ACK應(yīng)該發(fā)生在SCL線的第九個(gè)脈沖期間。當(dāng)接受到ACK信號(hào)時(shí),發(fā)送方應(yīng)該釋放SDA線使SDA線電平為高。接收方應(yīng)該驅(qū)動(dòng)SDA線為低在ACK脈沖過(guò)程中。因此,在第九個(gè)SCL脈沖的高電平期間SDA保持為低(因?yàn)樾盘?hào)是“與”的)。ACK的傳輸可以由軟件通過(guò)IICSTAT寄存器控制是否禁止,但它仍然是需要產(chǎn)生的。
IIC 總線數(shù)據(jù)傳送過(guò)程
1.每次都是先傳最高位,通常從器件在接收到每個(gè)字節(jié)后都會(huì)做出響應(yīng),即釋放SCL線返回高電平,準(zhǔn)備接收下一個(gè)數(shù)據(jù)字節(jié),主器件可繼續(xù)傳送。
2.如果從器件正在處理一個(gè)實(shí)時(shí)事件而不能接收數(shù)據(jù)時(shí),(例如正在處理一個(gè)內(nèi)部中斷,在這個(gè)中斷處理完之前就不能接收I2C 總線上的數(shù)據(jù)字節(jié))可以使時(shí)鐘SCL線保持低電平,從器件必須使SDA 保持高電平,此時(shí)主器件產(chǎn)生1 個(gè)結(jié)束信號(hào),使傳送異常結(jié)束,迫使主器件處于等待狀態(tài)。當(dāng)從器件處理完畢時(shí)將釋放SCL 線,主器件繼續(xù)傳送
讀寫操作
在發(fā)送模式下,當(dāng)一個(gè)數(shù)據(jù)傳輸時(shí),IIC總線接口將等待直到IICDS寄存器收到一個(gè)新數(shù)據(jù)。在一個(gè)新數(shù)據(jù)寫入IICDS寄存器前,SCL信號(hào)將保持為低。在數(shù)據(jù)被寫入之后,信號(hào)線被釋放(為高)。ARM需要保持中斷信號(hào)來(lái)辨別當(dāng)前數(shù)據(jù)發(fā)送完成。在ARM接到一個(gè)中斷請(qǐng)求后,它將寫一個(gè)新的數(shù)據(jù)到IICDS。
在接收模式下,當(dāng)一個(gè)數(shù)據(jù)接收時(shí),IIC總線接口將等待直到IICDS寄存器數(shù)據(jù)被讀出。在新數(shù)據(jù)被讀出之前,SCL信號(hào)保持為低。在數(shù)據(jù)被讀出后,信號(hào)線被釋放(為高)。ARM應(yīng)保持中斷信號(hào)以辨別接收數(shù)據(jù)操作完成。在ARM收到一個(gè)中斷請(qǐng)求時(shí),它將從IICDS讀出數(shù)據(jù)。
IIC 總線競(jìng)爭(zhēng)和仲裁機(jī)制
1. 總線上可能掛接有多個(gè)器件,有時(shí)會(huì)發(fā)生兩個(gè)或多個(gè)主器件同時(shí)想占用總線的情
況。
2. I2C 總線具有多主控能力,可以對(duì)發(fā)生在SDA 線上的總線競(jìng)爭(zhēng)進(jìn)行仲裁。
3. 其仲裁原則為:當(dāng)多個(gè)主器件同時(shí)想占用總線時(shí),如果某個(gè)主器件發(fā)送高電平,
而另一個(gè)主器件發(fā)送低電平,則發(fā)送電平與此時(shí)SDA 總線電平不符的那個(gè)器件將
自動(dòng)關(guān)閉其輸出級(jí)。
IIC 總線工作流程
開始:信號(hào)表明傳輸開始。
地址:主設(shè)備發(fā)送地址信息,包含7 位的從設(shè)備地址和1 位的指示位(表明讀或者寫,即數(shù)據(jù)流的方向)。
數(shù)據(jù):根據(jù)指示位,數(shù)據(jù)在主設(shè)備和從設(shè)備之間傳輸。數(shù)據(jù)一般以8 位傳輸,最重要的位放在前面;具體能傳輸多少量的數(shù)據(jù)并沒有限制。接收器上用一位的ACK 表明每一個(gè)字節(jié)都收到了。傳輸可以被終止和重新開始。
停止:信號(hào)結(jié)束傳輸。
S3C2410 的IIC 總線控制器
S3C2410 處理器提供了一個(gè)I2C 串行總線,包括一個(gè)專門的串行數(shù)據(jù)線和串行時(shí)
鐘線。它的操作模式有四種:
1.主設(shè)備發(fā)送模式
2.主設(shè)備接收模式
3.從設(shè)備發(fā)送模式
4.從設(shè)備接收模式
下圖為S3C2410 的IIC 功能框圖:
發(fā)送和接收步驟
在任何IIC Tx/Rx 操作之前,下面的步驟必須被執(zhí)行
1. 如果需要的話,向IICADD 寄存器寫從器件地址
2. 設(shè)置IICCON 寄存器
a) 允許中斷
b) 定義SCL 的時(shí)鐘周期
3. 設(shè)置IICSTAT 來(lái)允許串行輸出
IIC 總線控制相關(guān)寄存器
IIC 總線控制寄存器(IICCON)
Register
Address
R/W
Description
Reset Value
IICCON
0x54000000
R/W
總線控制寄存器
0x0X
IICCON
Bit
Description
Initial State
Acknowledge generation (note 1)
[7]
IIC總線確認(rèn)位使能
0 = 禁止, 1 =使能
在Tx模式,IICSDA在確認(rèn)時(shí)間內(nèi)是任意的,在Rx 模式中= IICSDA 在確認(rèn)時(shí)間內(nèi)是低
0
Tx clock source selection
[6]
IIC總線傳輸時(shí)間對(duì)于資源時(shí)間的分頻位
0 = IICCLK = fPCLK /16
1 = IICCLK = fPCLK /512
0
Tx/Rx Interrupt (note 5)
[5]
IIC總線 Tx/Rx中斷使能/禁止位
0 = Disable, 1 = Enable
0
Interrupt pending flag (note 2), (note 3)
[4]
IIC總線Tx/Rx中斷未決標(biāo)志位.
該位不能被寫為1,當(dāng)該位讀為1的時(shí)候,IICSCL信號(hào)為低并且IIC停止,要恢復(fù)操作,只需將該位清零
0 = 1) 沒有中斷未決(讀)2)清除未決狀態(tài) &恢復(fù)操作 (寫).
1 = 1) 中斷未決(讀) 2) N/A (寫)
0
Transmit clock value (note 4)
[3:0]
IIC總線傳輸時(shí)鐘預(yù)分頻 IIC總線傳輸時(shí)鐘頻率由這個(gè)四位的值決定,由下列公式?jīng)Q定
Tx clock =IICCLK/(IICCON[3:0]+1).
未定義
注意:
1.下面的幾種情況將產(chǎn)生一個(gè)IIC 中斷:
1) 當(dāng)一個(gè)字節(jié)傳輸或接受操作完成的時(shí) ;
2) 一個(gè)普通調(diào)用或一個(gè)從地址匹配產(chǎn)生時(shí);
3) 總線仲裁失敗時(shí);
2. 為了在IISSCL信號(hào)的上升沿之前調(diào)整IICSDA的設(shè)置時(shí)間,IICDS必須要在IIC的中斷位清零之前寫入。
3.IICLK 由IICCON[6]決定;
Tx時(shí)鐘會(huì)因?yàn)镾CL時(shí)間的轉(zhuǎn)換而改變
IIC 狀態(tài)寄存器(IICSTAT)
Register
Address
R/W
Description
Reset Value
IICSTAT
0x54000004
R/W
IIC總線狀態(tài)寄存器
0x0
IICSTAT
Bit
Description
Initial State
Mode selection
[7:6]
IIC總線主/從 Tx/Rx模式選擇位.
00: 從設(shè)備接受模式 01: 從設(shè)備發(fā)送模式
10: 主設(shè)備接受模式 11: 主設(shè)備發(fā)送模式
00
Busy signal status / START STOP condition
[5]
IIC總線忙信號(hào)狀態(tài)位
0 = 讀) 空閑 寫) STOP 信號(hào)產(chǎn)生
1 = 讀) 忙 寫) START信號(hào)產(chǎn)生.
IICDS中的數(shù)據(jù)在START信號(hào)后自動(dòng)傳輸
Serial output
[4]
IIC總線數(shù)據(jù)輸出使能/禁止位
0 =禁止 Rx/Tx, 1 = 使能 Rx/Tx
0
Arbitration status flag
[3]
IIC總線過(guò)程仲裁狀態(tài)位
0 =總線仲裁成功
1 = 在連續(xù)I/O 中總線仲裁失敗
0
Address-as-slave status flag
[2]
IIC總線從地址狀態(tài)標(biāo)志位.
0 = 當(dāng)START/STOP信號(hào)探測(cè)到時(shí)清零
1 =接收到的slave地址匹配IICADD的值
0
Address zero status flag
[1]
IIC總線地址零狀態(tài)標(biāo)志位
0 =當(dāng)START/STOP信號(hào)探測(cè)到時(shí)清零.
1 =接收到的從地址為 00000000b.
0
Last-received bit status flag
[0]
IIC總線IIC-bus上一次接收到的狀態(tài)標(biāo)志位.
0 =上一次接收到的位是0 (ACK was received).
1 =上一次接收到的位是1 (ACK was not received).
0
地址寄存器(IICADD)
Register
Address
R/W
Description
Reset Value
IICADD
0x54000008
R/W
IIC總線地址寄存器
0xXX
IICADD
Bit
Description
Initial State
Slave address
[7:0]
7位從地址,從IIC總線中鎖存
XXXXXXXX
當(dāng)IICSTAT 串行輸出允許為0,IICADD 為寫允許的時(shí)候
IICADD的值可以在任何時(shí)候被讀取, 而不用管當(dāng)前串行
輸出允許位(IICSTAT)的設(shè)置
從地址 = [7:1]
Not mapped = [0]
移位數(shù)據(jù)寄存器(IICDS)
Register
Address
R/W
Description
Reset Value
IICDS
0x5400000C
R/W
IIC總線移位數(shù)據(jù)寄存器
0xXX
IICDS
Bit
Description
Initial State
Data shift
[7:0]
IIC總線Tx/Rx 操作的8位移位寄存器
XXXXXXXX
當(dāng)IICSTAT 串行輸出允許為1,IICADD 為寫允許的時(shí)候
IICDS的值可以在任何時(shí)候被讀取, 而不用管當(dāng)前串行輸
出允許位(IICSTAT)的設(shè)置.
實(shí)驗(yàn)內(nèi)容
根據(jù)前面的原理介紹,編寫一個(gè)程序來(lái)實(shí)現(xiàn)IIC的讀寫操作。
實(shí)驗(yàn)步驟
1. 閱讀相關(guān)原理介紹,了解IIC協(xié)議發(fā)送和接收的基本過(guò)程。
2. 閱讀本實(shí)驗(yàn)的源代碼,更深層次理解IIC的實(shí)現(xiàn)細(xì)節(jié),時(shí)序要求等。
3. 自己動(dòng)手編寫一個(gè)程序來(lái)實(shí)現(xiàn)IIC的讀寫操作。
實(shí)驗(yàn)源碼
主函數(shù)Main
#include "2410header.h"
#include "2410IIC.h"
void Main(void)
{
sysinit(); //系統(tǒng)初始化代碼,主要完成串口的初始化工作
Delay(0); //calibrate Delay()
Uart_Printf("IIC Test Pol:\n"); //串口打印數(shù)據(jù)
while (1)
{
Test_Iic2(); //IIC測(cè)試程序
Delay(1000);
Uart_Printf("\n\nPress Any Key To Continue\n\n");
Uart_Getch();
}
}
測(cè)試函數(shù)Test_Iic2
void Test_Iic2(void)
{
unsigned int i,j,save_E,save_PE;
static U8 data[256];
Uart_Printf("[ IIC Test(Polling) using KS24C080 ]\n");
save_E = rGPECON; //保存寄存器的原來(lái)的值,等程序結(jié)束后恢復(fù)原值。
save_PE = rGPEUP;
rGPEUP |= 0xc000; //上拉禁止
rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL
//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICADD = 0x10; //2410 slave address = [7:1]
rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
Uart_Printf("\nWrite test data into KS24C080(0-255)\n");
for(i=0;i<256;i++)
_Wr24C080(0xa0,(U8)i,i); //向EEPROM寫數(shù)據(jù)
for(i=0;i<256;i++)
data[i] = 0; //初始化數(shù)組的值為0,
Uart_Printf("\nRead test data from KS24C080\n");
for(i=0;i<256;i++)
_Rd24C080(0xa0,(U8)i,&(data[i])); //讀取EEPROM中的數(shù)據(jù)
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS24C080(255-0)\n");
for(i=0;i<256;i++)
_Wr24C080(0xa0,(U8)i,255-i);
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS24C080\n");
for(i=0;i<256;i++)
_Rd24C080(0xa0,(U8)i,&(data[i]));
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS24C080(255-255)\n");
for(i=0;i<256;i++)
_Wr24C080(0xa0,(U8)i,255);
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS24C080\n");
for(i=0;i<256;i++)
_Rd24C080(0xa0,(U8)i,&(data[i]));
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS24C080(1-1)\n");
for(i=0;i<256;i++)
_Wr24C080(0xa0,(U8)i,1);
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS24C080\n");
for(i=0;i<256;i++)
_Rd24C080(0xa0,(U8)i,&(data[i]));
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
rGPEUP = save_PE;
rGPECON = save_E;
}
寫EEPROM函數(shù)_Wr24C080
void _Wr24C080(U32 slvAddr,U32 addr,U8 data)
{
_iicMode = WRDATA;
_iicPt = 0;
_iicData[0] = (U8)addr;
_iicData[1] = data;
_iicDataCount = 2;
rIICDS = slvAddr; //0xa0
//Master Tx mode, Start(Write), IIC-bus data output enable
//Bus arbitration sucessful, Address as slave status flag Cleared,
//Address zero status flag cleared, Last received bit is 0
rIICSTAT = 0xf0;
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(_iicDataCount!=-1)
Run_IicPoll();
_iicMode = POLLACK;
while(1)
{
rIICDS = slvAddr;
_iicStatus = 0x100; //To check if _iicStatus is changed
rIICSTAT = 0xf0; //Master Tx, Start, Output Enable, Sucessful, Cleared, Cleared, 0
rIICCON = 0xaf; //Resumes IIC operation.
while(_iicStatus==0x100)
Run_IicPoll();
if(!(_iicStatus & 0x1))
break; //When ACK is received
}
rIICSTAT = 0xd0; //Master Tx condition, Stop(Write), Output Enable
rIICCON = 0xaf; //Resumes IIC operation.
Delay(1); //Wait until stop condtion is in effect.
//Write is completed.
}
讀EEPROM函數(shù)_Rd24C080
void _Rd24C080(U32 slvAddr,U32 addr,U8 *data)
{
_iicMode = SETRDADDR;
_iicPt = 0;
_iicData[0] = (U8)addr;
_iicDataCount = 1;
rIICDS = slvAddr;
rIICSTAT = 0xf0; //MasTx,Start
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(_iicDataCount!=-1)
Run_IicPoll();
_iicMode = RDDATA;
_iicPt = 0;
_iicDataCount = 1;
rIICDS = slvAddr;
rIICSTAT = 0xb0; //Master Rx,Start
rIICCON = 0xaf; //Resumes IIC operation.
while(_iicDataCount!=-1)
Run_IicPoll();
*data = _iicData[1];
}