STM32----IIC詳解

2021-04-27 05:00:02

一.IIC簡介

1.IIC匯流排概述

IIC匯流排是飛利浦公司研發的兩線制序列通訊匯流排,IIC兩線制包括:序列時鐘線(SCL)和序列傳輸線(SDA)。序列時鐘線(SCL)只能由主器件控制,序列傳輸線(SDA)實現雙向資料傳輸(IIC通訊屬於同步、半雙工序列通訊)。IIC匯流排遵從主/從結構,可以實現一個主器件和多個從器件之間的通訊,並且從器件永遠不會主動給主器件傳送資料。器件傳送資料到匯流排上,則定義為傳送器,器件從匯流排上讀取資料,則定義為接收器(主器件和從器件都可以是傳送器也可以是接收器)誰接收誰應答。

2.IIC匯流排物理結構

上拉電阻作用:確保匯流排空閒時為高電平

3.IIC匯流排通訊方式

通過器件地址建立通訊。器件地址:固定地址(4)+ 可程式化地址(3)+ 讀寫為(0讀1寫)

IIC裝置地址是一個7位地址,並且這個7位地址分成兩部分,分別是固定地址(器件地址)和可程式化地址(晶片管腳地址)。 4+3

  • 固定地址:IIC器件在生產時,晶片廠家已經固化在晶片內部的地址,使用者不可更改。
  • 可程式化地址:由IIC器件地址管腳上的電平狀態決定。地址管腳接電源則表示數位「1」,地址管腳接地則表示數位「0」。(可以根據器件說明修改地址 例如:邁萊芯MLX90640修改裝置地址方法,I2C掛載多個MLX90640
  • 最低位為控制位元組,控制讀寫方向(指主機的讀寫方向)。

IIC匯流排資料傳輸速度在標準模式下可達100Kbit/S,快速模式下可達400Kbit/S以及高速模式下可達3.4Mbit/S。

 

4.IIC模式設定

1)引腳設定

 

  • SCL,SDA可以設定成推輓輸出、開漏輸出(上拉電阻輸出1)
  • SCL,SDA也可以設定成開漏輸出、開漏輸出(開漏輸出為防止多個器件存在短路)  

                注意:必須器件內部自帶上拉電阻      或者外界接上拉電阻   或者軟體設定上拉電阻

  • SCL,SDA也可以設定成推輓輸出、推輓輸出與浮空輸入(通過切換模式)

2)開漏輸出和線與

硬體IIC:會自動設定為開漏輸出,(不推薦不穩定)

軟體IIC

推輓輸出:輸出0,N-MOS啟用。 輸出1,P-MOS啟用

開漏輸出(不帶上拉電阻):輸出0,N-MOS啟用。   輸出1,P-MOS不會啟用,不會輸出高電平

開漏輸出(帶上拉電阻):輸出0,N-MOS啟用。   輸出1,P-MOS啟用

簡言之:開漏輸出必須有上拉電阻才能輸出高電平。目前微控制器GPIO口可以通過軟體設定設定上下拉

開漏輸出的作用:

  1. 防止短路: 在一些情況下(比如匯流排), 多個GPIO口可能會連線在同一根線上, 存在某個GPIO輸出高電平, 另一個GPIO輸出低電平的情況. 如果使用推輓輸出, 你會發現這個GPIO的VCC和另一個GPIO的GND接在了一起, 也就是短路了(涼涼了). 如果換成開漏輸出呢? VCC和GND多了個電阻, 這樣電路就是安全的.所以匯流排一般會使用開漏輸出.
  2. 實現線與,減少一個與門,簡化邏輯。同時當多個器件通訊的時候,因為線與. 如果主裝置A拉高SDA時, 已經有其他主裝置將SDA拉低了. 由於 1 & 0 = 0 那麼主裝置A在檢查SDA電平時, 會發現不是高電平, 而是低電平. 說明其他主裝置搶佔匯流排的時間比它早, 主裝置A只能放棄佔用匯流排. 如果是高電平, 則可以佔用.(SDA為高電平的時候才可以與器件進行通信,)

二.三種模式區別

IIC之所以分成三種模式,是由於SCL與SDA保持時間長短不同所決定的。例如:標準模式下要求SCL高電平保持時間最小為4.7us,快速模式下要求SCL高電平保持時間最小為0.7us. 這也是為什麼高速率可以相容低速率,而低速率不能相容高速率的原因。

 標準/S快速/F高速/HSE
速率100KHZ400KHZ3.4MHZ

例如:資料保持時間(為SCL低電

平時資料允許儲存最長時間)

 

0.9us72或150ns
器件定址7位(128個器件)7位或10位(1024個器件)7位或10位(1024個器件)
優化功能 快速模式器件的輸入有抑制毛刺的功能
 
Hs 模式器件的輸出可以抑制毛刺
 

 

更多區別請檢視IIC協定規範

三.時序分析

以軟體模擬推輓輸出例100K時序為例

1)起始訊號

SCL在高電平期間,SDA出現一個由高到低的跳變(SDA,SCL有最小保持時間 )

void IIC_Start(void)
{
	SDA_OUT();
	SDA_H;   							//序列傳輸線高電平(空閒訊號)
	CLK_H;   							//序列時鐘線高電平(空閒訊號)
	Delay_us(5);
	SDA_L;   							//序列傳輸線拉出下降沿
	Delay_us(5);
	CLK_L;   							//序列時鐘線拉出下降沿
}

2)終止訊號

SCL在高電平期間,SDA出現由低變高的跳變(SDA,SCL有最小保持時間 )

void IIC_Stop(void)
{
	SDA_OUT();					//輸出模式
	CLK_L;							//序列時鐘線低電平
	SDA_L;							//序列傳輸線低電平
	CLK_H;							//序列時鐘線高電平
	Delay_us(5);
	SDA_H;							//序列傳輸線高電平  上升沿
	Delay_us(5);

}

 

3)應答訊號

SCL在高電平期間SDA始終處於低電平(SCL保持時間<= SDA保持時間)

需要在傳輸完畢一個位元組後傳送

void IIC_Send_ACK(void)
{
	
	CLK_L;
	SDA_OUT();			   				//輸出模式
	SDA_L;										//序列傳輸線低電平
	Delay_us(5);
	CLK_H;										//序列時鐘線線高電平    上下
	Delay_us(5);
	CLK_L;										//序列時鐘線線低電平
}

4)非應答訊號

SCL在高電平期間SDA始終處於高電平(SCL保持時間<= SDA保持時間)

需要在傳輸完畢一個位元組後傳送

void IIC_Send_NoACK(void)
{
	
	CLK_L;
	SDA_OUT(); 
	SDA_H;											//序列傳輸線為高電平
	Delay_us(5);
	CLK_H;
	Delay_us(5);
	CLK_L;
}

5)檢測應答

SCL為高電平的時候可以讀取SDA的狀態,因此可以將SDA模式切換為輸入模式,讀取SDA引腳狀態,0位應答,1位非應答

SCL為低電平允許資料發生變化

SDA:為高電平的時候可以佔用匯流排,此時將SDA拉低,開始通訊。當為低電平的時候,SDA已經被佔用。
SCL: SCL為高電平的時候要求資料穩定  SCL為低電平的時候允許資料改變

u8 IIC_Get_ACK(void)
{
	u8 ERRTIME = 0;    //超時變數
	SDA_IN();
	//SDA_L;// 沒有影響
	Delay_us(5);
	CLK_H;
	Delay_us(5);
	while( READ_SDA() )
	{
		ERRTIME++;
		if(ERRTIME >=250)
		{
			IIC_Stop();
			return 1;
		}
	}
	CLK_L;
	return 0;
}

 

6)傳送資料

void IIC_Send_Data(u8 dat)
{
	u8 i;
	SDA_OUT();
	CLK_L;
	for(i = 0; i < 8; i++)					//分8次傳輸資料  一位一位傳遞  序列
	{
		if(dat & 0x80)								//先發最高位  1000 0000
		{
			SDA_H;     //寫1
		}
		else
		{
			SDA_L;     //寫0
		}
		dat <<= 1;									//左移操作  次高位-->最高位
		Delay_us(5);
		CLK_H;
		Delay_us(5);
		CLK_L;
		Delay_us(5);	
	}
}

7)接收資料

將SDA切換為輸入模式。拉高SCK電平,可以讀取資料

u8 IIC_Read_Data(u8 ack)
{
	unsigned char i,date = 0;
	SDA_IN();
	for(i = 0; i < 8; i++)
	{
		
		CLK_L;
		Delay_us(5);
		CLK_H;
		date <<= 1;
		Delay_us(5);
		if( READ_SDA() )
		{
			date ++;
		}
		//Delay_us(2);
	}
	if(ack)
	{
		IIC_Send_ACK();																	//傳送應答
	}
	else
	{
		IIC_Send_NoACK();																	//傳送非應答
	}
	return date;

}