软件IIC和硬件IIC的引脚配置有什么区别?

STM32的硬件IIC和软件模拟IIC在引脚配置上有根本性的区别

下面是两者的核心区别对比:

特性 硬件IIC 软件模拟IIC (Software IIC)
引脚要求 必须 使用芯片指定的、具有I2C外设功能复用的特定引脚 几乎任意通用输入输出(GPIO)引脚都可以。
配置模式 将GPIO模式设置为 GPIO_Mode_AF_OD (复用开漏输出)。 将GPIO模式设置为 GPIO_Mode_Out_OD (通用开漏输出)或使用推挽输出加外部上拉。
初始化内容 需要初始化两个部分 : 1. GPIO引脚 2. I2C外设本身(如I2C1) 只需要初始化GPIO引脚。所有时序都由软件代码控制。
内部上拉电阻 通常禁用 内部上拉,依赖外部上拉电阻(4.7kΩ),以确保总线兼容性和可靠性。 强烈建议 使用外部上拉电阻(4.7kΩ),禁用内部上拉。
灵活性 。引脚由芯片数据手册(Datasheet)的引脚定义表固定死,不可更改。 极高。可以任意更换到其他GPIO引脚,无需修改硬件电路。
性能 。由硬件处理,占用CPU资源少,速度稳定且快。 。由CPU循环模拟,占用大量CPU资源,速度慢且受其他中断影响。
可靠性 。硬件处理时序精确,抗干扰能力强。 较低。时序由软件延时保证,在复杂中断环境中容易出错。

详细配置代码对比

假设我们使用STM32F103系列芯片,操作I2C1,其硬件I2C引脚通常是PB6(SCL)PB7(SDA)

1. 硬件IIC配置

硬件IIC的配置分为两大步:配置GPIO配置I2C外设

c 复制代码
/* 硬件IIC引脚配置函数 */
void HW_I2C_GPIO_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
    
    // 配置I2C1 SCL (PB6) 和 SDA (PB7)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    // 关键区别:模式必须设置为 **复用开漏输出**
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度建议设置高一些
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/* 硬件IIC外设模式配置函数 */
void HW_I2C_Mode_Config(void) {
    I2C_InitTypeDef I2C_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // I2C1时钟位于APB1总线
    
    I2C_InitStructure.I2C_Mode = I2C_Mode_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 = 400000; // 400kHz
    I2C_Init(I2C1, &I2C_InitStructure);
    
    I2C_Cmd(I2C1, ENABLE); // 使能I2C1
}

// 在主函数中,需要调用以上两个函数来完成完整初始化
void main() {
    ...
    HW_I2C_GPIO_Config();
    HW_I2C_Mode_Config();
    ...
}
2. 软件模拟IIC (Software IIC) 配置

软件IIC只需要配置GPIO,非常灵活。这里我们仍然使用PB6和PB7,但你完全可以换成PC0和PC1等其他引脚。

c 复制代码
// 首先进行宏定义,方便后续编程和修改引脚
#define SOFT_I2C_SDA_PORT    GPIOB
#define SOFT_I2C_SDA_PIN     GPIO_Pin_7
#define SOFT_I2C_SCL_PORT    GPIOB
#define SOFT_I2C_SCL_PIN     GPIO_Pin_6

#define SOFT_I2C_SDA_HIGH()  GPIO_SetBits(SOFT_I2C_SDA_PORT, SOFT_I2C_SDA_PIN)
#define SOFT_I2C_SDA_LOW()   GPIO_ResetBits(SOFT_I2C_SDA_PORT, SOFT_I2C_SDA_PIN)
#define SOFT_I2C_SCL_HIGH()  GPIO_SetBits(SOFT_I2C_SCL_PORT, SOFT_I2C_SCL_PIN)
#define SOFT_I2C_SCL_LOW()   GPIO_ResetBits(SOFT_I2C_SCL_PORT, SOFT_I2C_SCL_PIN)
#define SOFT_I2C_SDA_READ()  GPIO_ReadInputDataBit(SOFT_I2C_SDA_PORT, SOFT_I2C_SDA_PIN)

/* 软件IIC GPIO配置函数 */
void SOFT_I2C_GPIO_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    // 配置SCL引脚为**通用开漏输出**
    GPIO_InitStructure.GPIO_Pin = SOFT_I2C_SCL_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 关键区别:通用开漏输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SOFT_I2C_SCL_PORT, &GPIO_InitStructure);
    
    // 配置SDA引脚,初始化为开漏输出。在读取时会临时切换为输入模式。
    GPIO_InitStructure.GPIO_Pin = SOFT_I2C_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 关键区别:通用开漏输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(SOFT_I2C_SDA_PORT, &GPIO_InitStructure);
    
    // 将总线置于空闲状态(高电平)
    SOFT_I2C_SCL_HIGH();
    SOFT_I2C_SDA_HIGH();
}

// 之后,你需要用软件代码模拟I2C的时序,例如:
void SOFT_I2C_Start(void) {
    SOFT_I2C_SDA_HIGH();
    SOFT_I2C_SCL_HIGH();
    Delay_us(5);
    SOFT_I2C_SDA_LOW(); // Start condition: SDA falls while SCL is high
    Delay_us(5);
    SOFT_I2C_SCL_LOW();
}
// ... 还需要实现Stop、SendByte、ReceiveByte等函数

总结与选择建议

场景 推荐方案 理由
高速、高可靠性、多从机通信 硬件IIC 硬件处理效率高,不占用CPU,时序精确稳定。
引脚冲突,硬件IIC引脚被占用 软件IIC 可以灵活更换到其他任意引脚。
学习、调试、快速验证 软件IIC 配置简单,便于理解I2C协议本质,调试时可用逻辑分析仪抓波形。
项目初期,硬件设计未定型 软件IIC 即使后期硬件引脚变更,软件也只需修改宏定义,无需大改。
需要同时使用多个I2C总线 组合使用 STM32通常只有1-2个硬件I2C,可用硬件I2C操作主要设备,软件I2C操作次要设备。

核心记住一点:硬件IIC的引脚是芯片固定的,而软件IIC的引脚是你自己任选的。 硬件IIC需要配置外设模式,软件IIC只需要配置GPIO模式并为它们编写模拟时序的函数。无论是软件IIC抑或是硬件IIC都依赖于外部上拉电阻来确保线兼容性和可靠性,这个电阻通常可以取4.7K。

相关推荐
yuanmenghao6 小时前
Classic AUTOSAR深入浅出系列 - 【第十六篇】MCAL:为什么 MCU 换了,上层几乎不用动
单片机·嵌入式硬件·autosar
MickyCode8 小时前
嵌入式开发调试之Traceback
arm开发·stm32·单片机·mcu
czwxkn9 小时前
3STM32(stdl)外部中断
stm32·单片机·嵌入式硬件
羽获飞9 小时前
从零开始学嵌入式之STM32——6.与GPIO相关的7个寄存器--重要知识
stm32·单片机·嵌入式硬件
棒子陈9 小时前
使用cursor移植单片机的串口驱动(DMA+队列式串口驱动,APM32F103移植到PY32F071)
单片机·嵌入式硬件·cursor·py32f071
VALENIAN瓦伦尼安教学设备10 小时前
镭射对心仪在联轴器找正作用
大数据·数据库·人工智能·嵌入式硬件
蓬荜生灰10 小时前
STM32(11)-- GPIO输出,库函数点灯
stm32·单片机·嵌入式硬件
济61710 小时前
ARM Linux 驱动开发篇----字符设备驱动开发(1)--字符设备驱动简介---- Ubuntu20.04
linux·嵌入式硬件
csg110711 小时前
PIC单片机驱动BH1750光照传感器,轻松获取环境光照数据
单片机·嵌入式硬件·物联网
雾削木11 小时前
使用 ESPHome 的核心指令
java·前端·javascript·单片机·嵌入式硬件