普中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;  // 读写失败
        }
        
        
    }
}

完结,撒花~~~

相关推荐
世人万千丶8 小时前
参数管理_Flutter在鸿蒙平台路由参数最佳实践
学习·flutter·华为·harmonyos·鸿蒙
遇乐的果园11 小时前
前端学习笔记-vue加载渲染优化
前端·笔记·学习
遇乐的果园12 小时前
前端学习笔记-vue状态管理优化
前端·笔记·学习
从零开始的代码生活_13 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
可乐奶茶sky13 小时前
AI Agent 学习
人工智能·学习
摇滚侠13 小时前
Java 全栈开发实战教程 课程笔记 29-33
笔记
茯苓gao13 小时前
嵌入式开发笔记:EtherCAT协议从硬件到软件完整配置指南——从零搭建一套EtherCAT通信系统
笔记·嵌入式硬件·学习
whyTeaFo14 小时前
GAMES101: Lecture 9: Shading 3(Texture Mapping cont.) ppt笔记
笔记
RD_daoyi15 小时前
外链权重暴跌至13%,品牌提及反超传统链接——2026年不做Digital PR,你的独立站等于隐形
运维·网络·学习·机器学习·搜索引擎
chase。15 小时前
【学习笔记】PointWorld:迈向通用机器人操控的3D世界模型
笔记·学习·机器人