當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > I2C總線協(xié)議簡(jiǎn)介
在物聯(lián)倉(cāng)儲(chǔ)系統(tǒng)和智能小車中,很多情況下都需要使用I2C總線協(xié)議進(jìn)行數(shù)據(jù)傳輸,本文將對(duì)該協(xié)議做一個(gè)簡(jiǎn)單的整理介紹。
一、I2C 總線的一些特征:
• 只要求兩條總線線路一條串行數(shù)據(jù)線SDA 一條串行時(shí)鐘線SCL
• 每個(gè)連接到總線的器件都可以通過唯一的地址和一直存在的簡(jiǎn)單的主機(jī)從機(jī)關(guān)系軟件設(shè)定地址主機(jī)可以作為主機(jī)發(fā)送器或主機(jī)接收器
• 它是一個(gè)真正的多主機(jī)總線如果兩個(gè)或更多主機(jī)同時(shí)初始化數(shù)據(jù)傳輸可以通過沖突檢測(cè)和仲裁防止數(shù)據(jù)被破壞
• 串行的8 位雙向數(shù)據(jù)傳輸位速率在標(biāo)準(zhǔn)模式下可達(dá)100kbit/s 快速模式下可達(dá)400kbit/s 高速模式下可達(dá)3.4Mbit/s
• 片上的濾波器可以濾去總線數(shù)據(jù)線上的毛刺波保證數(shù)據(jù)完整
• 連接到相同總線的IC 數(shù)量只受到總線的大電容400pF 限制
二、I2C總線在傳送數(shù)據(jù)過程中共有三種類型信號(hào):開始信號(hào)、結(jié)束信號(hào)和應(yīng)答信號(hào)。
開始信號(hào):SCL為高電平時(shí),SDA由高電平向低電平跳變,開始傳送數(shù)據(jù)。
結(jié)束信號(hào):SCL為高電平時(shí),SDA由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)。
應(yīng)答信號(hào):接收數(shù)據(jù)的IC在接收到8bit數(shù)據(jù)后,向發(fā)送數(shù)據(jù)的IC發(fā)出特定的低電平脈沖,表示已收到數(shù)據(jù)。程序如下所示:
起始和結(jié)束:
bool I2C_Start(void)
{
SDA_H;
SCL_H;
I2C_delay();
if(!SDA_read)return FALSE; // SDA線為低電平則總線忙,退出
SDA_L; // 拉低SDA線(當(dāng)SCL為高電平時(shí),SDA由高電平向低電平跳變表示開始信號(hào))
I2C_delay();
if(SDA_read) return FALSE; // SDA線為高電平則總線出錯(cuò),退出
SDA_L; //數(shù)據(jù)為準(zhǔn)備好時(shí),拉低SCL線
I2C_delay();
return TRUE;
}
發(fā)出開始信號(hào)之后,設(shè)備在數(shù)據(jù)未準(zhǔn)備好時(shí),拉低SCL線,這樣主設(shè)備可知從設(shè)備未發(fā)送數(shù)據(jù),從設(shè)備在數(shù)據(jù)準(zhǔn)備好,可以發(fā)送的時(shí)候,停止拉低SCL線,這時(shí)候才開始真正的數(shù)據(jù)傳輸。程序如下所示:
void I2C_Stop(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H; // SCL為高電平時(shí),SDA由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)
I2C_delay();
SDA_H;
I2C_delay();
}
STOP在單主環(huán)境下非必要,但在多主環(huán)境就非常必要,主控總線的設(shè)備發(fā)送STOP后,通知總線其他設(shè)備總線已經(jīng)閑置。
void I2C_Ack(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
當(dāng)主機(jī)作為接收設(shè)備時(shí),主機(jī)對(duì)后一個(gè)字節(jié)不應(yīng)答,以向發(fā)送設(shè)備(從設(shè)備)標(biāo)識(shí)數(shù)據(jù)傳送結(jié)束。這是因?yàn)槊看蝹鬏敹紤?yīng)得到應(yīng)答信號(hào)后再進(jìn)行下一個(gè)字節(jié)傳送。如果此時(shí)接收機(jī)應(yīng)答了,那它就接收的不是后一個(gè)字節(jié)了。如果是后一個(gè)字節(jié),第9個(gè)時(shí)鐘周期發(fā)送的是非應(yīng)答信號(hào)(此時(shí)發(fā)送的不是應(yīng)答信號(hào)就是非應(yīng)答信號(hào)),后發(fā)送停止信號(hào)。
1)主發(fā)從收:主START->主發(fā)地址->從ACK->(主發(fā)數(shù)據(jù)->從ACK(循環(huán)))->主STOP或主 START啟動(dòng)下一次傳輸,這一過程中,主控SCL線,從只在ACK時(shí)控SDA線,其他時(shí)刻主控SDA線。
2)主收從發(fā):主START->從發(fā)地址->主ACK->(從發(fā)數(shù)據(jù)->主ACK(循環(huán)))->接受至后一個(gè)字節(jié)時(shí),主 NACK->主 STOP 或主START啟動(dòng)下一次傳輸。注意,并非每傳輸8位數(shù)據(jù)之后,都會(huì)有ACK信號(hào),有以下3中例外
(1)當(dāng)從機(jī)不能響應(yīng)從機(jī)地址時(shí)(例如它正忙于其他事而無法響應(yīng)IIC總線的操作,或者這個(gè)地址沒有對(duì)應(yīng)的從機(jī)),在第9個(gè)SCL周期內(nèi)SDA線沒有拉低,即沒有ACK信號(hào)。這時(shí),主機(jī)發(fā)出一個(gè)P信號(hào)終止傳輸或者重新發(fā)出一個(gè)S信號(hào)開始新的傳輸。
(2)如果從機(jī)接收器在傳輸過程中不能接收更多的數(shù)據(jù)時(shí),它不會(huì)發(fā)出ACK信號(hào)。這樣,主機(jī)就可以意識(shí)到這點(diǎn),從而發(fā)出一個(gè)P信號(hào)終止傳輸或者重新發(fā)出一個(gè)S信號(hào)開始新的傳輸。
(3)主機(jī)接收器在接收到后一個(gè)字節(jié)后,也不會(huì)發(fā)出ACK信號(hào)。于是,從機(jī)發(fā)送器釋放SDA線,以允許主機(jī)發(fā)出P信號(hào)結(jié)束傳輸。
位傳輸:
主機(jī)向從機(jī)發(fā)送一字節(jié)數(shù)據(jù)
void I2C_SendByte(u8 SendByte) //數(shù)據(jù)從高位到低位
{
u8 i=8;
while(i--)
{
SCL_L;
I2C_delay();
if(SendByte&0x80)
SDA_H;
else
SDA_L;
SendByte<<=1;
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
}
三、7位尋址
在起始條件S 后發(fā)送了一個(gè)從機(jī)地址,這個(gè)地址共有7 位,緊接著的第8 位是數(shù)據(jù)方向位R/W ,0表示發(fā)送寫、1表示請(qǐng)求數(shù)據(jù)讀:
數(shù)據(jù)傳輸一般由主機(jī)產(chǎn)生的停止位P終止,但是如果主機(jī)仍希望在總線上通訊它可以產(chǎn)生重復(fù)起始條件Sr和尋址另一個(gè)從機(jī),而不是首先產(chǎn)生一個(gè)停止條件。
那么在完整的數(shù)據(jù)傳輸過程中,stm32如何建立與EEPROM的通訊
1、 配置I/O端口,確定并配置I2C的模式,使能GPIO和I2C時(shí)鐘。
2、 寫:
檢測(cè)SDA是否空閑;
->按I2C協(xié)議發(fā)出起始訊號(hào);
->發(fā)出7位器件地址和寫模式;
->要寫入的存儲(chǔ)區(qū)首地址;
->用頁(yè)寫入方式或字節(jié)寫入方式寫入數(shù)據(jù);
3、 讀:
檢測(cè)SDA是否空閑;
->按I2C協(xié)議發(fā)出起始訊號(hào);
->發(fā)出7位器件地址和寫模式(偽寫);
->發(fā)出要讀取的存儲(chǔ)區(qū)首地址;
->重發(fā)起始訊號(hào);
->發(fā)出7位器件地址和讀模式;
->接收數(shù)據(jù);