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

完结,撒花~~~

相关推荐
光影少年1 小时前
web3学习路线
前端·学习·前端框架·web3
暗然而日章1 小时前
C++基础:Stanford CS106L学习笔记 3 流
c++·笔记·学习
青衫码上行1 小时前
【JavaWeb学习 | 第17篇】JSP内置对象
java·开发语言·前端·学习·jsp
jimmyleeee1 小时前
人工智能基础知识笔记二十二:构建一个可以搜索Web的Agent
笔记
Molesidy1 小时前
【Embedded Development】【TCP-IP】关于TCP-IP网络协议的学习记录以及基于TCP-IP网络协议的上层协议的初步理解
网络协议·学习·tcp/ip
Darken031 小时前
基于 STM32 ——GPIO输出
单片机·学习·gpio·硬件
组合缺一1 小时前
Solon AI 开发学习10 - chat - 工具调用概念介绍
java·人工智能·学习·ai·llm·solon
丝斯20111 小时前
AI学习笔记整理(25)—— 计算机视觉之目标检测
人工智能·学习·计算机视觉
AA陈超1 小时前
只想克隆项目中的 Source 文件夹,而不影响其他内容
笔记·git·学习