IIC匯流排是飛利浦公司研發的兩線制序列通訊匯流排,IIC兩線制包括:序列時鐘線(SCL)和序列傳輸線(SDA)。序列時鐘線(SCL)只能由主器件控制,序列傳輸線(SDA)實現雙向資料傳輸(IIC通訊屬於同步、半雙工序列通訊)。IIC匯流排遵從主/從結構,可以實現一個主器件和多個從器件之間的通訊,並且從器件永遠不會主動給主器件傳送資料。器件傳送資料到匯流排上,則定義為傳送器,器件從匯流排上讀取資料,則定義為接收器(主器件和從器件都可以是傳送器也可以是接收器)誰接收誰應答。
上拉電阻作用:確保匯流排空閒時為高電平
通過器件地址建立通訊。器件地址:固定地址(4)+ 可程式化地址(3)+ 讀寫為(0讀1寫)
IIC裝置地址是一個7位地址,並且這個7位地址分成兩部分,分別是固定地址(器件地址)和可程式化地址(晶片管腳地址)。 4+3
IIC匯流排資料傳輸速度在標準模式下可達100Kbit/S,快速模式下可達400Kbit/S以及高速模式下可達3.4Mbit/S。
注意:必須器件內部自帶上拉電阻 或者外界接上拉電阻 或者軟體設定上拉電阻
硬體IIC:會自動設定為開漏輸出,(不推薦不穩定)
軟體IIC:
推輓輸出:輸出0,N-MOS啟用。 輸出1,P-MOS啟用
開漏輸出(不帶上拉電阻):輸出0,N-MOS啟用。 輸出1,P-MOS不會啟用,不會輸出高電平
開漏輸出(帶上拉電阻):輸出0,N-MOS啟用。 輸出1,P-MOS啟用
簡言之:開漏輸出必須有上拉電阻才能輸出高電平。目前微控制器GPIO口可以通過軟體設定設定上下拉
開漏輸出的作用:
IIC之所以分成三種模式,是由於SCL與SDA保持時間長短不同所決定的。例如:標準模式下要求SCL高電平保持時間最小為4.7us,快速模式下要求SCL高電平保持時間最小為0.7us. 這也是為什麼高速率可以相容低速率,而低速率不能相容高速率的原因。
標準/S | 快速/F | 高速/HSE | |
速率 | 100KHZ | 400KHZ | 3.4MHZ |
例如:資料保持時間(為SCL低電 平時資料允許儲存最長時間)
| 無 | 0.9us | 72或150ns |
器件定址 | 7位(128個器件) | 7位或10位(1024個器件) | 7位或10位(1024個器件) |
優化功能 | 快速模式器件的輸入有抑制毛刺的功能 | Hs 模式器件的輸出可以抑制毛刺 |
更多區別請檢視IIC協定規範
以軟體模擬推輓輸出例100K時序為例
SCL在高電平期間,SDA出現一個由高到低的跳變(SDA,SCL有最小保持時間 )
void IIC_Start(void)
{
SDA_OUT();
SDA_H; //序列傳輸線高電平(空閒訊號)
CLK_H; //序列時鐘線高電平(空閒訊號)
Delay_us(5);
SDA_L; //序列傳輸線拉出下降沿
Delay_us(5);
CLK_L; //序列時鐘線拉出下降沿
}
SCL在高電平期間,SDA出現由低變高的跳變(SDA,SCL有最小保持時間 )
void IIC_Stop(void)
{
SDA_OUT(); //輸出模式
CLK_L; //序列時鐘線低電平
SDA_L; //序列傳輸線低電平
CLK_H; //序列時鐘線高電平
Delay_us(5);
SDA_H; //序列傳輸線高電平 上升沿
Delay_us(5);
}
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; //序列時鐘線線低電平
}
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;
}
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;
}
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);
}
}
將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;
}