1. 项目概述:51单片机通过I2C总线读写24C02 EEPROM
在嵌入式系统开发中,EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种常用的非易失性存储器,用于保存系统配置参数、运行日志等关键数据。24C02是Atmel公司生产的2Kbit(256×8)串行EEPROM,采用I2C总线接口,工作电压范围宽(1.8V-5.5V),具有100万次擦写周期和100年数据保存期限。
本项目使用51单片机(如常见的STC89C52)作为主控,通过I2C总线实现对24C02 EEPROM的单字节地址读写操作。I2C(Inter-Integrated Circuit)是一种同步、多主从架构的串行通信总线,仅需两根信号线(SCL时钟线和SDA数据线)即可实现设备间通信,非常适合资源有限的嵌入式系统。
2. 硬件设计与连接
2.1 24C02引脚功能说明
24C02采用8引脚封装(如DIP-8),各引脚功能如下:
| 引脚 | 名称 | 功能描述 |
|---|---|---|
| 1 | A0 | 地址输入0 |
| 2 | A1 | 地址输入1 |
| 3 | A2 | 地址输入2 |
| 4 | VSS | 地 |
| 5 | SDA | 串行数据 |
| 6 | SCL | 串行时钟 |
| 7 | WP | 写保护 |
| 8 | VCC | 电源 |
提示:A0-A2用于设置器件地址,当系统中挂载多个24C02时,可通过这三根引脚区分不同器件。本项目中只使用单个EEPROM,因此A0-A2可直接接地。
2.2 51单片机与24C02连接方案
典型连接电路如下:
- 51单片机P2.0引脚 → 24C02 SDA引脚(需接4.7K上拉电阻)
- 51单片机P2.1引脚 → 24C02 SCL引脚(需接4.7K上拉电阻)
- 24C02 A0-A2引脚 → 接地(设置器件地址为000)
- WP引脚 → 接地(禁用写保护)
- VCC → +5V电源
- VSS → 地
注意:I2C总线必须使用上拉电阻,典型值为4.7KΩ。电阻值过大会导致信号上升沿过缓,过小则会增加总线负载。
3. I2C通信协议实现
3.1 I2C基本时序
I2C通信包含以下几种基本信号:
- 起始条件(START):SCL为高电平时,SDA由高变低
- 停止条件(STOP):SCL为高电平时,SDA由低变高
- 数据有效性:SDA数据在SCL高电平期间必须保持稳定
- 应答信号(ACK):接收方在每字节传输后拉低SDA表示应答
3.2 汇编语言实现I2C底层驱动
以下是关键子程序的汇编实现:
assembly复制; 起始信号
START:
SETB SDA ; SDA置高
SETB SCL ; SCL置高
NOP ; 保持至少4.7us
CLR SDA ; SDA置低
NOP
RET
; 停止信号
STOP:
CLR SDA ; SDA置低
SETB SCL ; SCL置高
NOP
SETB SDA ; SDA置高
NOP
RET
; 发送应答
ACK:
CLR SCL ; SCL置低
CLR SDA ; SDA置低(应答)
NOP
SETB SCL ; SCL置高
NOP
CLR SCL ; SCL置低
SETB SDA ; 释放总线
NOP
RET
; 发送非应答
NOACK:
CLR SCL ; SCL置低
SETB SDA ; SDA置高(非应答)
NOP
SETB SCL ; SCL置高
NOP
CLR SCL ; SCL置低
RET
; 接收应答
GET_ACK:
SETB SDA ; 释放SDA
SETB SCL ; SCL置高
NOP
MOV C,SDA ; 读取应答位
CLR SCL ; SCL置低
RET
; 发送单字节
TRANS:
MOV R0,#8 ; 8位数据
TLOOP:
RLC A ; 循环左移,最高位到C
CLR SCL ; SCL置低
NOP
MOV SDA,C ; 输出数据位
SETB SCL ; SCL置高
NOP
CLR SCL ; SCL置低
NOP
DJNZ R0,TLOOP
RET
; 接收单字节
RECEIVE:
MOV R0,#8 ; 8位数据
RLOOP:
CLR SCL ; SCL置低
NOP
SETB SCL ; SCL置高
NOP
MOV C,SDA ; 读取数据位
RLC A ; 移入累加器
CLR SCL ; SCL置低
NOP
DJNZ R0,RLOOP
RET
4. 24C02读写操作详解
4.1 器件地址与操作码
24C02的7位器件地址格式为:1010[A2][A1][A0]。本项目中A2-A0接地,因此地址为1010000(0xA0)。
- 写操作:器件地址 + 0(0xA0)
- 读操作:器件地址 + 1(0xA1)
4.2 单字节写操作流程
- 发送起始条件(START)
- 发送器件写地址(0xA0)
- 等待应答(ACK)
- 发送要写入的内存地址(00-FF)
- 等待应答(ACK)
- 发送要写入的数据
- 等待应答(ACK)
- 发送停止条件(STOP)
注意:写入操作需要约5ms的写入周期(tWR),在此期间EEPROM不会响应任何操作。
4.3 单字节读操作流程
- 发送起始条件(START)
- 发送器件写地址(0xA0)
- 等待应答(ACK)
- 发送要读取的内存地址(00-FF)
- 等待应答(ACK)
- 发送起始条件(START)
- 发送器件读地址(0xA1)
- 等待应答(ACK)
- 接收数据
- 发送非应答(NOACK)
- 发送停止条件(STOP)
4.4 完整汇编实现
assembly复制ORG 0000H
LJMP MAIN
ORG 1000H
MAIN:
; 初始化定时器0用于延时
MOV TMOD,#01H ; 定时器0模式1
MOV TH0,#0FCH ; 1ms定时初值
MOV TL0,#18H
MOV IE,#82H ; 允许T0中断
CLR TR0
CLR F0 ; 清除标志
; 写入数据0xAA到地址0x00
LCALL START
MOV A,#0A0H ; 器件写地址
LCALL TRANS
LCALL GET_ACK
JC ERROR
MOV A,#00H ; 内存地址0x00
LCALL TRANS
LCALL GET_ACK
JC ERROR
MOV A,#0AAH ; 写入数据0xAA
LCALL TRANS
LCALL GET_ACK
JC ERROR
LCALL STOP
; 延时等待写入完成
LCALL DELAY
; 从地址0x00读取数据
LCALL START
MOV A,#0A0H ; 器件写地址
LCALL TRANS
LCALL GET_ACK
JC ERROR
MOV A,#00H ; 内存地址0x00
LCALL TRANS
LCALL GET_ACK
JC ERROR
LCALL START
MOV A,#0A1H ; 器件读地址
LCALL TRANS
LCALL GET_ACK
JC ERROR
LCALL RECEIVE ; 接收数据
LCALL NOACK
LCALL STOP
; 将读取的数据输出到P0口LED
MOV P0,A
LOOP:
SJMP LOOP
ERROR:
LCALL STOP
SJMP LOOP
; 5ms延时子程序
DELAY:
MOV R2,#5
DLP1:
MOV TH0,#0FCH
MOV TL0,#18H
SETB TR0
DLP2:
JB F0,DLP2
SETB F0
DJNZ R2,DLP1
RET
; T0中断服务程序
INT_T0:
CLR TR0
CLR F0
RETI
5. 调试技巧与常见问题
5.1 典型问题排查
-
无应答信号:
- 检查硬件连接,确认SCL/SDA线正确连接并上拉
- 确认24C02电源电压正常(2.5-5.5V)
- 检查器件地址是否正确(本项目应为0xA0/0xA1)
-
数据读写错误:
- 确保在写操作后留有足够的写入时间(tWR≥5ms)
- 检查WP引脚是否已接地(禁用写保护)
- 确认时序符合规范,特别是SCL/SDA的边沿时间
-
通信不稳定:
- 缩短总线长度(建议<30cm)
- 调整上拉电阻值(4.7K-10KΩ)
- 在信号线上添加100pF电容滤波
5.2 实用调试方法
-
LED指示灯法:
- 在SCL/SDA线上各接一个LED(串联限流电阻)
- 通过LED闪烁观察通信状态
-
逻辑分析仪捕获:
- 使用Saleae等逻辑分析仪捕获I2C波形
- 验证起始/停止条件、数据位时序
-
分步调试:
- 先单独测试START/STOP信号
- 再测试单字节发送/接收
- 最后测试完整读写流程
5.3 性能优化建议
- 将频繁调用的子程序(如START/STOP)放在内存前256字节(使用ACALL)
- 使用定时器中断实现精确延时,避免忙等待
- 对关键代码段进行循环展开,减少跳转开销
- 在批量读写时使用页写/顺序读模式提高效率
6. 扩展应用
6.1 多字节连续读写
24C02支持页写(8字节/页)和顺序读操作。修改上述程序可实现更高效的数据传输:
- 页写:在发送起始地址后,连续发送最多8字节数据
- 顺序读:在发送起始地址后,连续读取多个字节(每字节后发送ACK,最后一个字节发NOACK)
6.2 存储结构化数据
通过定义固定地址映射,可在EEPROM中存储各种配置参数:
assembly复制; 定义参数地址
CONFIG_TEMP EQU 00H ; 温度校准值
CONFIG_HUMI EQU 01H ; 湿度校准值
CONFIG_ALARM EQU 02H ; 报警阈值
; 读取温度校准值
MOV ADDR,#CONFIG_TEMP
LCALL EEPROM_READ
MOV TEMP_CAL,A
; 写入报警阈值
MOV ADDR,#CONFIG_ALARM
MOV A,ALARM_VALUE
LCALL EEPROM_WRITE
6.3 与其他I2C器件共用总线
51单片机可同时控制多个I2C器件,只需为每个器件分配唯一地址:
- PCF8574(I/O扩展):0100[A2][A1][A0]
- DS1307(RTC):1101000
- BMP180(气压传感器):1110111
提示:总线上所有器件SCL/SDA线并联,通过器件地址区分。注意总电容不超过400pF。
