(1)概述 I2C(Inter-Integrated Circuit BUS) 集成電路總線,該總線由NXP(原PHILIPS)公司設計,多用于主控制器和從器件間的主從通信,在小數(shù)據(jù)量場合使用,傳輸距離短,任意時刻只能有一個主機等特性。 經(jīng)常IIC和SPI接口被認為指定是一種硬件設備,但其實這樣的說法是不盡準確的,嚴格的說他們都是人們所定義的軟硬結(jié)合體,分為物理層(四線結(jié)構(gòu))和協(xié)議層(主機,從機,時鐘極性,時鐘相位)。 IIC,SPI的區(qū)別不僅在與物理層,IIC比SPI有著一套更為復雜的協(xié)議層定義。下面來分別說明一下IIC的物理層和協(xié)議層。 (2)IIC的物理層 a.只要求兩條總線線路,一條是串行數(shù)據(jù)線SDA,一條是串行時鐘線SCL。(IIC是半雙工,而不是全雙工)。 b.每個連接到總線的器件都可以通過唯一的地址和其它器件通信,主機/從機角色和地址可配置,主機可以作為主機發(fā)送器和主機接收器。 c.IIC是真正的多主機總線,(而這個SPI在每次通信前都需要把主機定死,而IIC可以在通訊過程中,改變主機),如果兩個或更多的主機同時請求總線,可以通過沖突檢測和仲裁防止總線數(shù)據(jù)被破壞。 d.傳輸速率在標準模式下可以達到100kb/s,快速模式下可以達到400kb/s。 e.連接到總線的IC數(shù)量只是受到總線的最大負載電容400pf限制。 一個典型的IIC接口如下圖(1)所示 圖(1) (3)IIC的協(xié)議層 IIC的協(xié)議層才是掌握IIC的關鍵。現(xiàn)在簡單概括如下: a.數(shù)據(jù)的有效性 在時鐘的高電平周期內(nèi),SDA線上的數(shù)據(jù)必須保持穩(wěn)定,數(shù)據(jù)線僅可以在時鐘SCL為低電平時改變。 如圖(2)所示: 圖(2) b.起始和結(jié)束條件 起始條件:當SCL為高電平的時候,SDA線上由高到低的跳變被定義為起始條件,結(jié)束條件:當SCL為高電平的時候,SDA線上由低到高的跳變被定義為停止條件,要注意起始和終止信號都是由主機發(fā)出的,連接到I2C總線上的器件,若具有I2C總線的硬件接口,則很容易檢測到起始和終止信號。總線在起始條件之后,視為忙狀態(tài),在停止條件之后被視為空閑狀態(tài),對起始條件和結(jié)束條件的描述如下圖(3)所示。 圖(3) c.應答 每當主機向從機發(fā)送完一個字節(jié)的數(shù)據(jù),主機總是需要等待從機給出一個應答信號,以確認從機是否成功接收到了數(shù)據(jù),從機應答主機所需要的時鐘仍是主機提供的,應答出現(xiàn)在每一次主機完成8個數(shù)據(jù)位傳輸后緊跟著的時鐘周期,低電平0表示應答,1表示非應答,如圖(4)所示。 圖(4) d.數(shù)據(jù)幀格式
I2C總線上傳送的數(shù)據(jù)信號是廣義的,既包括地址信號,又包括真正的數(shù)據(jù)信號。
在起始信號后必須傳送一個從機的地址(7位),第8位是數(shù)據(jù)的傳送方向位(R/T),用“0”表示主機發(fā)送數(shù)據(jù)(T),“1”表示主機接收數(shù)據(jù)(R)。{這里小編在驅(qū)動MPU6050模塊的時候,就犯過這樣的錯誤,它寫的MPU6050從機地址是0x68,因為發(fā)送從機地址的時候,要加一位讀寫方向位,因為剛開始應該是向這個MPU6050里寫從機里某個寄存器的地址,所以應該是7位地址
0x68(1101000)+二進制位0=11010000)也就是0xD0,表示要向該IIC設備里寫東西,然后再緊接著寫入IIC設備里的寄存器地址,而我直接寫入了0x68,導致出錯},每次數(shù)據(jù)傳送總是由主機產(chǎn)生的終止信號結(jié)束。但是,若主機希望繼續(xù)占用總線進行新的數(shù)據(jù)傳送,則可以不產(chǎn)生終止信號,馬上再次發(fā)出起始信號對另一從機進行尋址。
在總線的一次數(shù)據(jù)傳輸過程中,可以有以下幾種組合方式:
[1]
主機向從機發(fā)送數(shù)據(jù),數(shù)據(jù)傳送方向在整個傳送過程中不變:
注:有陰影部分表示數(shù)據(jù)由主機向從機傳送,無陰影部分則表示數(shù)據(jù)由從機向主機傳送。
A表示應答(低電平), A非表示非應答(高電平)。S表示起始信號,P表示終止信號。
[2]主機在第一個字節(jié)后,立即從從機讀數(shù)據(jù):
[3]在傳送過程中,當需要改變傳送方向時,起始信號和從機地址都被重復產(chǎn)生一次,但兩次讀/寫方向位正好反相:
發(fā)送起始信號
等待從機應答
寫一個從機地址+0(表示寫),
等待從機應答
發(fā)送一個字節(jié)的MPU6050加速度存儲寄存器地址,
等待從機應答
再發(fā)送一次起始信號
等待從機應答
寫一個從機地址+1(表示讀)
等待從機應答
讀取MPU6050傳感器數(shù)據(jù)
主機非應答
e.IIC信號的模擬
主機可以采用不帶I2C總線接口的單片機,如80C51、AT89C2051等單片機,利用軟件實現(xiàn)I2C總線的數(shù)據(jù)傳送,即軟件與硬件結(jié)合的信號模擬。即使是含有IIC硬件的單片機(如stm32 103系列)也有一定的缺陷,所以一般也會模擬IIC的時序?,F(xiàn)將具體時間截圖如下:
具體的程序代碼如下:
void I2C_Start(void) { I2C_SDA_OUT();//配置一下引腳,引腳設置為輸出 I2C_SDA_H;//把數(shù)據(jù)線拉高 I2C_SCL_H;//把時鐘線拉高 delay_us(5);//延時5微秒,要求大于4.7微秒 I2C_SDA_L; //拉低,產(chǎn)生下降沿 delay_us(6);//這個過程大于4微秒 I2C_SCL_L;//最后一定要把這個時鐘線拉低,因為只有時鐘線拉低的時候才允許數(shù)據(jù)變化。 } //產(chǎn)生停止信號
void I2C_Stop(void) { I2C_SDA_OUT(); I2C_SCL_L; I2C_SDA_L; I2C_SCL_H; delay_us(6); I2C_SDA_H; delay_us(6); } //主機產(chǎn)生應答信號ACK
void I2C_Ack(void) { I2C_SCL_L; I2C_SDA_OUT(); I2C_SDA_L; delay_us(2); I2C_SCL_H; delay_us(5); I2C_SCL_L; } //主機不產(chǎn)生應答信號NACK void I2C_NAck(void) { I2C_SCL_L; I2C_SDA_OUT(); I2C_SDA_H; delay_us(2); I2C_SCL_H; delay_us(5); I2C_SCL_L; } //等待從機應答信號,我們只負責主機應答信號的產(chǎn)生,從機應答信號
//我們不控制。 //返回值:1 接收應答失敗 // 0 接收應答成功 u8 I2C_Wait_Ack(void) { u8 tempTime=0; I2C_SDA_IN(); //配置為上拉輸入。 I2C_SDA_H; //主機釋放數(shù)據(jù)總線,等待從機產(chǎn)生應答信號 delay_us(1); I2C_SCL_H; delay_us(1); //等待從機對數(shù)據(jù)總線的操作。低電平代表應答 while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)) { tempTime++; //這個屬于軟件延時,不一定準確。 if(tempTime>250) //如果時間超時,沒有應答就停止。 { I2C_Stop(); return 1; //沒有響應的話返回1. } } I2C_SCL_L; return 0; //如果有響應的話就返回0. }
|
|