)
文章目录一、IIC 简介1、IIC2、IIC 核心硬件特点3、两根总线功能详解4、IIC 通信层级角色5、典型应用场景二、IIC 模块详解1、IIC功能框图① 物理引脚接口区橙色② 时钟生成模块浅紫色③ 数据收发与地址校验模块绿色核心数据通路④ 全局控制与状态中断模块黄色顶层调度2、模块工作原理3、IIC 通信速率4、硬件IIC 与 软件IIC 区别三、CubeMX 标准 IIC 配置步骤1、基础配置1.Master Features 主机配置板块2.Slave Features 从机配置板块2、中断配置1. I2C1 event interruptI2C1 事件中断2. I2C1 error interruptI2C1 错误中断3、关键配置参数4、配置注意事项四、IIC编程模块1、IIC数据结构1.IIC句柄结构体2.IIC初始化结构体2、HAL_IIC_API1.阻塞轮询模式 Blocking mode: Polling线程同步占用CPU直到传输完成2.非阻塞中断模式 Non-Blocking mode: Interrupt函数立即返回传输靠中断完成3.非阻塞DMA模式 Non-Blocking mode: DMA零CPU搬运高速大批量传输4.中断服务入口函数IT.c中全局中断调用5.用户重写回调函数中断/DMA传输完成/故障触发用户自定义业务6.状态/模式/错误查询API五、IIC 应用实例1、硬件原理图EEPROM2、EEPROM设备地址3、CubeMX配置1. RCC 时钟配置2. I2C1 Parameter Settings 参数配置3. NVIC 中断配置4. DMA Settings5. GPIO Settings6. 工程生成设置4、工程源码1.eeprom.h 头文件2. eeprom.c 功能源码3.main.c 测试调用示例5、实验结果六、IIC 核心要点与避坑大全1、核心知识点2、高频坑点新手必错3、工程最优解决方案4、总结七、全篇总结一、IIC 简介1、IICIICInter-Integrated Circuit集成电路总线常写为I2C是一种低速、半双工、同步串行通信总线专为板内短距离设备通信设计是嵌入式最常用的传感器通信协议之一。IIC 仅需两根信号线即可实现多设备组网极大节省单片机引脚资源广泛用于各类传感器、EEPROM、RTC、OLED、气压、温湿度等外设通信。2、IIC 核心硬件特点双线通信SCL时钟线、SDA数据线。半双工通信同一时间只能收或发不能同时收发。同步通信通信时序完全跟随 SCL 时钟节拍。多主多从架构一条总线挂载多个设备依靠设备地址区分通信对象。开漏输出必须外接上拉电阻总线空闲时保持高电平。无片选引脚依靠软件地址寻址节省硬件引脚。3、两根总线功能详解SCLSerial Clock时钟线由主机产生时钟信号控制通信速率与时序。SDASerial Data数据线双向传输数据、地址、应答信号。4、IIC 通信层级角色主机MasterSTM32单片机负责产生时钟、发起通信、控制总线。从机Slave传感器、EEPROM、OLED等外设被动响应主机指令。5、典型应用场景传感器采集温湿度、气压、陀螺仪、加速度计。存储设备AT24C02 EEPROM 数据存储。显示设备IIC 协议 OLED 屏幕。板内低速近距离数据交互。二、IIC 模块详解1、IIC功能框图① 物理引脚接口区橙色外部总线输入输出端口3 根硬件引脚SDA串行数据双向传输地址 数据 应答位。SCL串行时钟同步总线时序。SMBASMBus 专用告警引脚标准 I2C 场景悬空不使用。功能连接外部 I2C 总线完成电平采样与驱动输出。② 时钟生成模块浅紫色负责生成标准 100kHz/400kHz SCL 时钟时钟控制寄存器CCR对 APB1 时钟分频配置 SCL 通信速率、400kHz 占空比。时钟控制逻辑处理时钟拉伸、总线同步、多主机仲裁时序。输出 SCL 时序给到数据控制模块同步 8bit 移位传输。时钟计算公式计算实例 PCLK136MHz想要配置400Kbit/s的速率计算方式如下 PCLK时钟周期 TPCLK1 1/36000000。 目标SCL时钟周期 TSCL 1/400000。 SCL时钟周期内的高电平时间 THIGH TSCL/3。 SCL时钟周期内的低电平时间 TLOW 2*TSCL/3。 计算CCR的值 CCR THIGH/TPCLK1 30。③ 数据收发与地址校验模块绿色核心数据通路完整实现 I2C 字节收发、地址匹配、PEC 硬件校验内部子模块核心功能数据寄存器 DR读写缓冲CPU 读写的唯一数据交互寄存器写 发送读 接收数据移位寄存器硬件自动完成 8bit 串行移位无需 CPU 逐位操作 SDA比较器匹配总线地址与本机地址寄存器匹配成功置 ADDR 标志自身地址寄存器 OAR1存储本机 7/10 位从机地址双地址寄存器 OAR2第二路从机地址实现双地址同时响应PEC 计算单元 PEC 寄存器SMBus 硬件 CRC8 校验存储校验结果数据控制逻辑控制 SDA 电平、应答 ACK/NACK、起始 / 停止信号时序④ 全局控制与状态中断模块黄色顶层调度I2C 外设总控单元对接 CPU 内核、中断、DMA控制寄存器CR1CR2外设总开关 PE、中断使能、DMA 开关、START/STOP 信号、应答控制。状态寄存器SR1SR2存储事件标志 (SB/ADDR/TxE/RxNE)、错误标志 (BERR/AF/ARLO)、主机 / 总线状态。控制逻辑核心统筹全部模块时序产生中断信号、DMA 握手、ACK 控制信号。2、模块工作原理时钟来源APB1 外设时钟通过 CCR 寄存器分频得到标准 100kHz/400kHz SCL电平机制双线开漏总线仅能拉低引脚靠外部上拉电阻拉高主机模式流程主机发送 S 起始信号→发送 7/10 位从地址 读写位→等待从机 ACK 应答→收发 N 字节数据→发送 P 停止信号从机模式流程总线检测 S 信号接收地址与 OAR 寄存器本机地址对比匹配后产生应答等待主机读写数据仲裁机制多主机同时发送数据时若主机输出高电平但总线被其他主机拉低判定仲裁失败立即停止传输并置 ARLO 标志时钟拉伸从机处理数据未就绪时拉低 SCL主机停止发送直到从机释放 SCL 继续传输应答机制每传输 8bit 数据后接收方拉低 SDA 产生 ACK高电平为 NACK主机读最后一字节时发送 NACK 告知从机传输结束。3、IIC 通信速率标准模式100Kbit/s默认标配。快速模式400Kbit/s大部分传感器支持。高速模式3.4Mbit/s极少使用。4、硬件IIC 与 软件IIC 区别对比项硬件IIC软件模拟IIC实现方式片上外设硬件时序无需CPU干预GPIO模拟高低电平软件延时时序占用资源占用硬件IIC引脚CPU占用低任意GPIO占用CPU资源高稳定性F103硬件IIC存在BUG易卡死时序灵活、兼容性强、极度稳定速率速度快最高400K速度慢延时可控工程使用极少使用F1通病项目90%使用软件模拟IIC三、CubeMX 标准 IIC 配置步骤1、基础配置1.Master Features 主机配置板块CubeMX 配置项当前取值映射 HAL 结构体字段详细说明I2C Speed ModeStandard Mode标准模式I2C_InitTypeDef.ClockSpeed标准模式速率上限 100kHz电磁兼容性更强走线较长、环境干扰偏大的场景适配性好备选 Fast Mode 可达到 400kHz适合短走线高速刷屏 OLEDI2C Clock Speed (Hz)100000I2C_InitTypeDef.ClockSpeed设置 SCL 时钟频率为 100kHzF103 APB136MHz 时硬件分频可以稳定输出该速率是工业 I2C 外设通用保守速率Duty Cycle Fast ModeI2C_InitTypeDef.DutyCycle400kHz 时钟高低电平占空比 DutyCycle_2 / DutyCycle_16_9选 16_9 适配 SSD13062.Slave Features 从机配置板块**CubeMX **配置项当前取值映射** HAL **结构体字段详细说明Clock No Stretch ModeDisabledI2C_InitTypeDef.NoStretchMode关闭禁止时钟拉伸允许从设备通过拉低 SCL 放缓时钟SSD1306、24C02 处理数据耗时较长开启时钟拉伸能够大幅降低应答失败的概率日常不要修改为 EnabledPrimary Address Length selection7-bitI2C_InitTypeDef.AddressingMode主本机从地址采用业界通用 7bit 格式绝大多数 I2C 外设OLED、EEPROM、各类传感器全部使用 7 位地址10bit 拓展地址极少用到Dual Address AcknowledgedDisabledI2C_InitTypeDef.DualAddressMode禁用第二路从地址 OAR2只有 MCU 自身需要响应两个不同 I2C 从地址的场景才启用作为主机操控外设时无需开启Primary slave address0I2C_InitTypeDef.OwnAddress1MCU 自身充当从机的主地址主机模式必须填 0主机不会被外部设备寻址填写非零值反而会引发总线地址冲突General Call address detectionDisabledI2C_InitTypeDef.GeneralCallMode关闭广播地址 0x00 检测广播模式适配多从机批量下发指令的特殊工业场景常规项目关闭可以减少多余中断触发2、中断配置1. I2C1 event interruptI2C1 事件中断触发场景出现正常传输类事件时触发涵盖起始发送完成、从机地址匹配、发送缓冲区为空、接收缓冲区存有数据、字节传输完成等常规通信流程事件使用场景仅采用中断模式_IT后缀 API、DMA 模式进行 I2C 收发才需要勾选开启如果日常使用阻塞轮询形式HAL_I2C_Master_Transmit这类轮询 API无需启用该项2. I2C1 error interruptI2C1 错误中断触发场景出现总线异常才触发包含 BERR 总线错误、AF 从机无应答、ARLO 多主机仲裁丢失、OVR 接收溢出等故障情况使用场景想要借助中断捕获 I2C 通信异常、做故障自愈逻辑时开启纯轮询开发时可以关闭代码主动调用HAL_I2C_GetError()即可排查故障3、关键配置参数Clock Speed100000100K通用配置。Duty Cycle2:1 标准占空比。自身从地址主机模式可默认0x00。4、配置注意事项IIC总线必须外接4.7K~10K上拉电阻否则通信异常。STM32F103硬件IIC存在硬件缺陷大批量项目建议用软件IIC。多条IIC设备挂载时必须保证设备地址不冲突。通信速率不宜过高否则容易丢包、无应答。四、IIC编程模块1、IIC数据结构1.IIC句柄结构体typedef struct __I2C_HandleTypeDef { I2C_TypeDef *Instance; // 外设寄存器基地址 I2C_InitTypeDef Init; // I2C时序、模式配置参数 HAL_LockTypeDef Lock; // 多线程互斥锁防止并发访问冲突 __IO HAL_I2C_StateTypeDef State; // 外设实时运行状态机 __IO uint32_t ErrorCode; // 硬件故障错误标志寄存器 DMA_HandleTypeDef *hdmatx; // 发送DMA句柄DMA收发时绑定 DMA_HandleTypeDef *hdmarx; // 接收DMA句柄DMA收发时绑定 HAL_I2C_CallbackTypeDef TxCpltCallback; // 发送完成用户回调函数指针 HAL_I2C_CallbackTypeDef RxCpltCallback; // 接收完成用户回调函数指针 HAL_I2C_CallbackTypeDef ErrorCallback; // 传输错误用户回调函数指针 HAL_I2C_CallbackTypeDef AbortCallback; // 传输中止用户回调函数指针 } I2C_HandleTypeDef;2.IIC初始化结构体typedef struct { uint32_t ClockSpeed; // I2C SCL总线时钟速率 uint32_t DutyCycle; // 400K快速模式时钟占空比 uint32_t OwnAddress1; // 本机从机7/10位地址 uint32_t AddressingMode; // 本机从地址位宽模式 uint32_t Mode; // 通信协议标准I2C / SMBus uint32_t NoStretchMode; // 时钟拉伸使能开关 uint32_t OwnAddress2; // 第二路本机从地址双地址从机模式 uint32_t DualAddressMode; // 双从地址匹配开关 } I2C_InitTypeDef;2、HAL_IIC_API1.阻塞轮询模式 Blocking mode: Polling线程同步占用CPU直到传输完成HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能I2C主机阻塞发送批量数据自动生成起始信号从机写地址数据停止信号Timeout超时未完成返回HAL_TIMEOUTOLED发指令/数据底层基础接口。 HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能I2C主机阻塞读取从机数据自动处理ACK/NACK应答时序适合读取传感器寄存器。 HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能I2C从机模式阻塞发送数据MCU作为从设备时使用OLED/24C02主机工程几乎不用。 HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能I2C从机模式阻塞接收主机下发数据仅多MCU互联从机场景使用。 HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能主机带片内寄存器地址阻塞写入自动时序起始→设备写地址→内部存储地址→用户数据→停止适配24C02、带寄存器的OLED、温感芯片。 HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout); 功能主机带片内寄存器地址阻塞读取自动生成重复起始信号切换读写方向是EEPROM读取专用接口。 HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout); 功能循环发送从机地址检测设备ACK应答判断I2C外设是否在线硬件调试排查无应答故障专用。2.非阻塞中断模式 Non-Blocking mode: Interrupt函数立即返回传输靠中断完成基础收发HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); 功能主机中断异步发送不阻塞主循环全部数据发送完毕触发HAL_I2C_MasterTxCpltCallback回调。 HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); 功能主机中断异步接收收到指定长度数据后进入HAL_I2C_MasterRxCpltCallback。 HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); 功能从机中断异步发送仅多MCU主从互联场景使用。 HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); 功能从机中断异步接收主机数据。 HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); 功能中断模式带内部地址写入寄存器型外设完成触发HAL_I2C_MemTxCpltCallback。 HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); 功能中断模式带内部地址读取寄存器型外设完成触发HAL_I2C_MemRxCpltCallback。序列分段传输Seq自定义起始/停止时序多帧复合通信HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能中断序列发送XferOptions自定义传输规则传输后是否发停止、重复起始适配复杂多段I2C时序。 HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能中断序列接收可控制传输结束是否发送NACK/停止信号。 HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能从机中断序列发送。 HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint16_t XferOptions); 功能从机中断序列接收。从机监听、传输中止HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c); 功能开启从机地址监听中断等待主机访问本机从地址匹配地址触发AddrCallback。 HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c); 功能关闭从机地址监听中断不再响应主机寻址。 HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress); 功能中止当前正在进行的中断异步传输强制释放总线传输中止完成触发AbortCpltCallback。3.非阻塞DMA模式 Non-Blocking mode: DMA零CPU搬运高速大批量传输基础DMA收发HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); 功能主机DMA异步发送数据由DMA硬件直接搬运至I2C_DRCPU全程不参与OLED全屏刷屏最优接口。 HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); 功能主机DMA异步接收硬件自动搬运总线数据至内存数组。 HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); 功能从机DMA发送。 HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size); 功能从机DMA接收。 HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); 功能DMA模式带内部地址写入寄存器外设大批量EEPROM页写入专用。 HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size); 功能DMA模式带内部地址读取寄存器外设。DMA序列分段传输HAL_StatusTypeDef HAL_I2C_Master_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能DMA序列发送自定义停止/重复起始时序。 HAL_StatusTypeDef HAL_I2C_Master_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能DMA序列接收自定义应答、停止时序。 HAL_StatusTypeDef HAL_I2C_Slave_Seq_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions); 功能从机DMA序列发送。 HAL_StatusTypeDef HAL_I2C_Slave_Seq_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint16_t XferOptions); 功能从机DMA序列接收。4.中断服务入口函数IT.c中全局中断调用void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c); 功能I2C事件中断总入口处理发送空、接收满、地址匹配、传输完成等事件自动分发对应完成回调。 void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c); 功能I2C错误中断总入口应答失败、总线错误、仲裁丢失时进入分发错误回调。5.用户重写回调函数中断/DMA传输完成/故障触发用户自定义业务主机收发完成回调void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c); 功能主机中断/DMA普通发送全部数据完成回调。 void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c); 功能主机中断/DMA普通接收指定长度数据完成回调。从机收发完成回调void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c); 功能从机发送数据完成回调。 void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c); 功能从机接收数据完成回调。从机地址匹配、监听完成回调void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode); 功能从机模式下主机寻址本机地址时触发参数区分读/写方向、匹配的本机地址。 void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c); 功能从机完整一帧主机读写传输结束回调。Mem寄存器读写专用完成回调void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c); 功能Mem_Write_IT/DMA带地址写入全部数据完成回调。 void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c); 功能Mem_Read_IT/DMA带地址读取全部数据完成回调。故障、传输中止回调void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c); 功能I2C硬件错误触发无应答AF、总线错误BERR、仲裁丢失ARLO、超时可读取HAL_I2C_GetError()判断故障类型。 void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c); 功能调用HAL_I2C_Master_Abort_IT()中止传输完成后触发。6.状态/模式/错误查询APIHAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c); 功能读取I2C外设当前运行状态就绪/发送忙/接收忙/错误/超时传输前判断总线是否空闲。 HAL_I2C_ModeTypeDef HAL_I2C_GetMode(I2C_HandleTypeDef *hi2c); 功能查询当前I2C工作模式主机模式/从机模式。 uint32_t HAL_I2C_GetError(I2C_HandleTypeDef *hi2c); 功能读取句柄内硬件错误标志位定位无应答、总线冲突、DMA故障等问题。五、IIC 应用实例1、硬件原理图EEPROM实现EEPROM指定地址写入、读取掉电保存数据.2、EEPROM设备地址EEPROM芯片的设备地址一共有7位其中高4位固定为1010 b 低3位则由A0/A1/A2信号线的电平决定。图 EEPROM设备地址 图中的R/W是读写方向位与地址无关。A0/A1/A2均为0EEPROM的7位设备地址是101 0000b即0x50。I2C通讯地址跟读写方向连在一起构成一个8位数当R/W位为0时表示写方向 加上7位地址其值为“0xA0”常称该值为“写地址”当R/W位为1时表示读方向 加上7位地址其值为“0xA1”常称该值为“读地址”。3、CubeMX配置1. RCC 时钟配置选择 HSE 外部高速晶振系统主频配置 72MHzAPB1 预分频系数设置为 2APB1 总线时钟最终得到 36MHz适配 I2C 外设时钟需求。2. I2C1 Parameter Settings 参数配置配置项设置值I2C Speed ModeStandard ModeI2C Clock Speed100000 HzClock No Stretch ModeDisabledPrimary Address Length selection7-bitDual Address AcknowledgedDisabledPrimary slave address0General Call address detectionDisabled3. NVIC 中断配置普通阻塞读写方案两个中断复选框全部保持未勾选状态若后续打算切换中断 / DMA 模式再勾选开启event interrupt与error interrupt。4. DMA Settings阻塞模式保持 DMA 关闭大批量页写入场景再配置 DMA1 通道。5. GPIO SettingsPB6、PB7 自动复用为 I2C 功能电气模式固定为复用开漏Alternate Open Drain硬件实物 SDA、SCL 需要外接 4.7kΩ 上拉电阻到 3.3V。6. 工程生成设置生成代码选择 HAL 库勾选生成独立.c/.h 文件。4、工程源码1.eeprom.h 头文件#ifndef __EEPROM_H #define __EEPROM_H #include main.h #include i2c.h /* 24C02基础宏定义 */ #define EEPROM_DEV_ADDR 0xA0U #define EEPROM_PAGE_SIZE 8U #define EEPROM_WRITE_DELAY_MS 5U #define EEPROM_CAPACITY 256U HAL_StatusTypeDef EEPROM_ByteWrite(uint8_t memAddr, uint8_t data); HAL_StatusTypeDef EEPROM_PageWrite(uint8_t startAddr, uint8_t *pData, uint8_t len); HAL_StatusTypeDef EEPROM_ByteRead(uint8_t memAddr, uint8_t *pData); HAL_StatusTypeDef EEPROM_BufferRead(uint8_t startAddr, uint8_t *pData, uint8_t len); HAL_StatusTypeDef EEPROM_CheckDevice(void); #endif2. eeprom.c 功能源码#include eeprom.h extern I2C_HandleTypeDef hi2c1; /** * brief 检测EEPROM设备是否在线 */ HAL_StatusTypeDef EEPROM_CheckDevice(void) { return HAL_I2C_IsDeviceReady(hi2c1, EEPROM_DEV_ADDR, 5U, 100U); } /** * brief 单字节写入EEPROM * param memAddr 片内存储地址 0~255 * param data 需要写入的单字节数据 */ HAL_StatusTypeDef EEPROM_ByteWrite(uint8_t memAddr, uint8_t data) { HAL_StatusTypeDef ret; ret HAL_I2C_Mem_Write(hi2c1, EEPROM_DEV_ADDR, memAddr, I2C_MEMADD_SIZE_8BIT, data, 1U, 100U); HAL_Delay(EEPROM_WRITE_DELAY_MS); return ret; } /** * brief 分页批量写入规避跨页覆盖数据的问题 */ HAL_StatusTypeDef EEPROM_PageWrite(uint8_t startAddr, uint8_t *pData, uint8_t len) { HAL_StatusTypeDef status HAL_OK; uint8_t writeLen; while(len 0U) { /* 计算当前页面剩余可写入字节 */ writeLen EEPROM_PAGE_SIZE - (startAddr % EEPROM_PAGE_SIZE); writeLen writeLen len ? len : writeLen; status HAL_I2C_Mem_Write(hi2c1, EEPROM_DEV_ADDR, startAddr, I2C_MEMADD_SIZE_8BIT, pData, writeLen, 100U); if(status ! HAL_OK) break; HAL_Delay(EEPROM_WRITE_DELAY_MS); startAddr writeLen; pData writeLen; len - writeLen; } return status; } /** * brief 读取单个字节 */ HAL_StatusTypeDef EEPROM_ByteRead(uint8_t memAddr, uint8_t *pData) { return HAL_I2C_Mem_Read(hi2c1, EEPROM_DEV_ADDR, memAddr, I2C_MEMADD_SIZE_8BIT, pData, 1U, 100U); } /** * brief 任意长度连续读取数据读取阶段不需要延时等待 */ HAL_StatusTypeDef EEPROM_BufferRead(uint8_t startAddr, uint8_t *pData, uint8_t len) { return HAL_I2C_Mem_Read(hi2c1, EEPROM_DEV_ADDR, startAddr, I2C_MEMADD_SIZE_8BIT, pData, len, 200U); }3.main.c 测试调用示例#include main.h #include i2c.h #include gpio.h #include eeprom.h #include stdio.h #include string.h /* 重定向printf */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; } uint8_t writeBuf[6] {0x10,0x20,0x30,0x40,0x50,0x60}; uint8_t readBuf[6]; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); // 1、检测EEPROM硬件是否在线 printf( AT24C02 EEPROM TEST \r\n); if(EEPROM_CheckDevice() HAL_OK) { printf(OK\r\n); // 2、分页批量写入EEPROM 0x00起始地址 EEPROM_PageWrite(0x00, writeBuf, 6); HAL_Delay(10); printf(DATA:); for(uint8_t i0; i6; i) { printf(0x%02X , writeBuf[i]); } printf(\r\n); // 3、从EEPROM读取数据 EEPROM_BufferRead(0x00, readBuf, 6); printf(DATA:); for(uint8_t i0; i6; i) { printf(0x%02X , readBuf[i]); } printf(\r\n); // 4、数据一致性校验 if(memcmp(writeBuf,readBuf, 6) 0) { printf(OK\r\n); } else { printf(ERR\r\n); } } else { printf(EEPROM ERROR!\r\n); } //16 字节一行批量打印全部 24C02 存储空间 /* uint8_t fullBuf[16]; for(uint8_t page0; page16; page) { EEPROM_BufferRead(page*16, fullBuf, 16); printf(地址0x%02X ~ 0x%02X, page*16, page*1615); for(uint8_t i0; i16; i) { printf(0x%02X , fullBuf[i]); } printf(\r\n); }*/ while (1) { // 循环间隔打印状态 HAL_Delay(2000); printf(Run......\r\n); } }5、实验结果六、IIC 核心要点与避坑大全1、核心知识点IIC为双线同步半双工通信SCL时钟、SDA数据。开漏输出必须外接上拉电阻总线空闲高电平。依靠设备地址寻址一条总线可挂载多个设备。通信核心时序起始、停止、应答、高位先行。F103硬件IIC有BUG工程优先使用软件模拟IIC。2、高频坑点新手必错未焊接上拉电阻导致总线电平异常、完全无法通信。设备地址读写位混淆写地址、读地址错位导致无应答。硬件IIC卡死、总线忙死锁无法恢复通信。超时时间设置过短高速通信频繁报错。多设备挂载地址冲突数据接收错乱。读写寄存器后未加延时外设未完成操作导致读取错误。3、工程最优解决方案STM32F1系列放弃硬件IIC全程使用软件IIC。统一封装寄存器读写函数适配所有IIC传感器。通信失败增加重试机制提升稳定性。每次读写操作增加适当延时适配低速外设。设备上电后先检测设备在线状态再执行通信。4、总结IIC是双线同步半双工串行总线依靠SCL时钟、SDA数据实现多设备组网通信通过设备地址寻址具备起始、停止、应答标准时序资源占用少、扩展性强是嵌入式传感器、存储设备最主流的低速通信协议。七、全篇总结IIC 是嵌入式开发使用频率最高的通信协议几乎所有传感器均基于IIC协议开发。掌握IIC时序原理、CubeMX配置、寄存器读写API、工程避坑方案、软件IIC替代思路即可完成99%的传感器、OLED、EEPROM项目开发是嵌入式进阶的核心必备技能。