资讯动态

STM32F103 I2C读写AT24C02实战:从硬件到代码的完整避坑指南

发布时间:2026/10/7 1:16:28 来源:尧图企业网站定制
I2C 总线在嵌入式开发里属于那种看起来简单、用起来处处是细节的典型。STM32F103 加 AT24C02 这个组合几乎是每个学单片机的人都会碰到的练手项目但真正把它跑稳、跑明白的人并不多。我见过太多人卡在能读能写但偶尔出错换个芯片就不工作上电第一次读全是 0xFF这类问题上最后只能靠反复复位凑合。这篇内容就把 STM32F103 通过 I2C 读写 AT24C02 的完整链路拆开讲从硬件上拉电阻怎么算、时序到底卡在哪、HAL 库和寄存器两种写法怎么选到页写边界、写周期等待、应答轮询这些实战里最容易翻车的地方全部摊开说清楚。不管你是刚接触 I2C 的新手还是已经能跑通但想搞清楚底层原理的老手都能从里面找到能直接抄作业的配置和排查思路。1. 先搞清楚 AT24C02 到底是个什么脾气很多人拿到 AT24C02 就直接照着例程写代码结果一遇到连续写入或者跨页就出问题。根本原因是没有先把这个芯片的存储结构和访问规则吃透。AT24C02 是 2Kbit 容量的 EEPROM换算成字节就是 256 字节内部按 32 页组织每页 8 字节。这个页的概念是后面所有坑的源头必须先记住。1.1 存储结构与地址映射AT24C02 的 256 字节地址范围是 0x00 到 0xFF一个字节的地址就能覆盖所以它的设备地址里不包含页地址位。设备地址是 7 位高 4 位固定为 1010接下来 3 位由 A2、A1、A0 三个引脚决定。也就是说同一条 I2C 总线上最多可以挂 8 片 AT24C02地址从 0x50 到 0x57。这里有个新手特别容易搞混的点HAL 库里的设备地址参数是左移一位之后的 8 位值也就是 0xA0 到 0xAE 的偶数序列。如果你直接填 0x50HAL 会把它当成 0x50 这个 8 位地址去发实际通信必然失败。读写操作码藏在设备地址的最低位写操作是 0读操作是 1。所以写的时候发 0xA0读的时候发 0xA1。这个细节在寄存器操作时需要自己拼用 HAL 库的话库函数会帮你处理但理解它对于看时序图和抓波形非常关键。1.2 字节写、页写与写周期AT24C02 支持两种写模式字节写和页写。字节写就是一次写一个字节页写是一次最多写 8 个字节但前提是这 8 个字节必须落在同一页内。什么叫同一页地址除以 8 取整相同的就属于同一页。比如地址 0x00 到 0x07 是第一页0x08 到 0x0F 是第二页。如果你从地址 0x06 开始连续写 8 个字节写到第 3 个字节时地址会回卷到 0x00把第一页开头的数据覆盖掉。这个回卷行为是芯片硬件决定的不是 bug但如果你不知道就会莫名其妙发现数据被改了。写操作还有一个绕不开的参数写周期时间 tWR。AT24C02 在收到停止条件后内部会启动一个自定时擦写过程典型 5ms最大 5ms不同厂家略有差异有的标 10ms。在这段时间内芯片不会响应任何 I2C 请求你如果立刻发下一个读或写它会直接不回应答。正确的做法是发完写命令后延时 5ms 以上或者用应答轮询的方式检测芯片是否忙完。应答轮询更高效后面会详细讲。1.3 读操作的三种模式读比写要绕一些分当前地址读、随机读和顺序读三种。当前地址读是直接发读命令芯片从上次操作结束的地址加一处开始返回数据。随机读是先发一个写命令把目标地址写进去这叫伪写再发读命令。顺序读是在读的过程中连续给应答芯片地址自动递增直到你给非应答再发停止条件。这三种模式在实际项目里随机读用得最多顺序读适合批量读取连续数据。提示AT24C02 的地址指针在跨页时不会自动回卷到页首而是继续线性递增到 0xFF 后回卷到 0x00。这一点和页写的行为不同别搞混。2. 硬件连接里那些容易被忽略的细节软件写得再对硬件没处理好照样通信失败。I2C 是开漏总线这一点决定了它的外围电路和普通推挽输出完全不一样。很多人从 GPIO 点灯直接过渡到 I2C习惯性地把引脚配成推挽输出结果要么通信不上要么两个设备同时输出时烧引脚。2.1 上拉电阻的取值计算I2C 的 SDA 和 SCL 都必须接上拉电阻因为总线上的设备只能把线拉低不能主动拉高。上拉电阻的取值不是随便选个 4.7k 就完事它受两个因素约束上升时间和总线电容。标准模式 100kHz 下上升时间要求小于 1000ns快速模式 400kHz 下要求小于 300ns。总线电容由走线、引脚和器件输入电容组成经验值每米走线约 50pF每个器件引脚约 10pF。上升时间公式是 t R × C。假设总线电容 200pF要满足 300ns 上升时间R 最大约 1.5k。但电阻太小又会导致低电平时灌电流过大超过器件 3mA 的驱动能力。所以 4.7k 在短距离、低速场景下是稳妥选择走线长或者设备多的时候要降到 2.2k 甚至 1k。我实测过一块板子走线 15cm、挂两个器件用 10k 上拉在 100kHz 下勉强能通但波形上升沿明显变缓换成 4.7k 后眼图干净很多。2.2 电平匹配与电源去耦STM32F103 的 IO 是 3.3V 电平AT24C02 常见的是 5V 和 3.3V 两种版本。如果用的是 5V 版本直接连会有问题STM32 输出高电平 3.3V对 5V 器件来说可能达不到 VIH 门限。稳妥做法是选 3.3V 版本的 AT24C02或者加电平转换电路。另外 AT24C02 的 VCC 引脚旁边一定要放一个 0.1uF 的去耦电容紧贴芯片放置。EEPROM 在擦写瞬间电流会有波动没有去耦电容容易导致写失败或者数据出错这个坑我在早期项目里踩过加了电容之后偶发的写失败直接消失。2.3 引脚配置的正确姿势用 STM32F103 的硬件 I2C 时SCL 和 SDA 要配置成复用开漏模式而不是普通开漏。复用开漏是让片上外设接管引脚控制权普通开漏是 GPIO 自己控制。如果你配成普通开漏又用硬件 I2C外设根本控制不了引脚。用软件模拟 I2C 时两个引脚配成通用开漏输出输出高电平时靠外部上拉把线拉高输出低电平时拉低。这里有个细节开漏模式下读引脚电平前要先写 1否则读回来永远是 0。配置项硬件 I2C软件模拟 I2C引脚模式复用开漏通用开漏输出速度50MHz50MHz上拉电阻必需必需时钟控制外设自动代码延时控制3. 用 CubeMX 把 I2C 外设配明白现在大部分人用 STM32 都走 CubeMX 生成初始化代码这条路效率确实高但 CubeMX 里 I2C 的几个参数如果不懂含义生成出来的代码就是黑盒出了问题无从下手。这一节把关键配置项逐个说清楚。3.1 时钟源与时钟频率STM32F103 的 I2C1 挂在 APB1 总线上APB1 最高 36MHz。CubeMX 里 I2C 的 Clock Speed 参数指的是 SCL 的实际频率标准模式填 100000快速模式填 400000。但要注意这个频率能不能达到取决于 APB1 时钟和 I2C 时钟控制寄存器的分频配置。CubeMX 会自动算 CCR 和 TRISE 的值但前提是你 APB1 时钟设对了。如果 APB1 配成 36MHzI2C 配 400kHzCubeMX 算出来的 CCR 是 90实际 SCL 频率是 36M / (2×90) 200kHz达不到 400kHz。这是因为快速模式下 CCR 的计算公式和标准模式不同CubeMX 会按占空比 2:1 来配。想真正跑到 400kHzAPB1 得是 36MHz 且占空比设成 16:9CCR 约 30。3.2 占空比与滤波参数CubeMX 里有个 Fast Mode Duty Cycle 选项可选 2:1 或 16:9。2:1 占空比下高低电平时间比是 2:116:9 更接近 1:1。占空比越接近 1:1同样频率下留给上升沿的时间越充裕抗干扰能力越强。所以快速模式下建议选 16:9。另外 Analog Filter 和 Digital Filter 两个选项模拟滤波默认开数字滤波可以设 0 到 15 的系数。数字滤波能滤掉总线上的窄脉冲干扰走线长或者环境嘈杂时开大一点但开太大会影响高速通信的时序余量。一般设 0 或 1 就够。3.3 生成代码后的初始化检查CubeMX 生成的 MX_I2C1_Init 函数里重点看几个寄存器值。OAR1 是自身地址主机模式用不到随便填。CCR 是时钟控制TRISE 是最大上升时间标准模式填 APB1 时钟周期数加 1快速模式填 300ns 对应的周期数加 1。这些 CubeMX 都会算好但如果你改了 APB1 时钟忘了重新生成就会出错。我习惯生成后手动核对一遍 CCR 和 TRISE花不了一分钟能省掉后面大量调试时间。static void MX_I2C1_Init(void) { hi2c1.Instance I2C1; hi2c1.Init.ClockSpeed 100000; hi2c1.Init.DutyCycle I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 0; hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 0; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(hi2c1) ! HAL_OK) { Error_Handler(); } }4. HAL 库读写 AT24C02 的完整实现HAL 库把 I2C 的底层时序都封装好了用起来确实省事但它的 API 设计有几个地方和 AT24C02 的访问规则不完全匹配需要自己包一层。直接用 HAL_I2C_Mem_Write 和 HAL_I2C_Mem_Read 是最常见的做法但页写边界和写周期等待得自己处理。4.1 字节写与页写的代码实现HAL_I2C_Mem_Write 的原型是传入设备地址、内存地址、内存地址长度、数据指针、数据长度和超时。AT24C02 的内存地址是 1 字节所以 MemAddressSize 填 I2C_MEMADD_SIZE_8BIT。写一个字节很简单直接调就行。页写要注意不能跨页所以封装一个函数先算出当前地址到页尾还能写多少字节如果剩余数据超过这个数就分多次写。#define AT24C02_ADDR 0xA0 #define PAGE_SIZE 8 HAL_StatusTypeDef AT24C02_Write(uint16_t memAddr, uint8_t *data, uint16_t len) { HAL_StatusTypeDef status; uint16_t bytesWritten 0; while (bytesWritten len) { uint16_t pageRemain PAGE_SIZE - (memAddr % PAGE_SIZE); uint16_t writeLen (len - bytesWritten pageRemain) ? (len - bytesWritten) : pageRemain; status HAL_I2C_Mem_Write(hi2c1, AT24C02_ADDR, memAddr, I2C_MEMADD_SIZE_8BIT, data bytesWritten, writeLen, 100); if (status ! HAL_OK) return status; HAL_Delay(6); memAddr writeLen; bytesWritten writeLen; } return HAL_OK; }这段代码里 HAL_Delay(6) 就是等写周期。为什么是 6 而不是 5因为 5ms 是典型值留 1ms 余量防止边界情况。如果你追求效率可以把延时换成应答轮询每 100us 发一次伪写收到应答说明芯片忙完了这样平均等待时间能降到 1ms 左右。4.2 随机读与顺序读的实现读操作分两步先伪写目标地址再读数据。HAL_I2C_Mem_Read 内部会自动完成这个伪写过程所以直接调就行。顺序读就是读多个字节HAL 会自动处理地址递增和最后的非应答加停止条件。HAL_StatusTypeDef AT24C02_Read(uint16_t memAddr, uint8_t *data, uint16_t len) { return HAL_I2C_Mem_Read(hi2c1, AT24C02_ADDR, memAddr, I2C_MEMADD_SIZE_8BIT, data, len, 100); }看起来很简单但这里有个隐藏问题HAL_I2C_Mem_Read 在读之前会发一个写命令设置地址这个写命令本身不触发写周期所以不需要延时。但如果你在读之前刚做过写操作必须确保写周期已经结束否则读会失败。这就是为什么写函数里要延时而读函数里不用。4.3 应答轮询替代固定延时固定延时简单但浪费时间应答轮询更优雅。原理是EEPROM 在写周期内不响应任何地址你发一个伪写命令如果它回非应答说明还在忙如果回应答说明忙完了。实现上就是循环调用 HAL_I2C_IsDeviceReady这个函数内部就是发地址看有没有应答。HAL_StatusTypeDef AT24C02_WaitReady(uint32_t timeout) { uint32_t tickstart HAL_GetTick(); while (HAL_I2C_IsDeviceReady(hi2c1, AT24C02_ADDR, 3, 100) ! HAL_OK) { if ((HAL_GetTick() - tickstart) timeout) { return HAL_TIMEOUT; } } return HAL_OK; }把写函数里的 HAL_Delay(6) 换成 AT24C02_WaitReady(100)平均等待时间能降到 1 到 2ms批量写的时候效率提升很明显。实测写 256 字节固定延时方案要 256/8×6 192ms轮询方案大概 60ms 左右。5. 不用 HAL 库寄存器级操作长什么样用 HAL 库虽然方便但有些场景下你不得不用寄存器操作比如项目对代码体积敏感、需要精确控制时序、或者用的是没有 HAL 支持的老芯片。理解寄存器级操作也能帮你更好地排查 HAL 库出的问题。5.1 寄存器操作的基本流程STM32F103 的 I2C 外设有几个关键寄存器CR1 控制使能和中断CR2 设频率CCR 设时钟TRISE 设上升时间DR 是数据寄存器SR1 和 SR2 是状态寄存器。发送流程是发起始条件等 SB 置位发地址等 ADDR 置位发数据等 TXE 置位发停止条件。每一步都要轮询状态位超时了要报错。void I2C_WriteByte(uint8_t devAddr, uint8_t memAddr, uint8_t data) { while (I2C1-SR2 I2C_SR2_BUSY); I2C1-CR1 | I2C_CR1_START; while (!(I2C1-SR1 I2C_SR1_SB)); I2C1-DR devAddr 0xFE; while (!(I2C1-SR1 I2C_SR1_ADDR)); (void)I2C1-SR2; while (!(I2C1-SR1 I2C_SR1_TXE)); I2C1-DR memAddr; while (!(I2C1-SR1 I2C_SR1_TXE)); I2C1-DR data; while (!(I2C1-SR1 I2C_SR1_TXE)); I2C1-CR1 | I2C_CR1_STOP; }这段代码看着简单但有几个坑读 SR2 是为了清除 ADDR 标志不读的话后面会卡死TXE 置位表示数据寄存器空可以写下一个字节BTF 置位表示字节传输完成发停止条件前最好等 BTF否则最后一个字节可能没发完就停了。5.2 寄存器操作与 HAL 库的取舍寄存器操作的优势是可控性强、代码体积小、时序精确。劣势是容易出错、移植性差、开发效率低。我的建议是学习阶段用寄存器操作把流程走一遍理解每个状态位的含义实际项目用 HAL 库把精力放在业务逻辑上。如果 HAL 库出了问题你有寄存器操作的经验看波形和状态寄存器就能快速定位。对比项HAL 库寄存器操作开发效率高低代码体积大小时序控制一般精确可移植性好差排错难度中高6. 那些年我踩过的 I2C 读写坑前面讲的都是应该怎么做这一节讲实际做的时候会出什么幺蛾子。这些问题在文档里基本不会写但实际项目中几乎都会遇到。6.1 上电第一次读全是 0xFF这个现象特别常见原因是 EEPROM 出厂时所有字节都是 0xFF你如果没写过就直接读读回来当然是 0xFF。但很多人会误以为是通信失败。判断方法很简单读设备地址看有没有应答有应答说明通信正常数据是 0xFF 只是没写过而已。解决办法是在初始化时写一个标志字节比如在地址 0x00 写 0xAA下次上电读这个字节如果是 0xAA 说明初始化过了否则执行初始化。6.2 连续写跨页导致数据错乱前面提过页写回卷的问题这里给个具体例子。假设你要从地址 0x06 写 8 个字节数据是 1 到 8。实际写入结果是地址 0x06 写 10x07 写 2然后地址回卷到 0x00 写 30x01 写 4依此类推。最后 0x00 到 0x05 的数据被覆盖0x06 和 0x07 是 1 和 2。如果你没做跨页处理数据就乱了。解决办法就是前面写的分页写函数每次写到页尾就停等写周期后再写下一页。6.3 写周期未等待导致后续操作失败这个坑的典型表现是写一个字节后立刻读读回来还是旧数据。原因是写周期还没结束芯片没响应读命令HAL 库返回错误或者返回旧值。很多人以为是读函数写错了其实是写周期没等。解决办法就是加延时或者用应答轮询。我建议用轮询因为延时时间不好把握不同厂家的芯片写周期不一样有的标 5ms 实际 3ms有的标 5ms 实际 6ms轮询能自适应。6.4 总线死锁与恢复I2C 总线有个经典问题如果主机在发送过程中复位从机可能还在等时钟把 SDA 拉低不放导致总线死锁。表现是 SCL 和 SDA 都高不了后续所有通信失败。恢复方法是在 SCL 上手动发 9 个时钟脉冲让从机把剩余数据发完释放 SDA然后发一个停止条件。STM32 的 I2C 外设有总线恢复机制但有时候不生效需要手动用 GPIO 模拟时钟来恢复。void I2C_BusRecovery(void) { GPIO_InitTypeDef gpio {0}; gpio.Pin GPIO_PIN_6 | GPIO_PIN_7; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, gpio); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); for (int i 0; i 9; i) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); HAL_Delay(1); } HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET); HAL_Delay(1); MX_I2C1_Init(); }6.5 多设备挂载时的地址冲突同一条总线上挂多个 AT24C02 时A0 到 A2 引脚不能悬空必须明确接 VCC 或 GND。悬空时引脚电平不确定设备地址可能随机变化导致通信时好时坏。我见过一个案例两块 EEPROM 的 A0 都悬空结果上电后地址随机有时候能读有时候不能读查了半天才发现是引脚没接。另外如果总线上还挂了其他 I2C 设备要确保地址不冲突比如 OLED 常用 0x78和 AT24C02 的 0x50 到 0x57 不冲突但有些传感器地址可能撞车选型时要查清楚。7. 用逻辑分析仪抓波形来验证时序代码写完了不代表就对了用逻辑分析仪抓一下波形能直观看到时序是否符合预期。我用的是一款几十块的 8 通道逻辑分析仪配合开源软件就能解码 I2C 协议非常方便。7.1 抓包看什么抓 I2C 波形主要看几个点起始条件是否干净地址字节是否正确应答位是否正常数据字节是否符合预期停止条件是否完整。如果地址字节发出去后没有应答说明设备地址错了或者设备没上电。如果数据字节和预期不符可能是页写回卷或者写周期没等。如果波形上升沿很缓说明上拉电阻太大或者总线电容太大。7.2 一个典型的写时序波形分析以写一个字节到地址 0x10 为例波形上应该看到起始条件SCL 高时 SDA 下降然后 8 位地址 0xA0第 9 位是应答SDA 被从机拉低然后 8 位内存地址 0x10应答然后 8 位数据应答最后停止条件SCL 高时 SDA 上升。整个过程 SCL 是连续的时钟脉冲SDA 在 SCL 高电平期间必须稳定。如果 SDA 在 SCL 高电平期间跳变那就是起始或停止条件不是数据。7.3 用示波器看上升沿逻辑分析仪看协议示波器看电气特性。如果通信不稳定用示波器看 SDA 和 SCL 的上升沿测量从 0.3VCC 到 0.7VCC 的时间。标准模式要求小于 1000ns快速模式小于 300ns。如果超了减小上拉电阻或者缩短走线。另外看低电平是否接近 0V如果低电平偏高说明灌电流能力不足或者地线有问题。8. 从 AT24C02 延伸到其他 EEPROM 和 I2C 设备把 AT24C02 玩明白之后换其他 EEPROM 或者 I2C 设备就是改改参数的事。但有几个差异点需要注意不然换个芯片就翻车。8.1 AT24C02 与 AT24C256 的差异AT24C256 是 32K 字节容量内存地址是 2 字节所以 HAL_I2C_Mem_Write 的 MemAddressSize 要改成 I2C_MEMADD_SIZE_16BIT。页大小也从 8 字节变成 64 字节。设备地址的高 4 位还是 1010但 A2 到 A0 的含义变了因为地址位多了部分地址位被挪到设备地址里。具体要看数据手册不同型号规则不一样。写周期时间也变长了AT24C256 典型 5ms 但最大 10ms延时或者轮询的超时要相应放宽。8.2 其他常见 I2C 设备的地址规律I2C 设备的 7 位地址一般分两部分高 4 位是厂家和型号标识低 3 位是引脚配置。比如 OLED 的 SSD1306 常用 0x3C 或 0x3D取决于 SA0 引脚。温度传感器 LM75 是 0x48 到 0x4F。实时时钟 PCF8563 是 0x51。这些地址在选型时要统一规划避免冲突。如果实在避不开可以用 I2C 多路复用器扩展总线但会增加成本和复杂度。8.3 软件模拟 I2C 的适用场景硬件 I2C 虽然方便但有些情况下不得不用软件模拟比如引脚被其他功能占用了或者需要在不支持硬件 I2C 的芯片上实现或者硬件 I2C 有 bugSTM32F103 早期的硬件 I2C 确实有一些已知问题。软件模拟 I2C 就是用 GPIO 加延时来产生时序灵活性高但占用 CPU 时间。实现时注意延时要用精确的微秒延时不能用 HAL_Delay因为 HAL_Delay 是毫秒级的太粗。void I2C_Delay(void) { for (volatile int i 0; i 10; i); } void I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); I2C_Delay(); SDA_LOW(); I2C_Delay(); SCL_LOW(); I2C_Delay(); }软件模拟的时序参数要根据从机手册来调延时太长通信慢太短从机反应不过来。一般 100kHz 下每个时钟周期 10us高低电平各 5us用循环延时能凑出来。但要注意编译器优化可能会把空循环优化掉加 volatile 关键字防止优化。9. 项目实战中的经验总结做了这么多项目关于 STM32F103 读写 AT24C02有几个经验是文档里不会写但特别有用的。第一初始化时先做一次全片检测。读设备地址看应答再读几个固定地址看数据是否合理。如果读回来全是 0xFF可能是新芯片也可能是通信失败要结合应答位判断。我习惯在初始化时写一个魔数到固定地址下次上电校验这样能区分新芯片和通信故障。第二写操作一定要做超时保护。HAL 库的函数都有超时参数别图省事填 HAL_MAX_DELAY那样出问题会死等。填 100ms 足够超时了返回错误让上层处理。我见过一个项目因为 I2C 超时填了最大值结果总线出问题时整个系统卡死看门狗都救不回来。第三数据存储要做校验。EEPROM 虽然可靠但极端情况下也会出错。重要数据加个 CRC 校验读出来先校验再使用。如果校验失败回退到默认值或者备份数据。这个习惯在工业项目里特别重要消费类项目可以酌情简化。第四批量写的时候尽量按页对齐。虽然分页写函数能处理任意地址和长度但按页对齐能减少写周期次数提高效率。比如要写 16 个字节从页首开始写两次页写就行从页中间开始可能要写三次。设计数据结构时把经常一起读写的数据放在同一页能明显提升性能。第五调试阶段多用断言和日志。I2C 通信失败的原因很多光看返回值不够。在关键步骤加日志记录设备地址、内存地址、数据长度和返回值出问题时能快速定位。量产时可以把日志关掉但调试阶段千万别省这个事。注意AT24C02 的擦写寿命是 100 万次读次数无限。如果项目里有频繁写 EEPROM 的需求要做磨损均衡或者用 FRAM 替代。我见过一个项目每秒写一次 EEPROM不到一个月芯片就坏了换成 FRAM 后问题解决。最后说个实际案例。之前做一个数据采集器用 AT24C02 存配置参数现场部署后偶尔出现配置丢失。查了很久发现是写配置时没等写周期紧接着读校验读回来是旧数据程序以为写失败就重试反复写导致芯片寿命耗尽。后来改成写后轮询等待问题彻底解决。这个案例说明I2C 读写 EEPROM 的坑往往不在通信本身而在对芯片时序特性的理解上。把写周期、页边界、应答机制这几个点吃透基本就能避开 90% 的问题。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑