一. IIC的基本介紹
1.1IIC的簡(jiǎn)介
IIC是雙線(不算地線)半雙工的一種通訊方式(可以雙向通訊,但不可以在同一時(shí)間雙向數(shù)據(jù)傳輸).
IIC串行總線一般有兩根信號(hào)線,一根是雙向的數(shù)據(jù)線SDA,另一根是時(shí)鐘線SCL,其時(shí)鐘信號(hào)是由主控器件產(chǎn)生。所有接到IIC總線設(shè)備上的串行數(shù)據(jù)SDA都接到總線的SDA上,各設(shè)備的時(shí)鐘線SCL接到總線的SCL上。對(duì)于并聯(lián)在一條總線上的每個(gè)IC都有唯一的地址。


1.2地址問題
IIC設(shè)備地址
協(xié)議格式中第一個(gè)字節(jié)(為slave address)由7位地址和一位R/W讀寫位組成的,這字節(jié)是個(gè)器件地址。
常用IIC接口通用器件的器件地址是由種類型號(hào),及尋址碼組成的,共7位。
如格式如下:
D7 D6 D5 D4 D3 D2 D1 D0
(1)、器件類型:D7-D4共4位決定的。這是由半導(dǎo)公司生產(chǎn)時(shí)就已固定此類型的了,也就是說這4位已是固定的。
(2)、用戶自定義地址碼:D3-D1共3位。這是由用戶自己設(shè)置的,通常的作法如EEPROM這些器件是由外部IC的3個(gè)引腳所組合電平?jīng)Q定的(用常用的名字如A0,A1,A2)。這也就是尋址碼。所以為什么同一IIC總線上同一型號(hào)的IC只能最多共掛8片同種類芯片的原因了。
(3)、最低一位就是R/W位,,“0”表示寫,“1”表示讀(通常讀寫信號(hào)中寫上面有一橫線,表示低電平)。所以IIC設(shè)備通常有兩個(gè)地址,即讀地址和寫地址。
IIC 設(shè)備的7 位地址是就當(dāng)前IIC總線而言的,是“相對(duì)地址”。不同的IIC總線上的設(shè)備可以使用相同的7 位地址,但是它們所在的i2c 總線不同。所以在系統(tǒng)中一個(gè)IIC設(shè)備的“絕對(duì)地址”由二元組(IIC適配器的ID 和設(shè)備在該總線上的7 位地址)表示。”,所以這個(gè)函數(shù)的作用主要是排除同一IIC總線上出現(xiàn)多個(gè)地址相同的設(shè)備。
1.3 IIC協(xié)議
IIC總線在傳輸數(shù)據(jù)的過程中一共有三種類型信號(hào),分別為:開始信號(hào)、結(jié)束信號(hào)和應(yīng)答信號(hào)。這些信號(hào)中,起始信號(hào)是必需的,結(jié)束信號(hào)和應(yīng)答信號(hào),都可以不要。同時(shí)我們還要介紹其空閑狀態(tài)、數(shù)據(jù)的有效性、數(shù)據(jù)傳輸。

(1)空閑狀態(tài)
當(dāng)IIC總線的數(shù)據(jù)線SDA和時(shí)鐘線SCL兩條信號(hào)線同時(shí)處于高電平時(shí),規(guī)定為總線的空閑狀態(tài)。此時(shí)各個(gè)器件的輸出級(jí)場(chǎng)效應(yīng)管均處在截止?fàn)顟B(tài),即釋放總線,由兩條信號(hào)線各自的上拉電阻把電平拉高。
(2)起始信號(hào)與停止信號(hào)
起始信號(hào):當(dāng)時(shí)鐘線SCL為高期間,數(shù)據(jù)線SDA由高到低的跳變;啟動(dòng)信號(hào)是一種電平跳變時(shí)序信號(hào),而不是一個(gè)電平信號(hào);
停止信號(hào):當(dāng)時(shí)鐘線SCL為高期間,數(shù)據(jù)線SDA由低到高的跳變;停止信號(hào)也是一種電平跳變時(shí)序信號(hào),而不是一個(gè)電平信號(hào)。

(3) 應(yīng)答信號(hào)
發(fā)送器每發(fā)送一個(gè)字節(jié)(8個(gè)bit),就在時(shí)鐘脈沖9期間釋放數(shù)據(jù)線,由接收器反饋一個(gè)應(yīng)答信號(hào)。
應(yīng)答信號(hào)為低電平時(shí),規(guī)定為有效應(yīng)答位(ACK,簡(jiǎn)稱應(yīng)答位),表示接收器已經(jīng)成功地接收了該字節(jié);
應(yīng)答信號(hào)為高電平時(shí),規(guī)定為非應(yīng)答位(NACK),一般表示接收器接收該字節(jié)沒有成功。
對(duì)于反饋有效應(yīng)答位ACK的要求是:接收器在第9個(gè)時(shí)鐘脈沖之前的低電平期間將數(shù)據(jù)線SDA拉低,并且確保在該時(shí)鐘的高電平期間為穩(wěn)定的低電平。 如果接收器是主控器,則在它收到最后一個(gè)字節(jié)后,發(fā)送一個(gè)NACK信號(hào),以通知被控發(fā)送器結(jié)束數(shù)據(jù)發(fā)送,并釋放數(shù)據(jù)線SDA,以便主控接收器發(fā)送一個(gè)停止信號(hào)P。

(4)數(shù)據(jù)有效性
IIC總線進(jìn)行數(shù)據(jù)傳送時(shí),時(shí)鐘信號(hào)為高電平期間,數(shù)據(jù)線上的數(shù)據(jù)必須保持穩(wěn)定;只有在時(shí)鐘線上的信號(hào)為低電平期間,數(shù)據(jù)線上的高電平或低電平狀態(tài)才允許變化。即:數(shù)據(jù)在時(shí)鐘線SCL的上升沿到來之前就需準(zhǔn)備好。并在在下降沿到來之前必須穩(wěn)定。

(5)數(shù)據(jù)的傳達(dá)
在IIC總線上傳送的每一位數(shù)據(jù)都有一個(gè)時(shí)鐘脈沖相對(duì)應(yīng)(或同步控制),即在SCL串行時(shí)鐘的配合下,在SDA上逐位地串行傳送每一位數(shù)據(jù)。數(shù)據(jù)位的傳輸是邊沿觸發(fā)。

二.代碼
關(guān)于IIC代碼部分的內(nèi)容這里主要講解HAL塊部分的內(nèi)容。這里HAL初始化的三個(gè)部分包括:引腳配置初始化,寫數(shù)據(jù)函數(shù),讀數(shù)據(jù)函數(shù)。
在引腳配置的 IICInit 中對(duì)IIC的兩個(gè) 引腳(SCL,SDA)進(jìn)行引腳的配置,并對(duì)IIC相關(guān)的庫(kù)函數(shù)進(jìn)行配置,其中引腳的配置這里不再進(jìn)行講解,需要注意的是GPIO的模式要配置成GPIO_MODE_AF_OD 復(fù)用開漏輸出或者GPIO_Mode_Out_PP數(shù)據(jù)寄存器輸出。
關(guān)于IIC的配置,IIC的模式,自身地址,
typedef struct
{
uint32_t I2C_ClockSpeed; /*設(shè)置SCL時(shí)鐘頻,此值不低于40000*/
uint16_t I2C_Mode; /* 指定工作模式,可選I2C模式和SMBUS模式*/
uint16_t I2C_DutyCycle; /*指定時(shí)鐘占空比,可選 low/high=2:1以及16:9模式*/
uint16_t I2C_OwnAddress1; /*指定自身的I2C設(shè)備地址 */
uint16_t I2C_Ack; /*使能或者關(guān)閉響應(yīng) (一般都是使能) */
uint16_t I2C_AcknowledgedAddress; /*指定地址的長(zhǎng)度,可以位7位及10位 */
}I2C_InitTypeDef;
? I2C_ClockSpeed 設(shè)置I2C的傳輸速率,在調(diào)用初始化函數(shù)時(shí),函數(shù)會(huì)根據(jù)我們輸入的數(shù)值經(jīng)過運(yùn)算后把時(shí)鐘因子寫入到I2C的時(shí)鐘控制寄存器CCR。而我們寫入的這個(gè)參數(shù)值不得高于400KHz。實(shí)際上由于CCR寄存器不能寫入小數(shù)類型的時(shí)鐘因子,影響到 SCL的實(shí)際頻率可能會(huì)低于本成員設(shè)置的參數(shù)值,這時(shí)除了通訊稍慢一點(diǎn)以外,不會(huì)對(duì)I2C的標(biāo)準(zhǔn)通訊造成其它影響。
? I2C_Mode 選擇I2C的使用方式,有I2C模式(I2C_Mode_I2C )和SMBus主、從模式(I2C_Mode_SMBusHost、 I2C_Mode_SMBusDevice ) 。 I2C不需要在此處區(qū)分主從模式,直接設(shè)置I2C_Mode_I2C即可。
? I2C_DutyCycle 設(shè)置I 2C的SCL線時(shí)鐘的占空比。該配置有兩個(gè)選擇,分別為低電平時(shí)間比高電平時(shí)間為2:1 ( I2C_DutyCycle_2)和16:9 (I2C_DutyCycle_16_9)。其實(shí)這兩個(gè)模式的比例差別并不大,一般要求都不會(huì)如此嚴(yán)格,這里隨便選就可以了。
? I2C_OwnAddress1 配置STM32的I2C設(shè)備自己的地址,每個(gè)連接到I2C總線上的設(shè)備都要有一個(gè)自己的地址,作為主機(jī)也不例外。地址可設(shè)置為7位或10位(受下面 I2C_AcknowledgeAddress成員決定),只要該地址是I2C總線上唯一的即可。 STM32的I2C外設(shè)可同時(shí)使用兩個(gè)地址,即同時(shí)對(duì)兩個(gè)地址作出響應(yīng),這個(gè)結(jié)構(gòu)成員I2C_OwnAddress1配置的是默認(rèn)的、OAR1寄存器存儲(chǔ)的地址,若需要設(shè)置第二個(gè)地址寄存器OAR2,可使用 I2C_OwnAddress2Config函數(shù)來配置,OAR2不支持10位地址。
? I2C_Ack_Enable 配置I 2C應(yīng)答是否使能,設(shè)置為使能則可以發(fā)送響應(yīng)信號(hào)。一般配置為允許應(yīng)答(I2C_Ack_Enable),這是絕大多數(shù)遵循I 2C標(biāo)準(zhǔn)的設(shè)備的通訊要求,改為禁止應(yīng)答(I2C_Ack_Disable)往往會(huì)導(dǎo)致通訊錯(cuò)誤。
? I2C_AcknowledgeAddress 選擇I2C的尋址模式是7位還是10位地址。這需要根據(jù)實(shí)際連接到I2C總線上設(shè)備的地址進(jìn)行選擇,這個(gè)成員的配置也影響到 I2C_OwnAddress1成員,只有這里設(shè)置成10位模式時(shí), I2C_OwnAddress1才支持10位地址。
利用庫(kù)函數(shù)版本編寫HAL代碼部分如下:
void IICInit(void)
{
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
/* 配置硬件IIC需要的變量 */
I2C_InitTypeDef I2C_InitStructure;
/* 使能與 I2C1 有關(guān)的時(shí)鐘 */
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOB,ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/* PB6-I2C1_SCL、PB7-I2C1_SDA*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*IIC外設(shè)初始化*/
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ; //配置為普通IIC模式
//I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
//I2C_InitStructure.I2C_OwnAddress1 = SlaveAddress;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能自動(dòng)應(yīng)答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 50000; //5K的速度?
/* I2C1 初始化 */
I2C_Init(I2C1, &I2C_InitStructure);
/* 使能 I2C1 */
I2C_Cmd (I2C1,ENABLE);
/*允許應(yīng)答模式*/
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
void ByteWrite(u8 addr,u8 dataValue)
{
I2C_GenerateSTART(I2C1,ENABLE);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,HMC_ADDR,I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1,addr);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1,dataValue);
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1,ENABLE);
}
u8 ByteRead(u8 addr)
{
u8 dataValue;
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1,ENABLE);//起始信號(hào)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,HMC_ADDR,I2C_Direction_Transmitter);//發(fā)送設(shè)備地址+寫信號(hào)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//
I2C_Cmd(I2C1,ENABLE);
I2C_SendData(I2C1,addr);//發(fā)送存儲(chǔ)單元地址,從0開始
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTART(I2C1,ENABLE);//起始信號(hào)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,HMC_ADDR,I2C_Direction_Receiver);//發(fā)送設(shè)備地址+讀信號(hào)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
I2C_AcknowledgeConfig(I2C1,DISABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
while(!(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)));
dataValue=I2C_ReceiveData(I2C1);//讀出寄存器數(shù)據(jù)
return dataValue;
}
審核編輯:湯梓紅
-
IIC
+關(guān)注
關(guān)注
11文章
306瀏覽量
39512 -
串行總線
+關(guān)注
關(guān)注
1文章
186瀏覽量
31122 -
代碼
+關(guān)注
關(guān)注
30文章
4900瀏覽量
70751
發(fā)布評(píng)論請(qǐng)先 登錄
一文詳解IIC總線

一文詳解IIC總線


IIC串行總線的組成及工作原理
IIC總線的相關(guān)資料推薦
IIC總線接口學(xué)習(xí)

IIC總線時(shí)序詳解

IIC總線初始化基本驅(qū)動(dòng)參考程序應(yīng)用代碼免費(fèi)下載

IIC總線接口的資料詳細(xì)說明

評(píng)論