學習交流792125321,歡迎一起加入討論!
在學習iic的時候,我們經常會遇到軟件 I2C和硬件 I2C,它兩到底有什么區別呢?
軟件 I2C(模擬 I2C)和硬件 I2C(外設 I2C)是兩種實現 I2C 總線通信的方式,核心區別在于 ?是否依賴微控制器(MCU)內置的硬件 I2C 外設。以下是詳細對比及標準庫(以 STM32 標準外設庫為例)的實現差異:
?1. 核心區別
?特性 | ?軟件 I2C | ?硬件 I2C |
---|---|---|
?實現方式 | 通過 GPIO 引腳模擬 I2C 時序(軟件控制) | 使用 MCU 內置的硬件 I2C 外設(硬件控制) |
?CPU 占用 | 高(需 CPU 持續操作 GPIO) | 低(硬件自動完成時序,CPU 可處理其他任務) |
?時序精度 | 依賴軟件延時,精度較低 | 由硬件時鐘控制,精度高且穩定 |
?開發復雜度 | 簡單(無需配置復雜寄存器) | 復雜(需初始化外設、處理中斷/DMA) |
?靈活性 | 高(可適配任意 GPIO 引腳) | 低(必須使用硬件 I2C 外設的固定引腳) |
?速度 | 較慢(受限于軟件延時) | 較快(支持標準模式 100kHz、快速模式 400kHz+) |
?兼容性 | 通用性強(可適配不同 MCU) | 依賴具體 MCU 的硬件支持 |
?2. 標準庫實現對比(以 STM32F1 標準外設庫為例)?
?(1) 硬件 I2C 實現
硬件 I2C 使用 STM32 內置的 I2C 外設,需配置時鐘、引腳復用、中斷/DMA 等。
代碼示例:初始化硬件 I2C1(標準模式,100kHz)?
#include "stm32f10x_i2c.h"void I2C_Hardware_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;I2C_InitTypeDef I2C_InitStruct;// 使能時鐘(I2C1 和 GPIOB)RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);// 配置 GPIOB6 (SCL) 和 GPIOB7 (SDA) 為復用開漏模式GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; // 復用開漏GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);// 配置 I2C1I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 占空比 16:9I2C_InitStruct.I2C_OwnAddress1 = 0xA0; // 主機地址(可忽略)I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 啟用應答I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHzI2C_Init(I2C1, &I2C_InitStruct);// 啟用 I2C1I2C_Cmd(I2C1, ENABLE);
}// 發送數據函數(需處理狀態標志和中斷)
void I2C_WriteByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) {I2C_GenerateSTART(I2C1, ENABLE);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));I2C_Send7bitAddress(I2C1, devAddr, I2C_Direction_Transmitter);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));I2C_SendData(I2C1, regAddr);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2C1, data);while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_GenerateSTOP(I2C1, ENABLE);
}
?(2) 軟件 I2C 實現
通過 GPIO 手動控制 SCL 和 SDA 引腳電平,模擬 I2C 時序。
代碼示例:模擬 I2C 時序(使用 GPIOB8 和 GPIOB9)?
#include "stm32f10x_gpio.h"// 定義 SCL 和 SDA 引腳
#define SOFT_I2C_SCL_PIN GPIO_Pin_8
#define SOFT_I2C_SDA_PIN GPIO_Pin_9
#define SOFT_I2C_PORT GPIOB// 初始化 GPIO
void Soft_I2C_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);// 配置 SCL 和 SDA 為開漏輸出模式GPIO_InitStruct.GPIO_Pin = SOFT_I2C_SCL_PIN | SOFT_I2C_SDA_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // 開漏輸出GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(SOFT_I2C_PORT, &GPIO_InitStruct);// 初始拉高 SCL 和 SDAGPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);
}// 微秒級延時函數(需根據實際時鐘調整)
void Delay_us(uint32_t us) {us *= 72; // 假設主頻為 72MHzwhile (us--) __NOP();
}// 發送起始信號
void Soft_I2C_Start(void) {GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);Delay_us(5);GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);
}// 發送停止信號
void Soft_I2C_Stop(void) {GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);Delay_us(5);GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);Delay_us(5);GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);
}// 發送一個字節
void Soft_I2C_WriteByte(uint8_t data) {for (int i = 0; i < 8; i++) {if (data & 0x80) {GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);} else {GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);}Delay_us(2);GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);Delay_us(5);GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);data <<= 1;}// 等待從機應答(省略應答檢查)GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SDA_PIN);Delay_us(2);GPIO_SetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);Delay_us(5);GPIO_ResetBits(SOFT_I2C_PORT, SOFT_I2C_SCL_PIN);
}
?3. 適用場景
?場景 | ?推薦方式 | ?原因 |
---|---|---|
高速通信(>100kHz) | 硬件 I2C | 依賴硬件時序精度,避免軟件延時誤差 |
多任務系統 | 硬件 I2C | 減少 CPU 占用,支持 DMA/中斷 |
引腳資源緊張 | 硬件 I2C | 必須使用固定引腳,避免浪費 GPIO |
適配非標準 I2C 設備 | 軟件 I2C | 可靈活調整時序(如長延時、非標準協議) |
硬件 I2C 外設不可用 | 軟件 I2C | 解決硬件資源沖突或兼容性問題 |
?4. 常見問題
-
?硬件 I2C 初始化失敗:
檢查時鐘配置、引腳復用、上拉電阻(硬件 I2C 需要外部上拉,通常 4.7kΩ)。 -
?軟件 I2C 通信不穩定:
調整延時函數精度,確保 SCL/SDA 邊沿時間符合設備要求。 -
?速度瓶頸:
軟件 I2C 通常無法超過 100kHz,硬件 I2C 可支持 400kHz(Fast Mode)或更高。
?總結
- ?硬件 I2C:適合高速、高穩定性場景,但開發復雜且依賴固定引腳。
- ?軟件 I2C:靈活簡單,但占用 CPU 資源且速度受限。
根據項目需求選擇合適方案:優先使用硬件 I2C 提升性能,若硬件資源不足或需要特殊時序,則用軟件模擬。