普中51单片机学习笔记-AT24C02读写

AT24C02介绍

开发板上使用的是 AT24C02(EEPROM) 芯片,此芯片具有 I2C 通信接口,芯片内保存的数据在掉电情况下都不丢失, 所以通常用于存放一些比较重要的数据等。AT24C02 芯片管脚及外观图如下图所示:

AT24C02 器件地址为 7 位,高 4 位固定为 1010,低 3 位由 A0/A1/A2 信 号线的电平决定。 因为传输地址或数据是以字节为单位传送的,当传送地址时,器件地址占 7 位,还有最后一位(最低位 R/W)用来选择读写方向,它与地址 无关。其格式如下:

开发板已经将芯片的 A0/A1/A2 连接到 GND,所以器件地址为 1010000,即 0x50(未计算最低位)。

如果要对芯片进行写操作时,R/W 即为 0,写器件地址为 0XA0。

如果要对芯片进行读操作时,R/W 即为 1,读器件地址为 0XA1。

开发板上也将 WP 引脚直接接在 GND 上,此时芯片允许数据正常读写。

硬件电路

从图中可以看出,芯片的 SCL 和 SDA 管脚是连接在单片机的 P2.1 和 P2.0 上,为了让 IIC 总线默认为高电平,通常会在 IIC 总线上接上拉电阻。

在图中并没有看到 SCL 和 SDA 管脚有上拉电阻,这是因为开发板单片机 IO 都外接了 10K 上拉电阻,当单片机 IO 口连接到芯片的 SCL 和 SDA 脚时即相当于它们外接上拉电阻,所以此处可以省去。

示例代码

I2C.h

复制代码
#ifndef _I2C_H_
#define _I2C_H_

#include <regx52.h>

// 定义I2C引脚连接 - 根据实际硬件调整
sbit I2C_SCL = P2^1;  // I2C时钟线
sbit I2C_SDA = P2^0;  // I2C数据线

// 函数声明
void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);

#endif

I2C.c

复制代码
#include "I2C.h"

/**
  * @brief  产生I2C起始信号
  */
void I2C_Start(void) {
    I2C_SDA = 1;
    I2C_SCL = 1;
    I2C_SDA = 0;
    I2C_SCL = 0;
}

/**
  * @brief  产生I2C停止信号
  */
void I2C_Stop(void) {
    I2C_SDA = 0;
    I2C_SCL = 1;
    I2C_SDA = 1;
}

/**
  * @brief  向I2C总线发送一个字节
  * @param  Byte: 要发送的字节
  */
void I2C_SendByte(unsigned char Byte) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        I2C_SDA = Byte & (0x80 >> i);
        I2C_SCL = 1;
        I2C_SCL = 0;
    }
}

/**
  * @brief  从I2C总线接收一个字节
  * @retval 接收到的字节
  */
unsigned char I2C_ReceiveByte(void) {
    unsigned char i, Byte = 0x00;
    I2C_SDA = 1;  // 释放数据线,设置为输入
    for (i = 0; i < 8; i++) {
        I2C_SCL = 1;
        if (I2C_SDA) { Byte |= (0x80 >> i); }
        I2C_SCL = 0;
    }
    return Byte;
}

/**
  * @brief  发送应答信号
  * @param  AckBit: 0-应答,1-非应答
  */
void I2C_SendAck(unsigned char AckBit) {
    I2C_SDA = AckBit;
    I2C_SCL = 1;
    I2C_SCL = 0;
}

/**
  * @brief  接收应答信号
  * @retval 0-应答,1-非应答
  */
unsigned char I2C_ReceiveAck(void) {
    unsigned char AckBit;
    I2C_SDA = 1;  // 释放数据线,设置为输入
    I2C_SCL = 1;
    AckBit = I2C_SDA;
    I2C_SCL = 0;
    return AckBit;
}

AT24C02.h

复制代码
#ifndef _AT24C02_H_
#define _AT24C02_H_

// AT24C02设备地址[citation:3]
#define AT24C02_ADDRESS 0xA0

// 函数声明
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
void AT24C02_DelayMs(unsigned int ms);

#endif

AT24C02.c

复制代码
										#include "AT24C02.h"
#include "I2C.h"

/**
  * @brief  向AT24C02指定地址写入一个字节[citation:3]
  * @param  WordAddress: 写入目标地址 (0x00~0xFF)
  * @param  Data: 要写入的数据
  */
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data) {
    I2C_Start();
    I2C_SendByte(AT24C02_ADDRESS);      // 发送设备地址+写命令
    I2C_ReceiveAck();
    I2C_SendByte(WordAddress);          // 发送要写入的存储单元地址
    I2C_ReceiveAck();
    I2C_SendByte(Data);                 // 发送要写入的数据
    I2C_ReceiveAck();
    I2C_Stop();
    
    // 写入操作后,AT24C02需要时间完成内部写周期[citation:6]
    AT24C02_DelayMs(10);  // 延时10ms等待写入完成
}

/**
  * @brief  从AT24C02指定地址读取一个字节[citation:3]
  * @param  WordAddress: 读取源地址 (0x00~0xFF)
  * @retval 读取到的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress) {
    unsigned char Data;
    I2C_Start();
    I2C_SendByte(AT24C02_ADDRESS);      // 发送设备地址+写命令
    I2C_ReceiveAck();
    I2C_SendByte(WordAddress);          // 发送要读取的存储单元地址
    I2C_ReceiveAck();
    
    I2C_Start();                        // 发送重复起始信号
    I2C_SendByte(AT24C02_ADDRESS | 0x01); // 发送设备地址+读命令
    I2C_ReceiveAck();
    
    Data = I2C_ReceiveByte();           // 读取数据
    I2C_SendAck(1);                     // 发送非应答信号,表示读取结束
    I2C_Stop();
    return Data;
}

/**
  * @brief  简单延时函数
  * @param  ms: 延时的毫秒数
  */
void AT24C02_DelayMs(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 112; j++);  // 针对12MHz晶振的近似延时
}

main.c

复制代码
#include <regx52.h>
#include "AT24C02.h"

// 定义LED指示灯 - 用于演示状态
sbit LED_READ = P2^5;   // 读取指示
sbit LED_WRITE = P2^6;  // 写入指示
sbit LED_SUCCESS = P2^7;// 成功指示

/**
  * @brief  主函数 - 完整的AT24C02读写测试示例
  */
void main() 
{
    unsigned char write_data = 0x5A;   // 要写入的测试数据
    unsigned char read_data;           // 存储读取的数据
    unsigned char test_address = 0x12; // 测试地址(0x00-0xFF)
    
    // 初始化LED状态
    LED_READ = 1;
	LED_WRITE = 1;
    LED_SUCCESS = 1;
    
    while (1) 
	{

        // 写入数据
        LED_WRITE = 0;
        AT24C02_WriteByte(test_address, write_data);
        AT24C02_DelayMs(200);  //延时看灯
        LED_WRITE = 1;
        
        // 短暂延时
        AT24C02_DelayMs(2000);
        
        // 读取刚写入的数据
        LED_READ = 0;
        read_data = AT24C02_ReadByte(test_address);
		AT24C02_DelayMs(200); //延时看灯
        LED_READ = 1;
        
        // 验证数据是否正确
        if (read_data == write_data) 
		{
            LED_SUCCESS = 0;  // 读写一致,点亮成功指示灯
        } 
		else 
		{
            LED_SUCCESS = 1;  // 读写失败
        }
        
        
    }
}

完结,撒花~~~

相关推荐
不会代码的小猴4 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
摇滚侠6 小时前
《SpringBoot 3:入门与应用实战》第 2 章 IOC 思想与实现 阅读笔记 1
spring boot·笔记·后端
蒸蒸yyyyzwd6 小时前
秋招不熟悉力扣学习笔记1
笔记·学习·leetcode
LuminousCPP8 小时前
数据结构-双向循环链表
c语言·数据结构·笔记·链表
小弥儿8 小时前
GitHub今日热榜 | 2026-08-11:图原生基础设施首日登顶
学习·开源·github
302wanger9 小时前
【阅读笔记】当AI拿走一切之后
笔记
疯狂打码的少年11 小时前
【数据结构】串(字符串):基本概念与存储
数据结构·笔记
for_ever_love__11 小时前
python基础语法学习: 数据容器
windows·python·学习
云空11 小时前
《电子专业完整学习路线图(分两套:本科四年版 / 零基础自学速成版)》
科技·学习·学习方法·高考
min(a,b)11 小时前
学习第16天:LangGraph 与 Agent 工作流编排
学习