這里要先介紹I2C總線中幾個(gè)專有名詞:
l 發(fā)送者:將數(shù)據(jù)發(fā)送到總線的設(shè)備
l 接收者:從總線接收數(shù)據(jù)的設(shè)備
l 主設(shè)備:產(chǎn)生時(shí)鐘信號(hào)、啟動(dòng)通信、發(fā)送I2C命令和終止通信的設(shè)備
l 從設(shè)備:監(jiān)聽(tīng)總線、能被主設(shè)備尋址的設(shè)備
l 多主設(shè)備:I2C能夠擁有多個(gè)主設(shè)備,而且每個(gè)主設(shè)備都能夠發(fā)送命令
l 仲裁:當(dāng)多個(gè)主設(shè)備請(qǐng)求使用總線時(shí),決定哪一個(gè)主設(shè)備可以占用的一個(gè)過(guò)程
l 同步:同步多個(gè)設(shè)備時(shí)鐘信號(hào)的一個(gè)過(guò)程
上面是從宏觀上對(duì)I2C總線介紹了下,接下來(lái)將深入細(xì)節(jié)研究其通信過(guò)程:
n 串行數(shù)據(jù)傳送:
在總線備用時(shí)SDA和SCL都必須保持高電平狀態(tài),只有關(guān)閉I2C總線時(shí)才能使SCL鉗位在低電平。在I2C總線數(shù)據(jù)傳輸時(shí),在時(shí)鐘線高電平期間,數(shù)據(jù)線上必須保持有穩(wěn)定的邏輯電平(也就是說(shuō)在數(shù)據(jù)傳輸期間只有時(shí)鐘線低電平期間,才允許數(shù)據(jù)線上的電平發(fā)生變化)。

圖 7_3 串行數(shù)據(jù)發(fā)送
因此在如圖7_3中對(duì)于每一個(gè)時(shí)鐘脈沖期間一比特的數(shù)據(jù)將會(huì)被傳送,SDA只能在時(shí)鐘信號(hào)為低電平時(shí)才能改變。下面是代碼中發(fā)送一字節(jié)的函數(shù):在循環(huán)體內(nèi)每次將dat內(nèi)的最高位移出到CY中,進(jìn)而賦值給SDA(這時(shí)SCL為低,SDA可改變)。接著拉高SCL并保持5us,最后再拉低SCL實(shí)現(xiàn)一個(gè)時(shí)鐘脈沖將dat中最高位送出。依此循環(huán)8次實(shí)現(xiàn)將dat全部傳出。
//------------------------------------------------
//向I2C總線發(fā)送一個(gè)字節(jié)數(shù)據(jù)
//------------------------------------------------
void I2C_SendByte(uchar dat)
{
uchar i;
for (i=0; i《8; i++) //8位計(jì)數(shù)器
{
dat 《《= 1; //移出數(shù)據(jù)的最高位
SDA = CY; //送數(shù)據(jù)口
SCL = 1; //拉高時(shí)鐘線
Delay5us(); //延時(shí)
SCL = 0; //拉低時(shí)鐘線
Delay5us(); //延時(shí)
}
I2C_RecvACK();
}
n 開(kāi)始和結(jié)束條件:
命令不會(huì)沒(méi)有任何預(yù)兆直接發(fā)送的,每一個(gè)I2C命令的發(fā)送總是開(kāi)始于開(kāi)始條件并結(jié)束于終止條件。這里所謂的開(kāi)始條件和終止條件起始也是由SCL和SDA組合形成的(如圖7_4)。

圖 7_4 開(kāi)始和結(jié)束條件
如果時(shí)鐘線保持高電平期間,數(shù)據(jù)線出現(xiàn)由高到低的電平變化,則會(huì)啟動(dòng)I2C總線,此時(shí)為I2C的起始信號(hào):
//------------------------------------------------
//I2C起始信號(hào)
//------------------------------------------------
void I2C_Start()
{
SDA = 1; //拉高數(shù)據(jù)線
SCL = 1; //拉高時(shí)鐘線
Delay5us(); //延時(shí)
SDA = 0; //產(chǎn)生下降沿
Delay5us(); //延時(shí)
SCL = 0; //拉低時(shí)鐘線
}
若在時(shí)鐘線保持高電平期間,數(shù)據(jù)線出現(xiàn)由低到高的電平變化,則會(huì)停止I2C總線的數(shù)據(jù)傳輸,此時(shí)為I2C的終止信號(hào):
//------------------------------------------------
//I2C停止信號(hào)
//------------------------------------------------
void I2C_Stop()
{
SDA = 0; //拉低數(shù)據(jù)線
SCL = 1; //拉高時(shí)鐘線
Delay5us(); //延時(shí)
SDA = 1; //產(chǎn)生上升沿
Delay5us(); //延時(shí)
}
開(kāi)始條件之后I2C總線被認(rèn)為是忙狀態(tài),只有當(dāng)停止信號(hào)之后其他主設(shè)備才能使用該總線。此外,當(dāng)開(kāi)始條件之后主設(shè)備能夠多次發(fā)出開(kāi)始信號(hào)。這些開(kāi)始信號(hào)和第一次發(fā)出的開(kāi)始信號(hào)類(lèi)似,他們后面經(jīng)常會(huì)跟從設(shè)備的地址。這樣可以方便實(shí)現(xiàn)在I2C總線忙期間,當(dāng)前占線的主設(shè)備可以和不同的從設(shè)備進(jìn)行通信。
n I2C數(shù)據(jù)傳送:
I2C總線上傳送的每一個(gè)字節(jié)均為8位,但是每啟動(dòng)一次I2C總線,其后的數(shù)據(jù)傳送字節(jié)數(shù)是沒(méi)有限制的。同時(shí)每傳送一字節(jié)的數(shù)據(jù)后面都要跟隨一個(gè)接收者回應(yīng)的應(yīng)答位(低電平為應(yīng)答信號(hào),高電平為非應(yīng)答信號(hào)),當(dāng)全部數(shù)據(jù)發(fā)送完畢后主設(shè)備發(fā)送終止信號(hào)。

圖 7_5 數(shù)據(jù)傳送圖
所以在上面向I2C總線發(fā)送一字節(jié)的數(shù)據(jù)的代碼的最后有一個(gè)I2C_RecvACK()函數(shù)。(如下)該函數(shù)負(fù)責(zé)接收接收者發(fā)送過(guò)來(lái)的應(yīng)答信號(hào),也即圖7_5中的第9個(gè)時(shí)鐘脈沖的期間的相應(yīng)操作。
//------------------------------------------------
//I2C接收應(yīng)答信號(hào)
//------------------------------------------------
bit I2C_RecvACK()
{
SCL = 1; //拉高時(shí)鐘線
Delay5us(); //延時(shí)
CY = SDA; //讀應(yīng)答信號(hào)
SCL = 0; //拉低時(shí)鐘線
Delay5us(); //延時(shí)
return CY;
}
電子發(fā)燒友App






評(píng)論