IIC協議詳解
- 一、IIC協議簡介
- 二、IIC總線結構圖
- 三、IIC通信流程詳解
- 1. 空閑狀態 : 雙高空閑
- 2. 起始信號(START): 時高數下開始
- 3. 停止信號(STOP): 時高數上結束
- 4. 數據傳輸格式 : 時高數穩,時低數變
- 5. 應答信號
- 四、寫操作流程
- 五、讀操作流程
- 六、IIC代碼(STM32)詳解
- 1. 初始化函數
- 2. 寫數據函數(主寫從)
- 七、小結
- 八、常見問題
一、IIC協議簡介
IIC(I2C)是由飛利浦公司提出的一種串行通信協議,僅用兩根線:
- SDA:串行數據線
- SCL:串行時鐘線
它是一種半雙工、多主機、主從通信協議,每個從設備都有唯一的地址。數據傳輸速度支持:
- 標準模式:100kbps
- 快速模式:400kbps
- 高速模式:3.4Mbps
二、IIC總線結構圖
兩條總線連接主從設備,SDA和SCL均需上拉電阻保持高電平(空閑狀態)。
三、IIC通信流程詳解
1. 空閑狀態 : 雙高空閑
SDA 和 SCL 都為高電平時為空閑狀態。
2. 起始信號(START): 時高數下開始
在 SCL 為高電平時,SDA 從高變低,表示通信開始。
3. 停止信號(STOP): 時高數上結束
在 SCL 為高電平時,SDA 從低變高,表示通信結束。
4. 數據傳輸格式 : 時高數穩,時低數變
- 數據按字節(8位)發送
- 每個字節后跟一個應答位(ACK)
- 傳輸過程中,SDA 數據需在 SCL 高電平期間穩定
當SCL為高電平時,便會獲取SDA數據值,其中SDA數據必須是穩定的(若SDA不穩定就會變成起始/停止信號)。
當SCL為低電平時,便是SDA的電平變化狀態。
若主從機在傳輸數據期間,需要完成其它功能(例如一個中斷),可以主動拉低SCL,使I2C進入等待狀態,直到處理結束再釋放SCL,數據傳輸會繼
5. 應答信號
I2C總線上的數據都是以8位數據(字節)進行的,當發送了8個數據后,發送方會在第9個時鐘脈沖期間釋放SDA數據,當接收方接收該字節成功,便會輸出一個ACK應答信號,當SDA為高電平,表示為非應答信號NACK,當SDA為低電平,表示為有效應答信號AC
- ACK:SDA 被接收方拉低,表示接收成功
- NACK:SDA 保持高電平,表示接收失敗或結束
四、寫操作流程
- 主機發送起始信號
- 發送從機地址 + 寫方向(最低位,第八位為0)
- 等待從機應答ACK
- 發送寄存器地址和數據
- 每發送1字節都需從機應答
- 最后發送停止信號
五、讀操作流程
- 主機發送起始信號
- 發送從機地址 + 寫方向(0)
- 等待應答,發送寄存器地址
- 發送重新開始信號(重復START): 主機要改變通信模式(主機將由發送變為接收,從機將由接收變為發送),所以主機重新發送一個開始start信號,然后緊跟著發送一個從機地址,注意此時該地址的第8位為1,表明將主機設置成接收模式,開始讀取數據
- 發送從機地址 + 讀方向(1)
- 接收數據,每接收一個字節主機需發送 ACK
- 最后一個字節發 NACK + 停止信號
六、IIC代碼(STM32)詳解
1. 初始化函數
void I2C_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 開啟GPIOB時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 開啟I2C1時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // SCL = PB6, SDA = PB7GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 復用開漏輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOBI2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // I2C模式I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 本機地址I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // 打開應答I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz速率I2C_Init(I2C1, &I2C_InitStructure);I2C_Cmd(I2C1, ENABLE); // 使能I2C
}
2. 寫數據函數(主寫從)
void I2C_SendData(uint8_t slaveAddress, uint8_t* pBuffer, uint16_t numByteToWrite)
{I2C_GenerateSTART(I2C1, ENABLE); // 產生起始信號while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));I2C_Send7bitAddress(I2C1, slaveAddress, I2C_Direction_Transmitter); // 發地址+寫方向while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));while (numByteToWrite--){I2C_SendData(I2C1, *pBuffer++); // 發送數據while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // 等待發送完成}I2C_GenerateSTOP(I2C1, ENABLE); // 發送停止信號
}
七、小結
名稱 | 描述 |
---|---|
SDA | 數據線(雙向) |
SCL | 時鐘線(主機控制) |
START | SDA下降沿 + SCL高,表示開始 |
STOP | SDA上升沿 + SCL高,表示結束 |
ACK/NACK | 接收方對字節的響應 |
八、常見問題
- 為什么要加上拉電阻?
因為SDA/SCL為開漏結構,無法主動輸出高電平。 - 為什么要重復發送START?
切換讀寫模式或設備地址時,需發START而不是STOP。