第七周 AT24C02

I2C EEPROM (AT24C02) 学习与实战笔记

1. 核心概念理解

  • EEPROM (AT24C02): 单片机的“笔记本”。

    • 特点: 掉电不丢失(Non-volatile)。

    • 用途: 保存设置参数(如密码、阈值、状态)。

  • RAM (变量): 单片机的“黑板”。

    • 特点: 读写快,但掉电即失。
  • 交互逻辑:

    • 开机时: 必须执行 EEPROM_Read,把“笔记本”里的数据抄到“黑板”上。

    • 修改时: 执行 EEPROM_Write,把“黑板”上的新数据刻录到“笔记本”里。


2. 代码解析与记忆 (重点)

2.1 驱动函数对比

步骤 Write (写函数) Read (读函数)
1. 起手式 Start → 0xA0 → Addr Start → 0xA0 → Addr
2. 关键转折 (直接写数据) Start (重启) → 0xA1
3. 循环操作 发送数据 (SendByte) 接收数据 (RecByte)
4. 核心细节 必加 Delay(5ms) (等存储) 判断 ACK/NACK (是否读完)

2.2 记忆口诀

写 (Write):一路绿灯,写完记得歇一会 (Delay)。

读 (Read):先假写,回马枪 (Restart) 变 0xA1,收完数据分 0 和 1。

2.3 标准代码模板

C

 // 写函数:指针强转,循环写入,写完延时
 void EEPROM_Write(unsigned char* String, unsigned char addr, unsigned char num)
 {
     IIC_Start();
     IIC_SendByte(0xA0); IIC_WaitAck();  // 呼叫写
     IIC_SendByte(addr); IIC_WaitAck();  // 设地址
     while(num--) {
         IIC_SendByte(*String++);        // 发送
         IIC_WaitAck();
         IIC_Delay(200);                 // 【重点】物理写入需要时间
     }
     IIC_Stop();
 }
 ​
 // 读函数:假写地址,重启读模式,ACK/NACK判断
 void EEPROM_Read(unsigned char* String, unsigned char addr, unsigned char num)
 {
     IIC_Start();
     IIC_SendByte(0xA0); IIC_WaitAck();
     IIC_SendByte(addr); IIC_WaitAck();  // 假写,为了设指针
     
     IIC_Start();                        // 【重点】重启
     IIC_SendByte(0xA1); IIC_WaitAck();  // 【重点】呼叫读 (0xA1)
     while(num--) {
         *String++ = IIC_RecByte();      // 接收
         if(num) IIC_SendAck(0);         // 还有数据?回 ACK (0)
         else    IIC_SendAck(1);         // 没了?回 NACK (1)
     }
     IIC_Stop();
 }

3. 常见逻辑陷阱 (Bug 预警)

3.1 地址冲突 (Address Collision)

  • 现象: 保存了变量 B,结果变量 A 的值变了。

  • 原因: 多个变量使用了同一个 EEPROM 地址(如都往 addr 0 写)。

  • 解决: 地址规划。给每个变量分配独立的“房间”。

3.2 页边界回卷 (Page Wrap)

  • 现象: 连续写入超过 8 字节,或者跨越了 8 的倍数地址,数据覆盖了页首。

  • 解决: 尽量按 8字节一页 进行对齐,不要一次性跨页写入。


4. 进阶技巧:存储 int/long 类型

4.1 存储空间换算

EEPROM 的最小单元是 1 Byte (字节)

  • char: 占 1 个地址。

  • int: 占 2 个地址。

  • long: 占 4 个地址。

4.2 强制类型转换 (Type Casting)

为了把 int 拆成字节存进去,必须使用指针强转。

写入时:

C

 int speed = 500;
 // (unsigned char*)&speed : 把 int指针 伪装成 char指针
 // 2 : 写入长度为 2 字节
 EEPROM_Write((unsigned char*)&speed, 0, 2); 

读取时:

C

 int speed;
 EEPROM_Read((unsigned char*)&speed, 0, 2);

4.3 为什么必须强转?

  • 如果不转,指针加法 ptr++ 会按 int 的步长(跳2个字节)移动,导致数据漏写。

  • 转为 char* 后,ptr++ 按 1 个字节移动,保证数据被完整切片保存。


## 5. 完美的 Main 函数逻辑示例

C

 void main()
 {
     // 1. 上电第一件事:恢复数据
     // 注意:变量a和数组dat地址错开,互不干扰
     EEPROM_Read(&a, 0, 1);        // 从地址0读 a (1字节)
     EEPROM_Read(dat, 8, 2);       // 从地址8读 dat (2字节, int的话也是2)
 ​
     // 2. 初始化系统
     System_Init();
     Timer0Init();
 ​
     // 3. 进入循环
     while (1)
     {
         Key_Proc(); // 按键修改并保存数据
         Seg_Proc(); // 显示数据
     }
 }
2 个赞