|
網上轉載的IIC總線筆記,歡迎大家共師兄習
人與人之間能進行交流是因為有語言這個工具。電子芯片之間的交流也需要一個工具,IIC總線就是這個工具,通過IIC總線,芯片之間能進行信息交流。但是,交流并不是那么簡單的,交流的雙方必須有共同語言,就像我們和外國人交流的時候就要用外語,而不能用國語,否則無法交流。芯片通過IIC總線進行交流。
什么是IIC總線?
IIC總線由一條SDA數據線和一條SCL時鐘線組成,在這兩條線上可以掛載多個IIC設備,每個IIC設備都有自己的地址,這些地址由硬件的出廠固定地址位和可編程地址位組成,只有在兩條線上傳輸的值是IIC設備的地址時,這個IIC設備才會作出響應。就像師傅上課提問學生一樣,只有學生被叫到自己的名字才會站起來回答問題。
IIC作為電子芯片之間的交流語言,它也有一些語法------IIC通訊協議。
當SCL時鐘線為高電平的時候,如果SDA線由高電平跳到低電平,說明師傅準備提問學生了,即IIC主機準備尋找從機。
這個過程轉換為C語言就是
void IIC_Start(void)
{
SDA_OUT(); //sda線設置為輸出模式
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0; // SDA由高跳到低
delay_us(4);
IIC_SCL=0;//鉗住I2C總線,準備發送或接收數據
}
我們把這個過程稱為IIC的起始信號。
注意:上面的delay延時函數不是固定的,要根據硬件設備的固定時序來設置。就像有些學生反應比較快,有些學生反應比較慢,師傅不能要求每個學生反應時間都一樣。所以主機呼叫從機要根據從機的反應速度來設定等待時間。這個延時十分重要!延時長一點和短一點都無法得到正確的數據。
做事要有始有終,師傅提問完學生當然要請學生坐下啦,IIC用完從機,當然也要把從機釋放了。
這個過程就是主機發出一個終止信號:SCL為高時,SDA由低電平跳到高電平
void IIC_Stop(void)
{
SDA_OUT();//sda線輸出
IIC_SCL=0;
IIC_SDA=0;//SDA由低跳到高
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//發送I2C總線結束信號
delay_us(4);
}
終止信號完了之后,IIC處于閑置狀態,主機可以呼叫其他設備了,(提問完一個學生,師傅又可以去提問另一個學生了!)
俗話說:一個巴掌拍不響。師傅叫學生起來回答問題,如果學生不樂意當然也就不鳥師傅了。當主機呼叫從機時,從機可以應答也可以不應答。即當SCL為高電平的時候,SDA為低電平表明從機應答,否則表明從機不應答。
void IIC_Ack(void)
{
IIC_SCL=0; //首先拉低SCL,防止產生起始或結束信號
SDA_OUT();
IIC_SDA=0; //低電平代表應答
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
}
Ack即從機應答。
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1; //高電平代表不應答
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
}
NAck即是No Ack ,從機不應答。
等待應答也是一個過程:
u8IIC_Wait_Ack(void)
{
u8ucErrTime=0;
SDA_IN(); //SDA設置為輸入模式
IIC_SDA=1;
delay_us(4);
IIC_SCL=1;
delay_us(4);
while(READ_SDA) //SDA為高即未應答
{
ucErrTime++;
if(ucErrTime>250) //等待一段時間還沒應答則發送停止信號
{
IIC_Stop();
return1;
}
}
IIC_SCL=0;//時鐘線輸出0
return0;
}
有了上面的基本信號,主從機可以進行交流了。
voidIIC_Send_Byte(u8 txd) //發送一個字節的數據
{
u8t;
SDA_OUT();
IIC_SCL=0;//拉低時鐘線開始數據傳輸
for(t=0;t<8;t++)
{
if(txd&0x80) // 因為先發的是最高位
IIC_SDA=1; //如果剛剛的位是1則證明SDA為高,所以置1
else
IIC_SDA=0; //你懂的
txd <<=1; //為讀下一位作準備
delay_us(4);
IIC_SCL=1; //時鐘線高的時候,數據保持穩定,保證正確讀取
delay_us(4);
IIC_SCL=0; //時鐘線拉低,允許讀下一位
delay_us(4);
}
}
為什么要先把SCL設置為低電平?其實上面已經有提示,因為在SCL為高電平的時候,SDA的變化代表著起始或者終止信號,所以在SCL為低的時候,才允許SDA變化(這些變化代表數據)。
另外因為一個字節(8位)的數據是按照一位一位來傳送的,協議規定先傳送最高位,所以txd與上0x80,判斷最高位什么電平,然后txd自身左移一位,即第6位變第7位...以此類推,循環8次,則0~7號位上的數據完成了傳送。
師傅可以提問學生,學生也可以提問師傅。同樣,主機可以向從機發數據,從機也可以向主機發數據(或主機讀取從機數據)
u8 IIC_Read_Byte() //因為接收從最高位開始,所以下面進行左移操作的。
{
u8i,receive=0;
SDA_IN(); //SDA設置為輸入
for(i= 0;i < 8;i++ ) //一個字節需要一位一位地讀出來,所以要循環8次
{
IIC_SCL= 0;
delay_us(4);
IIC_SCL= 1;
receive<<= 1; //左移一位
if(READ_SDA) //當SDA是1的時候讀入1否則直接補零
receive|= 0x01;
delay_us(1);
}
IIC_Ack();//發送ACK ,表示讀完數據且應答了
returnreceive;
}
這里的READ_SDA是SDA線的引腳狀態號。
以上就是IIC的基本“語法”了。
再來一個實際應用:
/************************************************/
/* 向從機寫數據 */
/************************************************/
//“1”代表主機讀取數據,“0”代表主機發送數據
void Single_Write(u8 SlaveAddress,u8 REG_Address,u8REG_Data)
{
IIC_Start(); //開始信號
IIC_Send_Byte(SlaveAddress); //發送設備地址+寫信號
IIC_Wait_Ack(); //等待應答
IIC_Send_Byte(REG_Address); //發送設備寄存器地址
IIC_Wait_Ack(); //等待應答
IIC_Send_Byte(REG_Data); //寫數據
IIC_Wait_Ack(); //等待應答
IIC_Stop(); //停止信號
delay_ms(5);
}
/************************************************/
/* 讀取從機的數據 */
/************************************************/
u8 Single_Read(u8 SlaveAddress,u8 REG_Address)
{
u8 REG_Data;
IIC_Start(); //開始信號
IIC_Send_Byte(SlaveAddress); //發送設備地址+寫信號
IIC_Wait_Ack(); //等待應答
IIC_Send_Byte(REG_Address); //發送設備寄存器地址
IIC_Wait_Ack(); //等待應答
IIC_Start(); //再次開始信號
IIC_Send_Byte(SlaveAddress+ 1); //發送設備地址+讀信號
IIC_Wait_Ack(); //等待應答
REG_Data =IIC_Read_Byte(); //獲取數據
IIC_NAck(); //不再應答
IIC_Stop(); //停止信號
delay_ms(5);
returnREG_Data;
}
注意:在同一IIC總線上可以掛載的同一IIC設備最大數量是2^(可編程位數),如果可編程位數是3,那么可以掛載這種IIC設備的最大數量就是8個。
|
-
-
IIC總線筆記.pdf
2020-4-7 11:29 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
1.89 MB, 下載次數: 8, 下載積分: 黑幣 -5
|