F429-HAL-I2C读取AT24C02(2026/7/24)

📅 2026/7/24 21:34:06
F429-HAL-I2C读取AT24C02(2026/7/24)
目录一:I2C Init 字段逐个解析① Instance — 用哪个 I2C 硬件② AddressingMode — 7 位还是 10 位地址③ ClockSpeed — I2C 总线速率④ DualAddressMode — 双地址模式⑤ DutyCycle — 时钟占空比⑥ GeneralCallMode — 广播模式⑦ NoStretchMode — 时钟拉伸⑧ OwnAddress1 — STM32 自己作为从设备时的地址⑨ OwnAddress2 — 第二从设备地址跟 UART Init 对比二、HAL_I2C_Mem_Write / HAL_I2C_Mem_Read1: HAL_I2C_Mem_Write — 向设备的某个寄存器写入数据2: HAL_I2C_Mem_Read — 从设备的某个寄存器读取数据3: 跟 MPU6050 对比4: AT24C02 vs MPU6050 vs W25Q64三、轮询读写流程(阻塞模式)四、I2C 中断读写1: 轮询 vs 中断 新增内容对比2: 中断架构:EV 管正常,ER 管故障3: 中断写完整跳转链4: 中断读完整跳转链5: 错误路径6: 跟 UART IT 对比五、I2C DMA 读写1: F429 I2C1 的 DMA 映射2: 三轮模式新增内容对比3: DMA 完成后的中断链:两波中断,硬件链式触发4: IT 版 vs DMA 版对比5: 三种模式共用一个 main 框架六、实战踩坑:I2C 回调函数名(两个 bug)Bug 1:多了一个下划线Bug 2:Master 和 Mem 是两个家族一:I2C Init 字段逐个解析① Instance — 用哪个 I2C 硬件.Instance = I2C1;STM32F429 有三个 I2C 外设:I2C1、I2C2、I2C3。这块板子 AT24C02 接在 I2C1 上(PB6=SCL,PB7=SDA)。跟huart1.Instance = USART1一样——选了硬件编号。② AddressingMode — 7 位还是 10 位地址.AddressingMode = I2C_ADDRESSINGMODE_7BIT;模式地址范围场景7 位0~127绝大多数芯片,AT24C02 就是 0x50(7 位)10 位0~1023极少见,地址不够用时才用器件地址 0xA0 是加上读写位之后的值。纯 7 位地址是 0x50,左移一位最低位放 R/W → 变成 0xA0(写)/ 0xA1(读)。③ ClockSpeed — I2C 总线速率.ClockSpeed = 400000; // 400 KHz模式速率场景标准模式 (Standard)100 KHz低速、长距离快速模式 (Fast)400 KHz最常用快速+ (Fast Plus)1 MHz手册说有,实际不常用400KHz 对应一个时钟周期 2.5us。④ DualAddressMode — 双地址模式.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 关闭STM32 自己是 I2C 主设备,也可以被别的设备呼叫。这个字段的意思是"要不要同时响应两个I2C 地址"。DISABLE→ 只响应 OwnAddress1(0x0A)ENABLE→ 同时响应 OwnAddress1 和 OwnAddress2做主设备去读 EEPROM,开着没用,关掉就行。只有 STM32 被当从设备时才需要。⑤ DutyCycle — 时钟占空比.DutyCycle = I2C_DUTYCYCLE_2;只对快速模式(400KHz)有意义:选项时钟低:高说明DUTYCYCLE_22:1低电平 2 份,高电平 1 份 →标准选择DUTYCYCLE_16_916:9低电平更长,给慢速设备更多反应时间AT24C02 用DUTYCYCLE_2就行。⑥ GeneralCallMode — 广播模式.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 关闭广播 = 主设备向地址0x00发消息,总线上所有从设备一起响应。工程只有 EEPROM 一个从设备,不需要广播,关掉。⑦ NoStretchMode — 时钟拉伸.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 允许从设备拉慢时钟时钟拉伸(Clock Stretching):从设备来不及处理数据时,可以把SCL 线拉低,让主设备等着。处理完了释放 SCL,主设备才能继续发下一个字节。主设备: [发数据]→[想发下一个]→咦 SCL 被从设备拉低?→等着→SCL 释放→继续 从设备: 收到数据 → 来不及处理 → 拉低 SCL → 处理完了 → 释放 SCLDISABLE = 允许拉伸(等待),ENABLE = 禁止拉伸(不等人)。AT24C02 写一个字节后要等 5ms 才能再写——在这个间隙它会拉低 SCL。如果关了拉伸,主设备不等就发,写入失败。所以必须 DISABLE。⑧ OwnAddress1 — STM32 自己作为从设备时的地址.OwnAddress1 = I2C_OWN_ADDRESS7; // 0x0A这个在 EEPROM 读写场景中根本用不到——你是主设备去读别人。但如果哪天真有一块板子要当 I2C 从设备给别人读,那别人就用 0x0A 这个地址来找它。现在随便填个值就行。⑨ OwnAddress2 — 第二从设备地址.OwnAddress2 = 0; // 没用,填 0双地址模式关了,这个值无效。跟 UART Init 对比UART Init I2C Init ─────── ──────── .Instance = USART1 .Instance = I2C1 ← 同一套路 .BaudRate = 115200 .ClockSpeed = 400000 ← 波特率 vs 时钟速率 .WordLength = 8B .AddressingMode = 7BIT ← 数据位 vs 地址位 .StopBits = 1 .DutyCycle = 2 ← 都不复杂 .Parity = NONE .GeneralCall = DISABLE ← 都用不到的关掉 .Mode = TX_RX .DualAddress = DISABLE ← 都用不到的关掉还是老规矩——填结构体 → 调HAL_I2C_Init→ 完事。跟 UART、DMA 一个模子刻出来的。二、HAL_I2C_Mem_Write / HAL_I2C_Mem_Read1: HAL_I2C_Mem_Write — 向设备的某个寄存器写入数据HAL_I2C_Mem_Write(I2C_Handle, EEPROM_ADDRE