2026/3/1 12:18:48
网站建设
项目流程
网站建设公司税率,怎么区分模板网站,推荐软件分类,领诺科技网站建设通过代码直观看到软件 I2C 和硬件 I2C 的区别#xff0c;这个思路特别好#xff01;我以 STM32F103 为例#xff0c;分别给出驱动同一个 I2C 设备#xff08;比如温湿度传感器#xff09; 的核心代码#xff0c;你对比着看就能立刻明白差异。一、软件 I2C 核心代码#…通过代码直观看到软件 I2C 和硬件 I2C 的区别这个思路特别好我以 STM32F103 为例分别给出驱动同一个 I2C 设备比如温湿度传感器的核心代码你对比着看就能立刻明白差异。一、软件 I2C 核心代码模拟时序软件 I2C 完全用 GPIO 口模拟 SCL/SDA 的高低电平变化所有时序都靠代码手动控制#include stm32f10x.h // 定义软件I2C引脚可任意选GPIO #define I2C_SCL_PIN GPIO_Pin_0 #define I2C_SDA_PIN GPIO_Pin_1 #define I2C_GPIO_PORT GPIOB #define I2C_GPIO_CLK RCC_APB2Periph_GPIOB // 引脚电平控制核心手动改电平 #define SCL_HIGH() GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN) #define SCL_LOW() GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN) #define SDA_HIGH() GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN) #define SDA_LOW() GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN) #define SDA_READ() GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN) // 软件I2C初始化就是配置GPIO为推挽输出 void Soft_I2C_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(I2C_GPIO_CLK, ENABLE); // SCL引脚配置 GPIO_InitStruct.GPIO_Pin I2C_SCL_PIN; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO_PORT, GPIO_InitStruct); // SDA引脚配置 GPIO_InitStruct.GPIO_Pin I2C_SDA_PIN; GPIO_Init(I2C_GPIO_PORT, GPIO_InitStruct); // 初始电平拉高 SCL_HIGH(); SDA_HIGH(); } // 软件I2C起始信号手动模拟时序 void Soft_I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); delay_us(2); // 必须加延时保证时序否则通信失败 SDA_LOW(); delay_us(2); SCL_LOW(); } // 软件I2C发送一个字节每一位都要手动控制时钟 uint8_t Soft_I2C_Send_Byte(uint8_t data) { uint8_t i; for(i0; i8; i) // 逐位发送 { if(data 0x80) SDA_HIGH(); // 最高位先发送 else SDA_LOW(); data 1; SCL_HIGH(); // 时钟拉高从机读取数据 delay_us(2); SCL_LOW(); // 时钟拉低准备下一位 delay_us(2); } // 等待从机应答 SDA_HIGH(); SCL_HIGH(); delay_us(2); uint8_t ack SDA_READ(); SCL_LOW(); return ack; } // 其他停止、接收字节等函数都是类似的手动时序控制...二、硬件 I2C 核心代码外设自动处理硬件 I2C 只需要配置寄存器剩下的时序由硬件自动完成#include stm32f10x.h #define I2Cx I2C1 #define I2C_CLK RCC_APB1Periph_I2C1 #define I2C_GPIO_CLK RCC_APB2Periph_GPIOB #define I2C_SCL_PIN GPIO_Pin_6 #define I2C_SDA_PIN GPIO_Pin_7 // 硬件I2C初始化配置外设参数引脚是固定的 void Hard_I2C_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; // 1. 使能时钟 RCC_APB1PeriphClockCmd(I2C_CLK, ENABLE); RCC_APB2PeriphClockCmd(I2C_GPIO_CLK, ENABLE); // 2. 配置引脚为复用开漏输出硬件I2C必须用固定引脚复用模式 GPIO_InitStruct.GPIO_Pin I2C_SCL_PIN | I2C_SDA_PIN; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_OD; // 复用开漏 GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStruct); // 3. 配置I2C外设参数 I2C_DeInit(I2Cx); I2C_InitStruct.I2C_Mode I2C_Mode_I2C; I2C_InitStruct.I2C_DutyCycle I2C_DutyCycle_2; I2C_InitStruct.I2C_OwnAddress1 0x00; // 主机模式自己的地址随便设 I2C_InitStruct.I2C_Ack I2C_Ack_Enable; I2C_InitStruct.I2C_AcknowledgedAddress I2C_AcknowledgedAddress_7bit; I2C_InitStruct.I2C_ClockSpeed 400000; // 400KHz高速模式 I2C_Cmd(I2Cx, ENABLE); I2C_Init(I2Cx, I2C_InitStruct); } // 硬件I2C发送一个字节调用外设函数不用管时序 void Hard_I2C_Send_Byte(uint8_t addr, uint8_t data) { // 1. 等待I2C总线空闲 while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); // 2. 发送起始信号硬件自动生成时序 I2C_GenerateSTART(I2Cx, ENABLE); while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); // 3. 发送设备地址硬件自动处理时钟和应答 I2C_Send7bitAddress(I2Cx, addr, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // 4. 发送数据硬件自动移位不用逐位控制 I2C_SendData(I2Cx, data); while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // 5. 发送停止信号 I2C_GenerateSTOP(I2Cx, ENABLE); }三、核心区别一眼看明白对比项软件 I2C硬件 I2C引脚控制任意 GPIO手动改高低电平固定引脚复用模式硬件自动控制时序实现靠 delay_us () 和循环逐位模拟硬件逻辑自动生成无需手动延时CPU 占用高全程要 CPU 盯着低配置完 CPU 可干别的代码复杂度简单直接操作 GPIO稍复杂配置外设寄存器灵活性极高可自定义时序低引脚 / 时序固定总结软件 I2C像你手动掰开关控制电路代码直观、引脚随便选但要自己控制每一步时序CPU 不能干别的硬件 I2C像你给机器人下指令只需要告诉它 “发什么数据”剩下的由硬件自动完成CPU 解放出来但必须用固定引脚新手做简单项目比如读单个传感器选软件 I2C 更易上手需要高频通信 / 多设备时选硬件 I2C 更稳定。