1. 程式人生 > >I2C通信基本原理及其實現

I2C通信基本原理及其實現

false 波形 如何 tps function del 數據通信 aaa char

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

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

技術分享圖片

因為,通信之前,主設備需要發送一個起始信號,所以,先講一下起始信號。通過上面的圖就可以知道(上圖中的第一個波形圖是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();		
}

技術分享圖片

接下來就是該講一下,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的低層時序到這裏基本上就已經結束了。

I2C通信基本原理及其實現