第4章 EEPROM器件选型:AT24C系列深度解析
做I2C驱动开发,选对器件是第一步。AT24C系列,说白了就是EEPROM界的“常青树”。我最早接触它是在一个工业控制项目里,当时需要存储设备校准参数,翻来覆去还是选了它——不是因为最先进,而是因为最可靠。
这一章,我们就把AT24C系列掰开揉碎了讲。从型号命名到地址配置,从页写和字节写的差异到实际选型建议,都是我这些年踩坑换来的经验。
4.1 AT24C系列型号与容量
AT24C系列是Microchip(原Atmel)的经典产品线。型号命名其实有规律可循:
| 型号 | 容量(Kbit) | 容量(字节) | 页大小(字节) | 地址位宽 |
|---|---|---|---|---|
| AT24C01 | 1K | 128 | 8 | 7位 |
| AT24C02 | 2K | 256 | 8 | 7位 |
| AT24C04 | 4K | 512 | 16 | 7位 |
| AT24C08 | 8K | 1024 | 16 | 7位 |
| AT24C16 | 16K | 2048 | 16 | 7位 |
| AT24C32 | 32K | 4096 | 32 | 7位 |
| AT24C64 | 64K | 8192 | 32 | 7位 |
| AT24C128 | 128K | 16384 | 64 | 7位 |
| AT24C256 | 256K | 32768 | 64 | 7位 |
| AT24C512 | 512K | 65536 | 128 | 7位 |
注意看,型号数字除以8就是字节数。比如AT24C02,2Kbit = 256字节。这个换算关系,我建议你记在心里——调试时经常要用到。
4.2 地址引脚配置——I2C从机地址怎么来的?
AT24C系列的I2C从机地址,由两部分组成:
- 固定部分:高4位,固定为
1010 - 可配置部分:由A2、A1、A0引脚电平决定
- 读写位:最低位,0表示写,1表示读
举个例子,AT24C02的7位从机地址格式:
Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 0 1 0 A2 A1 A0
如果A2、A1、A0都接地(低电平),那么7位地址就是 1010000,即0x50。写操作时发送0xA0,读操作时发送0xA1。
这里有个关键点:不同容量的器件,可用的地址引脚数量不一样。
| 型号 | 可用地址引脚 | 最大级联数量 | 说明 |
|---|---|---|---|
| AT24C01/02 | A2, A1, A0 | 8个 | 3个引脚全可用 |
| AT24C04 | A2, A1 | 4个 | A0内部用于页选择 |
| AT24C08 | A2 | 2个 | A1、A0内部用于页选择 |
| AT24C16 | 无 | 1个 | 所有地址引脚内部用于页选择 |
为什么会这样?因为容量越大,需要的内部地址位越多。AT24C16有2K字节,需要11位地址。I2C协议里器件地址只给了3位可配置空间,不够用怎么办?就把A0、A1、A2“征用”为内部页地址了。
4.3 页写与字节写模式差异
这是驱动开发中最容易出问题的地方。我见过不少新手,写一个字节没问题,一写多个字节就翻车——十有八九是没搞懂页写和字节写的区别。
4.3.1 字节写模式
字节写,一次只写一个字节。时序流程:
- 主机发送起始信号
- 主机发送器件地址(写方向)
- EEPROM应答
- 主机发送存储地址(高字节)
- EEPROM应答
- 主机发送存储地址(低字节)
- EEPROM应答
- 主机发送数据字节
- EEPROM应答
- 主机发送停止信号
写完后,EEPROM会进入内部编程周期,大约5ms。这期间不会响应任何I2C命令。
4.3.2 页写模式
页写,一次可以写多个字节,但不能跨页。什么意思?
比如AT24C02,页大小8字节。如果你从地址0x00开始写,可以连续写8个字节(0x00~0x07)。但如果从地址0x05开始写,写第4个字节时就会“卷回”到页首——0x05、0x06、0x07、0x00、0x01……
这个特性,我称之为“页内回绕”。很多驱动bug都源于此。
// 页写示例:向AT24C02写入多个字节
// 注意:不能跨页,需要手动处理页边界
uint8_t i2c_eeprom_page_write(uint8_t dev_addr, uint16_t mem_addr,
uint8_t *data, uint16_t len)
{
// 检查是否跨页
uint16_t page_size = 8; // AT24C02页大小
uint16_t page_start = (mem_addr / page_size) * page_size;
uint16_t page_end = page_start + page_size - 1;
uint16_t write_len = (mem_addr + len - 1 > page_end) ?
(page_end - mem_addr + 1) : len;
// 构造I2C消息
uint8_t buffer[write_len + 2];
buffer[0] = (mem_addr >> 8) & 0xFF; // 地址高字节
buffer[1] = mem_addr & 0xFF; // 地址低字节
memcpy(&buffer[2], data, write_len);
// 发送
i2c_master_write(dev_addr, buffer, write_len + 2);
// 等待内部编程完成
i2c_eeprom_wait_ready(dev_addr);
return write_len; // 返回实际写入的字节数
}
| 特性 | 字节写 | 页写 |
| 每次写入字节数 | 1字节 | 1~N字节(N=页大小) |
| 跨页支持 | 支持(逐字节写) | 不支持(页内回绕) |
| 编程时间 | 每次5ms | 每次5ms(整页) |
| 总线占用 | 高(频繁启停) | 低(批量传输) |
| 适用场景 | 零星数据更新 | 批量数据写入 |
4.4 选型建议与避坑指南
根据我多年的项目经验,给你几条实在的建议:
- 小数据量(<256字节):AT24C02就够了,8字节页大小,地址引脚全可用,级联方便
- 中等数据量(256~2K字节):AT24C16,注意它不能级联
- 大数据量(>2K字节):AT24C256或AT24C512,页大小64/128字节,写入效率高
- 需要频繁写入:注意EEPROM的擦写寿命,一般是100万次。AT24C系列在这方面表现不错
4.5 知识体系结构图
下面这张图,把AT24C系列的核心知识点串起来了: