I2C簡介
I2C總線是由Philips公司開發(fā)的一種簡單、雙向二線制同步串行總線。它只需要兩根線即可在連接于總線上的器件之間傳送信息。主器件用于啟動(dòng)總線傳送數(shù)據(jù),并產(chǎn)生時(shí)鐘以開放傳送的器件,此時(shí)任何被尋址的器件均被認(rèn)為是從器件.在總線上主和從、發(fā)和收的關(guān)系不是恒定的,而取決于此時(shí)數(shù)據(jù)傳送方向。如果主機(jī)要發(fā)送數(shù)據(jù)給從器件,則主機(jī)首先尋址從器件,然后主動(dòng)發(fā)送數(shù)據(jù)至從器件,最后由主機(jī)終止數(shù)據(jù)傳送;如果主機(jī)要接收從器件的數(shù)據(jù),首先由主器件尋址從器件.然后主機(jī)接收從器件發(fā)送的數(shù)據(jù),最后由主機(jī)終止接收過程。在這種情況下.主機(jī)負(fù)責(zé)產(chǎn)生定時(shí)時(shí)鐘和終止數(shù)據(jù)傳送。
I2C工作原理
SDA(串行數(shù)據(jù)線)和SCL(串行時(shí)鐘線)都是雙向I/O線,接口電路為開漏輸出.需通過上拉電阻接電源VCC.當(dāng)總線空閑時(shí).兩根線都是高電平,連接總線的外同器件都是CMOS器件,輸出級也是開漏電路.在總線上消耗的電流很小,因此,總線上擴(kuò)展的器件數(shù)量主要由電容負(fù)載來決定,因?yàn)槊總€(gè)器件的總線接口都有一定的等效電容.而線路中電容會影響總線傳輸速度.當(dāng)電容過大時(shí),有可能造成傳輸錯(cuò)誤.所以,其負(fù)載能力為400pF,因此可以估算出總線允許長度和所接器件數(shù)量。
主器件用于啟動(dòng)總線傳送數(shù)據(jù),并產(chǎn)生時(shí)鐘以開放傳送的器件,此時(shí)任何被尋址的器件均被認(rèn)為是從器件.在總線上主和從、發(fā)和收的關(guān)系不是恒定的,而取決于此時(shí)數(shù)據(jù)傳送方向。如果主機(jī)要發(fā)送數(shù)據(jù)給從器件,則主機(jī)首先尋址從器件,然后主動(dòng)發(fā)送數(shù)據(jù)至從器件,最后由主機(jī)終止數(shù)據(jù)傳送;如果主機(jī)要接收從器件的數(shù)據(jù),首先由主器件尋址從器件.然后主機(jī)接收從器件發(fā)送的數(shù)據(jù),最后由主機(jī)終止接收過程。在這種情況下.主機(jī)負(fù)責(zé)產(chǎn)生定時(shí)時(shí)鐘和終止數(shù)據(jù)傳送。
2C總線特點(diǎn)
(1)在硬件上,12C總線只需要一根數(shù)據(jù)線和一根時(shí)鐘線兩根線,總線接口已經(jīng)集成在芯片內(nèi)部,不需要特殊的接口電路,而且片上接口電路的濾波器可以濾去總線數(shù)據(jù)上的毛刺.因此I2C總線簡化了硬件電路PCB布線,降低了系統(tǒng)成本,提高了系統(tǒng)可靠性。因?yàn)?2C芯片除了這兩根線和少量中斷線,與系統(tǒng)再?zèng)]有連接的線,用戶常用IC可以很容易形成標(biāo)準(zhǔn)化和模塊化,便于重復(fù)利用。
?。?)I2C總線是一個(gè)真正的多主機(jī)總線,如果兩個(gè)或多個(gè)主機(jī)同時(shí)初始化數(shù)據(jù)傳輸,可以通過沖突檢測和仲裁防止數(shù)據(jù)破壞,每個(gè)連接到總線上的器件都有唯一的地址,任何器件既可以作為主機(jī)也可以作為從機(jī),但同一時(shí)刻只允許有一個(gè)主機(jī)。數(shù)據(jù)傳輸和地址設(shè)定由軟件設(shè)定,非常靈活。總線上的器件增加和刪除不影響其他器件正常工作。
?。?)I2C總線可以通過外部連線進(jìn)行在線檢測,便于系統(tǒng)故障診斷和調(diào)試,故障可以立即被尋址,軟件也利于標(biāo)準(zhǔn)化和模塊化,縮短開發(fā)時(shí)問。
?。?)連接到相同總線上的IC數(shù)量只受總線最大電容的限制,串行的8位雙向數(shù)據(jù)傳輸位速率在標(biāo)準(zhǔn)模式下可達(dá)100Kbit/s,快速模式下可達(dá)400Kbit/s,高速模式下可達(dá)3.4Mbit/s。
?。?)總線具有極低的電流消耗.抗高噪聲干擾,增加總線驅(qū)動(dòng)器可以使總線電容擴(kuò)大10倍,傳輸距離達(dá)到15m;兼容不同電壓等級的器件,工作溫度范圍寬。
Arduino主從機(jī)之間的I2C通訊實(shí)驗(yàn)
I2C總線是由數(shù)據(jù)線SDA和時(shí)鐘SCL構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù)。在CPU與被控IC之間、IC與IC之間進(jìn)行雙向傳送,最高傳送速率100kbps。各種被控制電路均并聯(lián)在這條總線上,但就像電話機(jī)一樣只有撥通各自的號碼才能工作,所以每個(gè)電路和模塊都有唯一的地址,在信息的傳輸過程中,I2C總線上并接的每一模塊電路既可以是主控器(或被控器),又可以是發(fā)送器(或接收器),這取決于它所要完成的功能。
Arduino通訊命令見網(wǎng)址:http://www.arduino.cc/en/Reference/Wire,我通過這次IIC通訊實(shí)驗(yàn)把這10個(gè)I2C通訊命令全部應(yīng)用到了。
我現(xiàn)在采用老版本A rduino-0018編程,老版本I2C通訊的發(fā)送數(shù)據(jù)命令是send(),接受數(shù)據(jù)命令是receive(),最新版本Arduino 1.0的發(fā)送數(shù)據(jù)的命令是write(),接受數(shù)據(jù)的命令是read(),這一點(diǎn)要注意啊,看清楚自己下載應(yīng)用的是什么版本的Arduino編程軟件。Arduino程序下載地址:http://arduino.cc/en/Main/Software
I2C實(shí)驗(yàn)說明: 主機(jī)向從機(jī)循環(huán)發(fā)送字符串“l(fā)ight is ”和字節(jié)x,x為1或0,從機(jī)接收后,把數(shù)據(jù)顯示在它的串口監(jiān)視器中,如上圖。然后當(dāng)主機(jī)通知從機(jī)向它上傳數(shù)據(jù)時(shí),會把x值再上傳回主機(jī),然后賦值給變量c。當(dāng)主機(jī)程序判斷c為1,則點(diǎn)亮主機(jī)數(shù)字端口13相連的LED,否則熄滅LED。
通過這個(gè)實(shí)驗(yàn)把主從機(jī)之間的雙向通訊都詮釋出來了。
實(shí)驗(yàn)全景圖:
把雙Arduino控制器的SCL和SDA以及GND三根引腳用杜邦線相連,如果不是兩個(gè)Arduino分別獨(dú)立供電,您就要把雙Arduino控制器的VCC也連一起,它們共用一個(gè)電源。這次實(shí)驗(yàn)就是把這四根線SCL和SDA以及GND、VCC都互連起來了。Arduino的SCL引腳位于模擬端口5,SDA引腳位于模擬端口4。
Arduino控制器源于DFRobot官方網(wǎng)址:http://item.taobao.com/item.htm?spm=1101*r1F.1-1mJ7T.3-1MYgQs&id=3136612323
注意:由于“單三角括號”里的內(nèi)容,博客里顯示不出來,所以我把頭文件聲明命令“被迫”進(jìn)行了修改,以便在博客里看到頭文件,例如改成“#include 《Wire.h》”。
Arduino主機(jī)程序:(包括與I2C通訊相關(guān)的命令)
/*主機(jī)向從機(jī)循環(huán)發(fā)送字符串“l(fā)ight is ”和字節(jié)x,x為1或0
從機(jī)接收到主機(jī)發(fā)來的數(shù)據(jù)后,當(dāng)主機(jī)通知從機(jī)向它上傳數(shù)據(jù)時(shí)
會把x值再上傳回主機(jī),然后賦值給變量c。
當(dāng)主機(jī)程序判斷c為1,則點(diǎn)亮LED,否則熄滅LED。*/
#include 《Wire.h》//聲明I2C庫文件
#define LED 13
byte x = 0;//變量x決定LED的亮滅
//初始化
void setup()
{
Wire.begin(); // 加入 i2c 總線,作為主機(jī)
pinMode(LED,OUTPUT);//設(shè)置數(shù)字端口13為輸出
}
//主程序
void loop()
{
Wire.beginTransmission(4); //發(fā)送數(shù)據(jù)到設(shè)備號為4的從機(jī)
Wire.send(“l(fā)ight is ”); // 發(fā)送字符串“l(fā)ight is ”
Wire.send(x); // 發(fā)送變量x中的一個(gè)字節(jié)
Wire.endTransmission(); // 停止發(fā)送
x++;//變量x加1
if(x==2)//如果變量x的值為2,則把x值轉(zhuǎn)為0
x=0;
delay(1000);//延時(shí)1s
Wire.requestFrom(4, 1); //通知4號從機(jī)上傳1個(gè)字節(jié)
while(Wire.available()》0) // 當(dāng)主機(jī)接收到從機(jī)數(shù)據(jù)時(shí)
{
byte c = Wire.receive(); //接收一個(gè)字節(jié)賦值給c
//判斷c為1,則點(diǎn)亮LED,否則熄滅LED。
if(c==1)
{digitalWrite(LED,LOW);}
else
{digitalWrite(LED,HIGH);}
}
delay(1000);//延時(shí)1s
}
Arduino從機(jī)程序:(包括與I2C通訊相關(guān)的命令)
/*循環(huán)接收主機(jī)發(fā)送來的數(shù)據(jù)包,同時(shí)顯示在串口監(jiān)視器上
把數(shù)據(jù)包的最后一個(gè)字節(jié),再上傳回主機(jī)
*/
#include 《Wire.h》//聲明I2C庫文件
int x;//變量x值決定主機(jī)的LED是否點(diǎn)亮
//初始化
void setup()
{
Wire.begin(4); // 加入 i2c 總線,設(shè)置從機(jī)地址為 #4
Wire.onReceive(receiveEvent); //注冊接收到主機(jī)字符的事件
Wire.onRequest(requestEvent); // 注冊主機(jī)通知從機(jī)上傳數(shù)據(jù)的事件
Serial.begin(9600); //設(shè)置串口波特率
}
//主程序
void loop()
{
delay(100);//延時(shí)
}
// 當(dāng)從機(jī)接收到主機(jī)字符,執(zhí)行該事件
void receiveEvent(int howMany)
{
while( Wire.available()》1) // 循環(huán)執(zhí)行,直到數(shù)據(jù)包只剩下最后一個(gè)字符
{
char c = Wire.receive(); // 作為字符接收字節(jié)
Serial.print(c); // 把字符打印到串口監(jiān)視器中
}
//接收主機(jī)發(fā)送的數(shù)據(jù)包中的最后一個(gè)字節(jié)
x = Wire.receive(); // 作為整數(shù)接收字節(jié)
Serial.println(x); //把整數(shù)打印到串口監(jiān)視器中,并回車
}
//當(dāng)主機(jī)通知從機(jī)上傳數(shù)據(jù),執(zhí)行該事件
void requestEvent()
{
//把接收主機(jī)發(fā)送的數(shù)據(jù)包中的最后一個(gè)字節(jié)再上傳給主機(jī)
Wire.send( x); // 響應(yīng)主機(jī)的通知,向主機(jī)發(fā)送一個(gè)字節(jié)數(shù)據(jù)
}
我通過這次I2C通訊實(shí)驗(yàn)把這10個(gè)Arduino的I2C通訊命令全部應(yīng)用到了,仔細(xì)看實(shí)驗(yàn)程序注釋,并實(shí)踐一次,就可以了解這Arduino控制器的I2C命令如何應(yīng)用了。
在數(shù)字通信各種協(xié)議中,相對Ethernet, USB, SATA, PCI-Express等傳輸速度達(dá)數(shù)百上千兆字節(jié)每秒的總線,I2C和SPI常稱為“小”協(xié)議。但是,我們不能忘記的是各種總線的用途是什么?!按蟆眳f(xié)議是用于系統(tǒng)外的整個(gè)系統(tǒng)之間通信的,“小”協(xié)議是用于系統(tǒng)內(nèi)各芯片間的通信,沒有跡象表明“大”協(xié)議有必要取代“小”協(xié)議。I2C和SPI的存在和流行體現(xiàn)了“夠用就好”的哲學(xué)。
評論
查看更多