
1. EEPROM与I2C通信基础认知第一次接触蓝桥杯单片机竞赛时我被EEPROM这个神奇的小东西吸引住了。想象一下你的单片机突然断电所有数据都消失了——这种场景在比赛中太常见了。而AT24C02就像个不会失忆的记事本即使断电也能牢牢记住重要数据。AT24C02本质上是个256字节的电子便签采用I2C协议与单片机对话。I2C就像两个人用摩斯密码交流一根时钟线SCL打节拍一根数据线SDA传信息。最妙的是它可以同时管理多个设备就像老师用同一个口哨指挥全班同学。实际使用时要注意几个关键点设备地址固定为1010开头A0-A2接地时为000每次写入后需要5ms以上的消化时间数据分页存储每页8字节超出的部分会循环覆盖我曾在比赛中犯过低级错误连续写入不延时结果数据像被施了魔法一样随机变化。后来用示波器抓波形才发现原来是EEPROM需要喘口气才能处理下一条指令。2. 硬件连接与初始化实战拿到开发板第一件事先找到I2C接口。以STC15系列为例SCL接P2.0SDA接P2.1记得加上4.7kΩ的上拉电阻——就像给通信线装上弹簧保证信号能快速回弹。初始化代码要像这样严谨void IIC_Init() { P2M1 ~0x03; // 设置P2.0/P2.1为准双向口 P2M0 ~0x03; SCL 1; // 初始拉高 SDA 1; }特别注意138译码器的配置这是很多新手容易翻车的地方。有一次我调试两小时才发现是译码器通道选错了数码管死活不亮void HC138_Init(unsigned char channel) { P2 (P2 0x1F) | (channel 5); }建议在初始化时完成三件事关闭所有LED和蜂鸣器设置I/O口工作模式确认上拉电阻正常工作3. 单字节读写深度解析先看最基础的写操作流程就像寄信要有固定格式开始信号SCL高时SDA下降沿发送设备地址0xA0表示写等待应答发送存储地址发送数据停止信号SCL高时SDA上升沿对应的代码骨架void AT24C02_WriteByte(unsigned char addr, unsigned char dat) { IIC_Start(); IIC_SendByte(0xA0); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); IIC_SendByte(dat); IIC_WaitAck(); IIC_Stop(); Delay_ms(5); // 必须的延时 }读操作稍复杂些需要先假装写入地址再切换为读模式unsigned char AT24C02_ReadByte(unsigned char addr) { unsigned char dat; // 伪写操作 IIC_Start(); IIC_SendByte(0xA0); IIC_WaitAck(); IIC_SendByte(addr); IIC_WaitAck(); // 真实读取 IIC_Start(); IIC_SendByte(0xA1); IIC_WaitAck(); dat IIC_RecByte(); IIC_SendAck(1); IIC_Stop(); return dat; }实测中发现个有趣现象如果省略伪写步骤直接读会得到随机数据就像不按门铃直接闯进别人家。4. 多字节数据存储方案比赛中最常存储的是超过255的整型数据如计分值。这时就需要将数据拆包存储像把大象装进冰箱分两步方法一手动拆分高低字节// 存储16位数据 void SaveScore(unsigned int score) { AT24C02_WriteByte(0, score 8); // 高字节 Delay_ms(5); AT24C02_WriteByte(1, score 0xFF); // 低字节 } // 读取时重组 unsigned int ReadScore() { return (AT24C02_ReadByte(0) 8) | AT24C02_ReadByte(1); }方法二更优雅的封装写法void AT24C02_WriteInt(unsigned char addr, unsigned int dat) { IIC_Start(); IIC_SendByte(0xA0); IIC_WaitAck(); IIC_SendByte(addr * 2); // 地址翻倍避免重叠 IIC_WaitAck(); IIC_SendByte(dat 8); IIC_WaitAck(); IIC_SendByte(dat 0xFF); IIC_WaitAck(); IIC_Stop(); } unsigned int AT24C02_ReadInt(unsigned char addr) { unsigned int dat; //...省略起始流程... dat IIC_RecByte() 8; IIC_SendAck(0); dat | IIC_RecByte(); IIC_Stop(); return dat; }特别提醒方法二中地址乘以2的操作很关键相当于给每个16位数分配两个停车位避免数据互相覆盖。5. 数码管验证技巧写完存储功能后用数码管验证是最直观的。动态扫描要注意每次只点亮1位数码管刷新频率保持在50Hz以上显示函数不要阻塞主循环推荐这样实现unsigned char code SMG_Table[] {0xC0,0xF9,...}; // 共阳段码表 void ShowNumber(unsigned int num) { static unsigned char pos 0; P0 0xFF; // 先消隐 switch(pos) { case 0: P0 SMG_Table[num/1000%10]; break; // 千位 case 1: P0 SMG_Table[num/100%10]; break; // 百位 //...其他位类似... } HC138_Init(6); P0 1 pos; pos (pos1)%4; }调试时可先显示固定值如1234确认硬件正常后再接EEPROM数据。我曾遇到段码表顺序错误的情况显示的数字像中了面目全非脚。6. 典型问题排查指南问题1写入后读取全是0xFF检查I2C线序是否接反测量上拉电阻是否正常确认停止信号是否完整问题2数据随机变化确保每次写入后有足够延时检查电源稳定性避免超过页写入限制8字节/页问题3只能读取最后一次写入的值确认地址没有重叠检查读函数中的应答信号尝试降低I2C时钟频率有个实用的调试技巧用LED灯指示操作状态。比如写入时闪绿灯读取时闪蓝灯能快速定位故障阶段。7. 竞赛实战经验分享在真实比赛中建议提前封装好EEPROM驱动对关键数据做校验如CRC校验准备备用存储方案如片内Flash我曾见过有队伍因为EEPROM故障改用矩阵键盘输入密码作为备用方案最终逆袭夺冠。记住在蓝桥杯比赛中稳定性比炫技更重要。存储系统配置时可以采用这样的结构struct SystemConfig { unsigned int param1; unsigned char param2; //... }; void SaveConfig() { AT24C02_WriteInt(0, config.param1); AT24C02_WriteByte(2, config.param2); //... }最后提醒比赛前务必烧录测试程序确认EEPROM模块正常工作。有些批次的芯片可能存在响应延迟等问题早发现才能早解决。