恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
STM32开发之IIC通信详解:从协议基础到FM24CL04实战
首页
资讯中心
/
STM32开发之IIC通信详解:从协议基础到FM24CL04实战
STM32开发之IIC通信详解:从协议基础到FM24CL04实战
发布时间:2026/10/12 4:49:00
1. IIC概述IICInter-Integrated Circuit集成电路间总线是一种由飞利浦公司现恩智浦半导体开发的两线式串行通信总线广泛应用于微控制器与各类外设如 EEPROM、传感器、RTC 时钟芯片等之间的低速通信。IIC总线仅需两根信号线即可完成数据传输SDASerial Data Line串行数据线用于传输数据双向传输数据在 SCL 高电平期间必须保持稳定。SCLSerial Clock Line串行时钟线用于传输时钟信号由主机产生控制数据传输的节奏。IIC总线具有以下显著特点两线制仅需 SDA 和 SCL 两根线节省引脚资源。多主机多从机总线上可挂载多个设备每个设备具有唯一的 7 位或 10 位地址。半双工通信同一时刻只能有一个方向的数据传输。速率适中标准模式 100kbit/s快速模式 400kbit/s高速模式 3.4Mbit/s。开漏输出SDA 和 SCL 均为开漏结构需外接上拉电阻。在 STM32 中IIC 外设通常集成在芯片内部支持硬件 IIC 和软件模拟 IIC 两种实现方式。硬件 IIC 由芯片内部外设自动处理时序软件模拟 IIC 则通过 GPIO 翻转电平实现两者各有优劣。2. IIC协议2.1 总线空闲状态当总线处于空闲状态时SDA 和 SCL 均为高电平。此时总线上没有任何设备占用通信主机可以发起通信。2.2 起始条件START起始条件是 IIC 通信的启动标志由主机产生。其时序要求为在 SCL 保持高电平期间SDA 由高电平跳变为低电平。起始条件产生后总线进入忙碌状态其他设备不能再发起通信。2.3 停止条件STOP停止条件是 IIC 通信的结束标志同样由主机产生。其时序要求为在 SCL 保持高电平期间SDA 由低电平跳变为高电平。停止条件产生后总线恢复空闲状态释放总线控制权。2.4 数据有效性IIC 协议规定数据在传输过程中必须满足以下时序要求数据稳定期在 SCL 高电平期间SDA 上的数据必须保持稳定不允许发生变化。数据变化期在 SCL 低电平期间SDA 上的数据才允许发生变化。这一规定确保了接收方在 SCL 高电平采样时读取到的数据是稳定可靠的。2.5 应答机制ACK/NACKIIC协议采用应答机制来确认数据接收是否成功。每传输一个字节8位数据后接收方需要返回一个应答位ACK应答接收方在第9个时钟周期将SDA拉低表示成功接收数据可以继续传输。NACK非应答接收方在第9个时钟周期保持SDA为高电平表示未成功接收或不再接收数据。主机在发送数据后需要释放SDA并等待从机的应答信号从机在接收数据后需要主动拉低SDA以产生应答。2.6 完整数据传输时序一次完整的IIC数据传输过程如下主机产生起始条件START。主机发送从机地址7位地址 1位读写标志位共8位。从机返回应答位ACK。主机发送寄存器地址或数据每字节后跟一个应答位。根据读写方向继续传输数据或切换方向。主机产生停止条件STOP结束通信。2.7 时序图说明IIC时序图是理解协议的关键工具下面用文字描述标准时序图的各个阶段起始阶段SCL为高SDA从高跳变为低产生START信号。地址传输阶段主机在SCL的驱动下逐位发送从机地址先发送最高位MSB共7位地址随后发送1位读写标志0表示写1表示读。应答阶段第9个时钟周期从机拉低SDA产生ACK应答。数据传输阶段主机继续发送数据字节每个字节8位每字节后跟一个ACK应答位。数据在SCL高电平期间保持稳定在SCL低电平期间变化。停止阶段SCL为高SDA从低跳变为高产生STOP信号总线释放。2.8 读写操作示例写操作流程主机发送START → 发送从机地址写标志0→ 等待ACK → 发送寄存器地址 → 等待ACK → 发送数据 → 等待ACK → 发送STOP。读操作流程主机发送START → 发送从机地址写标志0→ 等待ACK → 发送寄存器地址 → 等待ACK → 重新发送START重复起始条件→ 发送从机地址读标志1→ 等待ACK → 读取数据 → 主机发送NACK → 发送STOP。3. STM32中的IIC实现3.1 硬件IICSTM32系列芯片内置IIC外设支持主机模式和从机模式具备中断和DMA传输能力。硬件IIC的优点是CPU占用低、时序精确但配置相对复杂且部分型号的硬件IIC存在兼容性问题。3.2 软件模拟IIC软件模拟IIC通过GPIO引脚手动翻转电平按照IIC时序要求逐位传输数据。其优点是灵活、兼容性好、不受芯片型号限制缺点是占用CPU资源较多。3.3 上拉电阻由于IIC总线采用开漏输出结构SDA和SCL必须外接上拉电阻。典型上拉电阻值为4.7kΩ标准模式或2.2kΩ快速模式具体取值需根据总线电容和通信速率确定。4. FM24CL04 EEPROM 详解FM24CL04 是 Cypress现 Infineon推出的一款4Kbit 铁电存储器FRAM采用 IIC 接口与主机通信。与传统的 EEPROM 相比FRAM 具有写入速度快、擦写寿命长、功耗低等显著优势非常适合需要频繁读写数据的应用场景。4.1 主要特性存储容量4Kbit512 × 8 位组织为两个 256 字节的存储区。接口类型标准 IIC 接口支持 100kHz 标准模式和 400kHz 快速模式。写入速度无需等待写入周期写入后立即可读写入速度远快于传统 EEPROM。擦写寿命高达 10 亿次读写循环远超普通 EEPROM 的 100 万次。数据保持掉电后数据可保持 10 年以上。工作电压2.7V ~ 3.6V兼容 3.3V 系统。封装形式常见 SOP-8 封装引脚与标准 24C04 EEPROM 兼容。4.2 器件地址与存储区映射FM24CL04 的从机地址为 7 位格式为1010 A2 A1 A0其中 A2、A1 为硬件地址引脚A0 为存储区选择位。由于芯片内部划分为两个 256 字节的存储区A0 位用于选择访问哪个存储区A0 0访问存储区 0地址 0x00 ~ 0xFF。A0 1访问存储区 1地址 0x00 ~ 0xFF。因此FM24CL04 的完整从机地址为0xA0写/ 0xA1读对应存储区 0或0xA2写/ 0xA3读对应存储区 1具体取决于 A2、A1 引脚的接法。4.3 写操作时序FM24CL04 的写操作与标准 IIC EEPROM 类似但无需等待内部写周期。具体流程如下主机发送起始条件START。主机发送从机地址 写标志如 0xA0。从机返回应答位ACK。主机发送字节地址0x00 ~ 0xFF对应所选存储区内的地址。从机返回应答位ACK。主机发送数据字节每字节后从机返回 ACK。主机发送停止条件STOP写入完成。由于 FRAM 无需写周期主机可以在发送 STOP 后立即发起下一次读写操作无需像传统 EEPROM 那样轮询 ACK 或等待延时。4.4 读操作时序FM24CL04 支持两种读操作方式当前地址读和随机地址读。随机地址读流程主机发送起始条件START。主机发送从机地址 写标志如 0xA0。从机返回应答位ACK。主机发送字节地址目标读取地址。从机返回应答位ACK。主机重新发送起始条件重复起始条件。主机发送从机地址 读标志如 0xA1。从机返回应答位ACK。主机读取数据字节每字节后主机发送 ACK除最后一字节发送 NACK。主机发送停止条件STOP读取完成。4.5 与 STM32 的硬件连接FM24CL04 与 STM32 的连接非常简单只需两根 IIC 信号线加上拉电阻SDA连接到 STM32 的 IIC 数据引脚如 PB7。SCL连接到 STM32 的 IIC 时钟引脚如 PB6。VCC连接到 3.3V 电源。GND连接到地。WP写保护引脚接地表示允许写入接高电平表示写保护。A2、A1地址引脚通常接地。SDA 和 SCL 需要外接上拉电阻典型值 4.7kΩ与 STM32 的 IIC 外设或软件模拟 IIC 配合使用。4.6 应用场景FM24CL04 凭借其高速写入和超长寿命广泛应用于以下场景数据采集系统频繁记录传感器数据无需担心擦写寿命。参数存储保存系统配置参数、校准数据等。掉电保护在系统掉电瞬间快速保存关键状态。日志记录记录运行日志、故障信息等。5. STM32F4xx I2C控制器STM32F4xx系列微控制器内置了功能完善的I2C外设控制器支持主机模式和从机模式具备中断、DMA传输以及多主机仲裁等高级特性。本节将详细介绍STM32F4xx I2C控制器的内部结构、寄存器配置以及实际应用方法。5.1 I2C控制器内部结构STM32F4xx的I2C外设主要由以下功能模块组成时钟控制单元负责产生SCL时钟信号支持标准模式100kHz、快速模式400kHz以及快速模式1MHz。数据移位寄存器实现SDA数据的串行发送与接收支持7位和10位地址模式。地址比较器在从机模式下自动比较接收到的地址与自身地址匹配时产生中断。状态寄存器记录通信过程中的各种状态标志如起始条件、停止条件、应答状态等。控制寄存器配置I2C的工作模式、中断使能、DMA请求等参数。数据寄存器用于读写待发送或已接收的数据字节。5.2 I2C引脚配置STM32F4xx的I2C外设通常可以映射到多个GPIO引脚以I2C1为例其引脚映射如下I2C1_SCL可映射到 PB6、PB8 等引脚。I2C1_SDA可映射到 PB7、PB9 等引脚。I2C2_SCL可映射到 PB10、PF1 等引脚。I2C2_SDA可映射到 PB11、PF0 等引脚。I2C3_SCL可映射到 PA8、PH7 等引脚。I2C3_SDA可映射到 PC9、PH8 等引脚。在使用I2C外设前需要将对应的GPIO引脚配置为复用功能AF模式并设置为开漏输出、带上拉电阻。以I2C1使用PB6和PB7为例GPIO配置代码如下// 使能GPIOB和I2C1时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 配置PB6为SCLPB7为SDA复用功能AF4 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_OpenDrain; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; GPIO_Init(GPIOB, GPIO_InitStructure); // 将PB6、PB7连接到I2C1的复用功能 GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);5.3 I2C初始化配置完成GPIO配置后需要对I2C外设进行初始化设置通信速率、地址模式等参数。使用标准外设库的初始化代码如下I2C_InitTypeDef I2C_InitStructure; // I2C1配置为快速模式400kHz I2C_InitStructure.I2C_Mode I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress 0x00; // 主机模式自身地址可设为0 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);在配置I2C时钟频率时需要注意APB1总线的时钟频率。I2C的时钟由APB1时钟分频得到计算公式为// I2C时钟频率 APB1时钟频率 / (2 × (CCR 1))快速模式 // 或 I2C时钟频率 APB1时钟频率 / (2 × CCR)标准模式5.4 主机发送数据作为主机发送数据时需要依次完成起始条件、发送从机地址、发送数据、停止条件等步骤。以下是一个向FM24CL04写入数据的完整示例void I2C_WriteByte(uint8_t slaveAddr, uint8_t regAddr, uint8_t data) { // 发送起始条件 I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); // 发送从机地址 写标志 I2C_Send7bitAddress(I2C1, slaveAddr, 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); }5.5 主机接收数据主机接收数据时需要先发送从机地址和寄存器地址然后重新发送起始条件并切换为接收模式。以下是从FM24CL04读取一个字节的示例uint8_t I2C_ReadByte(uint8_t slaveAddr, uint8_t regAddr) { uint8_t data 0; // 发送起始条件 I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); // 发送从机地址 写标志先写寄存器地址 I2C_Send7bitAddress(I2C1, slaveAddr, 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_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); // 发送从机地址 读标志 I2C_Send7bitAddress(I2C1, slaveAddr, I2C_Direction_Receiver); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); // 读取数据发送NACK后停止 I2C_AcknowledgeConfig(I2C1, DISABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); data I2C_ReceiveData(I2C1); I2C_GenerateSTOP(I2C1, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); return data; }5.6 使用DMA进行批量传输对于大量数据的传输使用DMA可以显著降低CPU负载。STM32F4xx的I2C外设支持DMA请求配置DMA传输的步骤如下配置DMA通道设置数据传输方向、数据宽度和传输数量。使能I2C的DMA请求功能。启动DMA传输I2C会自动触发DMA请求。传输完成后DMA产生中断通知CPU。以下是一个使用DMA向FM24CL04写入多个字节的示例void I2C_DMA_Write(uint8_t slaveAddr, uint8_t regAddr, uint8_t *buffer, uint16_t len) { // 配置DMA1通道6用于I2C1发送 DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_InitStructure.DMA_Channel DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)I2C1-DR; DMA_InitStructure.DMA_Memory0BaseAddr (uint32_t)buffer; DMA_InitStructure.DMA_DIR DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize len; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode DMA_Mode_Normal; DMA_InitStructure.DMA_Priority DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode DMA_FIFOMode_Disable; DMA_Init(DMA1_Stream6, DMA_InitStructure); // 发送起始条件和从机地址 I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, slaveAddr, 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)); // 使能DMA请求并启动传输 I2C_DMACmd(I2C1, ENABLE); DMA_Cmd(DMA1_Stream6, ENABLE); // 等待传输完成 while (!DMA_GetFlagStatus(DMA1_Stream6, DMA_FLAG_TCIF6)); DMA_Cmd(DMA1_Stream6, DISABLE); I2C_DMACmd(I2C1, DISABLE); // 发送停止条件 I2C_GenerateSTOP(I2C1, ENABLE); }5.7 状态标志函数在标准外设库中I2C_GetFlagStatus和I2C_ClearFlag是用于查询和清除 I2C 外设状态标志的两个重要函数常用于轮询方式判断通信状态或处理异常情况。I2C_GetFlagStatus用于读取 I2C 外设的指定状态标志位其函数原型如下FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);该函数返回SET或RESET用于判断对应标志是否置位。常用标志包括I2C_FLAG_BUSY总线忙标志置位表示总线正在通信。I2C_FLAG_AF应答失败标志置位表示从机未应答。I2C_FLAG_BTF字节发送完成标志置位表示数据寄存器已空且移位寄存器已发送完毕。I2C_FLAG_TXE数据寄存器空标志置位表示可以写入下一个数据。I2C_FLAG_RXNE数据寄存器非空标志置位表示已接收到数据。使用示例// 等待数据发送完成 while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) RESET); // 检查从机是否应答 if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) SET) { // 从机无应答处理错误 }I2C_ClearFlag用于手动清除指定的状态标志位其函数原型如下void I2C_ClearFlag(I2C_TypeDef* I2Cx, uint32_t I2C_FLAG);当通信异常导致某些标志如应答失败标志 AF、总线错误标志 BERR一直保持置位时需要调用该函数清除标志以便恢复正常通信。使用示例// 清除应答失败标志 I2C_ClearFlag(I2C1, I2C_FLAG_AF); // 清除总线错误标志 I2C_ClearFlag(I2C1, I2C_FLAG_BERR);在实际开发中建议在每次通信开始前先清除相关标志避免上一次通信遗留的标志影响本次判断在通信过程中则通过 I2C_GetFlagStatus 轮询关键标志确保每一步操作都正确完成。5.8 常见问题与调试技巧在使用STM32F4xx I2C控制器时可能会遇到以下常见问题总线忙BUSY标志无法清除当通信异常中断时I2C总线的BUSY标志可能一直保持置位。解决方法是将I2C外设复位I2C_SoftwareResetCmd或切换GPIO引脚电平强制释放总线。SCL时钟频率不准确检查APB1时钟频率配置是否正确以及CCR寄存器的分频值是否计算准确。从机无应答NACK检查从机地址是否正确、上拉电阻是否接好、从机是否处于正常工作状态。DMA传输数据错位确保DMA配置的数据宽度与I2C数据寄存器一致均为8位并正确设置传输方向。中断优先级冲突当I2C中断与DMA中断同时使用时需要合理设置NVIC优先级避免数据丢失。调试I2C通信时建议使用逻辑分析仪或示波器观察SDA和SCL的波形确认起始条件、地址、数据和停止条件是否符合协议要求。5.9 软件模拟 IIC 示例GPIO 位操作除了使用 STM32 硬件 I2C 外设外也可以通过 GPIO 引脚手动翻转电平来软件模拟 IIC 时序。这种方式不依赖芯片内部 I2C 外设兼容性更好常用于调试或对时序要求不高的场景。下面给出一个完整的软件模拟 IIC 读写示例。首先定义 SCL 和 SDA 引脚其中 SDA 需要同时支持输入和输出#define SCL PBout(8) #define SDA_R PBin(9) #define SDA_W PBout(9)起始条件在 SCL 保持高电平期间SDA 由高电平跳变为低电平。建立时间 Tsu 至少为 4.7us保持时间 Thd 至少为 4.0us因此延时取 4us 以上void i2c_start(void) { SCL 1; SDA_W 1; delay_us(4); SDA_W 0; delay_us(4); }停止条件在 SCL 保持高电平期间SDA 由低电平跳变为高电平void i2c_stop(void) { SCL 0; SDA_W 0; delay_us(4); SCL 1; SDA_W 1; delay_us(4); }主机发送一个字节数据在 SCL 低电平期间变化在 SCL 高电平期间保持稳定从高位MSB开始逐位发送void i2c_send_byte(uint8_t c) { int i; SCL 0; // 拉低时钟线允许 SDA 改变 delay_us(2); for (i 0; i 8; i) { SDA_W !!(c (1 (7 - i))); // 先发高位 delay_us(2); SCL 1; // 锁存数据让从机可以识别 delay_us(2); SCL 0; delay_us(2); } SDA_W 1; // 一个字节发送完毕释放数据线等待对方回 ACK delay_us(2); }主机接收一个字节同样在 SCL 低电平期间允许 SDA 变化在高电平期间采样读取从高位开始逐位接收uint8_t i2c_recv_byte(void) { uint8_t recv 0; int i; for (i 0; i 8; i) { SCL 0; // 只有在时钟线为低电平时SDA 才能改变 delay_us(2); SCL 1; // 时钟线为高电平让 SDA 保持稳定 delay_us(2); recv | SDA_R (7 - i); // 先接收高位大端式 } SCL 0; // 拉低时钟线允许对方继续发数据 return recv; }主机发送应答位ACK/NACK在 SCL 低电平期间设置 SDA 电平高电平期间锁存给从机识别void i2c_ack(uint8_t ack) // 回 ACK { SCL 0; delay_us(2); SDA_W ack; delay_us(2); SCL 1; delay_us(2); SCL 0; // 拉低时钟线允许对方继续发数据 }主机等待从机应答释放 SDA 后拉高 SCL检测 SDA 是否被从机拉低ACK。若超时未应答则发送停止条件并返回错误uint8_t i2c_wait_ack(void) { uint8_t timeout 0; SCL 1; // 锁存数据使 SDA 保持稳定 delay_us(2); while (SDA_R) // 等待 SDA_R 变为 0 { timeout; if (timeout 250) { i2c_stop(); return 1; // 超时从机无应答 } } SCL 0; // 拉低时钟线允许对方继续发数据 return 0; }以从机地址0b01011107 位地址为例读取一个字节时主机先发送从机地址 读标志1即0b0101110 1随后等待从机应答再逐位读取数据。上述代码中的延时参数4us、2us已满足标准模式 100kHz 下建立时间 Tsu ≥ 4.7us、保持时间 Thd ≥ 4.0us、数据有效时间 ≥ 3.4us 的时序要求。6. 总结本文围绕 STM32 的 IIC 通信展开从协议基础到实际工程应用进行了系统梳理。核心要点可以归纳为以下几个方面协议层面IIC 是两线制、半双工的串行通信总线仅需 SDA 和 SCL 两根信号线。通信过程由起始条件START、从机地址、应答位ACK/NACK、数据字节和停止条件STOP组成数据在 SCL 高电平期间保持稳定、低电平期间变化。实现方式STM32 支持硬件 IIC 和软件模拟 IIC 两种方案。硬件 IIC 由芯片外设自动处理时序CPU 占用低、时序精确但配置复杂且部分型号存在兼容性问题软件模拟 IIC 通过 GPIO 翻转电平实现灵活通用但占用 CPU 资源较多。典型器件以 FM24CL04 铁电存储器FRAM为例其采用 IIC 接口写入无需等待写周期、擦写寿命高达 10 亿次非常适合频繁读写和掉电保护等场景。器件地址为 1010 A2 A1 A0通过 A0 位选择两个 256 字节存储区。工程实践STM32F4xx 的 I2C 控制器支持主机/从机模式、中断和 DMA 传输。开发时需正确配置 GPIO 复用功能、初始化 I2C 外设并通过 I2C_GetFlagStatus 和 I2C_ClearFlag 轮询与清除状态标志确保通信可靠。调试要点遇到总线忙、从机无应答、DMA 数据错位等问题时应优先检查地址、上拉电阻、时钟分频和中断优先级并借助逻辑分析仪或示波器观察 SDA/SCL 波形定位问题。总体而言IIC 协议本身并不复杂难点在于时序控制和异常处理。建议读者先通过软件模拟 IIC 理解协议细节再切换到硬件 IIC 提升效率并结合实际器件如 FM24CL04完成读写验证逐步掌握 STM32 的 IIC 开发。