I2C通信基本原理及其實現

   I2C是一種總線式結構,它只需要SCL時鐘信號線與SDA數據線,兩根線就能將連接與總線上的設備實現數據通信,由於它的簡便的構造設計,於是成爲一種較爲常用的通信方式。

   由於I2C採用的是主從式通信方式,所以,通信的過程完全由主設備仲裁在通信之前,必須由主設備發送一個起始信號,決定數據是否可以開始傳送,並且在結束通信時,必須再由主設備發送一個結束信號,以表示通信已經結束。

wKiom1mzRHfyBubFAAA9DU6GOIQ092.jpg-wh_50

   因爲,通信之前,主設備需要發送一個起始信號,所以,先講一下起始信號。通過上面的圖就可以知道(上圖中的第一個波形圖是SDA數據線,第二個波形圖是SCL時鐘信號線),起始信號是在SCL時鐘信號線處於高電平時,SDA數據線由高電平轉換爲低電平,也就是產生一個下降沿,就意味着起始信號已經發送,數據的通信可以進行了。代碼如下:

void I2C_Start()
{
	I2C_SDA = 1;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立時間是I2C_SDA保持時間>4.7us
	I2C_SDA = 0;
	I2C_Delay10us();//保持時間是>4us
	I2C_SCL = 0;			
	I2C_Delay10us();		
}

   同樣的,由上圖可知:結束信號,就是在SCL時鐘信號線處於高電平時,SDA數據線由低電平變爲高電平 ,也就是,SDA數據線產生一個 上升沿。代碼如下:

void I2C_Stop()
{
	I2C_SDA = 0;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立時間大於4.7us
	I2C_SDA = 1;
	I2C_Delay10us();		
}

wKioL1mzR2qyjxokAABQRuG-DxY425.png-wh_50  

   接下來就是該講一下,I2C數據的發送問題了。由於I2C是主從式通信,也就意味着一根總線上可以掛載多個從設備,那麼主設備如何區分這些從設備呢?主設備如何知道是在與哪一個從設備在通信呢?答案是:通過地址。每一個從設備都有自己的地址編碼,也就是說,主設備在與具體的某一個從設備通信之前,必須先發送地址,以表示與主設備通信的是該設備。從上圖可知,主設備在發送完起始信號後,立刻開始了發送從設備的地址。那麼如何發送數據地址呢?首先,在SCL時鐘信號線處於低電平時,SDA數據線上的地址信息要開始準備了。I2C通信一個必須注意的點就是,在傳送地址信息是,都是從高位開始傳送,

	I2C_SDA = dat >> 7;
	dat = dat << 1;

接着,SCL時鐘信號線開始由低電平向高電平轉換,這個時候,SDA數據線上的數據開始在傳送了,當SCL時鐘信號線上的信號再由高電平轉換位低電平的時候,一個Bit位的數據已經傳送完畢。在地址信息傳送完畢之後,還會有一個應答信號,因爲,爲了確保從設備接收到已經發送的數據,從設備就會向主設備發送一個應答信號,若主設備接收到應答信號則說明數據傳送成功,否則數據傳送失敗。很重要的一點是,總線一直是由主設備控制,那麼當從設備想要向主設備發送一個應答信號時,這設備需要是釋放總線,將總線權限交給從設備。

所以,從設備在向主設備發送應答信號時,主設備應該釋放總線,代碼如下:

        I2C_SDA = 1;

接着,由上圖可知,當SCL時鐘信號線再次拉高時,就進入了第9個時鐘週期,也就是此時開始傳送應答信號。當成功應答時,返回1,否則返回0。完整代碼如下:

	I2C_SDA = 1;     
	I2C_Delay10us();
	I2C_SCL = 1;        
	
	while(I2C_SDA && (ack == 1))
	{
		b++;
		if(b > 200)	
		{
			I2C_SCL = 0;
			I2C_Delay10us();
			return 0;
		}
	}

	I2C_SCL = 0;
	I2C_Delay10us();
 	return 1;		
}

最後,就是I2C設備(也就是主設備)數據的接收。此時,從設備發送數據給主設備,也就是,主設備進行數據的接收。那麼,主設備同樣要釋放總線權限。也就是

        I2C_SDA = 1;

首先,SCL時鐘信號線爲低電平,這時,SDA數據線要準備好數據了,接着,SCL時鐘信號線由低電平變爲高電平,此時,數據傳送開始了,當SCL時鐘信號線再次變爲低電平是,一個Bit的數據傳送結束。代碼如下:

uchar I2C_ReadByte()
{
	uchar a = 0,dat = 0;
	I2C_SDA = 1;			
	                        
	I2C_Delay10us();
	//I2C_SCL = 0;
	for(a=0; a<8; a++)
	{
		I2C_SCL = 1;       
		I2C_Delay10us();
		dat <<= 1;
		dat |= I2C_SDA;
		I2C_Delay10us();
		I2C_SCL = 0;
		I2C_Delay10us();
	}
	return dat;		
}

I2C的低層時序到這裏基本上就已經結束了。


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                                                                                                  歡迎打賞,哈哈~

支付寶.jpg

                                                                                1毛兩毛也表示萬分感謝,哈哈!

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------                                                                                 順便附上我的微信碼,哈哈!

微信.png







                                                                                一定是我膨脹了,竟然想要打賞!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章