Skip to main content

AT24C02寄存助手

选用模块

这个组件叫 AT24C02寄存器

直接上库

先看提供了哪些函数:

实现代码(其实直接塞进去就ok)

AT24C02.c

#include <REGX52.H>
#include "I2C.h"

#define AT24C02_ADDRESS 0xA0

/**
* @brief AT24C02写入一个字节
* @param WordAddress 要写入字节的地址
* @param Data 要写入的数据
* @retval 无
*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_SendByte(Data);
I2C_ReceiveAck();
I2C_Stop();
}

/**
* @brief AT24C02读取一个字节
* @param WordAddress 要读出字节的地址
* @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;
}


AT24C02.h

#ifndef __AT24C02_H__
#define __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);


#endif


这个库提供了哪些函数?


1. AT24C02_WriteByte

void AT24C02_WriteByte(unsigned char WordAddress, Data);
  • 功能:向AT24C02 EEPROM的指定地址写入一个字节。
  • 参数
    • WordAddress:目标存储单元的地址(范围为0x00到0xFF,具体取决于芯片容量)。
    • Data:需要存储的数据(一个字节,范围为0x00到0xFF)。
  • 返回值:无(void类型)。
  • 具体用途
    • 在EEPROM中保存配置信息、状态值等,断电后数据依然保存。

2. AT24C02_ReadByte

unsigned char AT24C02_ReadByte(unsigned char WordAddress);
  • 功能:从AT24C02 EEPROM的指定地址读取一个字节。
  • 参数
    • WordAddress:需要读取的存储单元地址。
  • 返回值:从指定地址读取到的数据(一个字节)。
  • 具体用途
    • 从EEPROM中提取配置数据、记录等。

江协科技速览

1. 如何新建工程并添加所需模块?

操作步骤

  • 打开KO软件,点击“新建工程”,选择保存位置(如12 - 1文件夹),设定工程名称。
  • 在工程设置中,选择合适的单片机型号(如AT89CY)。
  • 添加main函数,确保勾选“HEX”选项,以便生成可执行文件。
  • 点击“头文件”按钮,添加所需的头文件(如 REGX52.H 等)。
  • 从软件界面找到并选中所需模块(如LCD、按键、AT24C02等相关模块),使用“复制”(Ctrl + C)和“粘贴”(Ctrl + V)操作将其添加到工程中。

注意事项

  • 确保所选单片机型号与实际使用的硬件一致,否则可能导致程序无法正常运行。
  • 添加头文件时,要注意文件路径的正确性,避免找不到头文件的错误。

2. I2C协议中起始条件和停止条件是如何实现的?

起始条件实现原理

  • 在I2C的起始条件中,默认SCL(时钟线)和SDA(数据线)为高电平,这是空闲状态。
  • 为确保起始条件的正确拼接,首先执行I2C_SDA = 1;,将SDA线置为高电平。这一步是为了保证在起始条件之前,SDA处于一个确定的高电平状态,避免因之前状态不确定而导致起始条件错误。
  • 接着I2C_SCL = 1;,拉高SCL时钟线,此时SCL和SDA均为高电平。然后I2C_SDA = 0;,在SCL为高电平时,将SDA线拉低,这是起始条件的关键操作,根据I2C协议,SCL高电平期间,SDA从高电平切换到低电平表示起始条件。最后I2C_SCL = 0;,拉低SCL线,完成起始条件的设置。

停止条件实现原理

  • 停止条件的实现同样基于SCL和SDA的电平操作。在停止之前,SDA可能处于0或1的不确定状态,所以先执行I2C_SDA = 0;,将SDA线拉低。
  • 然后I2C_SCL = 1;,拉高SCL时钟线。此时,SCL为高电平,SDA为低电平。最后I2C_SDA = 1;,将SDA线拉高,使SDA和SCL均为高电平,恢复到空闲状态,符合I2C协议中停止条件的规定,即SCL高电平期间,SDA从低电平切换到高电平表示停止条件。

代码示例

代码示例
// 起始条件函数
void I2C_Start(void)
{
I2C_SDA = 1;
I2C_SCL = 1;
I2C_SDA = 0;
I2C_SCL = 0;
}

// 停止条件函数
void I2C_Stop(void)
{
I2C_SDA = 0;
I2C_SCL = 1;
I2C_SDA = 1;
}

3. 如何实现I2C协议中发送一个字节和接收一个字节的功能?

发送一个字节的实现

  • 发送一个字节的函数(如I2C_SendByte)有一个参数Byte,用于指定要发送的字节数据。
  • 通过一个for循环8次,实现从字节的高位到低位依次发送。每次循环中,先将Byte0x80进行与运算,取出最高位的值赋给SDA(即I2C_SDA = Byte & 0x80;),然后将SCL拉高(I2C_SCL = 1;),再拉低(I2C_SCL = 0;)。在拉高SCL期间,从机可以读取SDA上的数据,完成一位数据的发送。发送完一位后,Byte右移一位(Byte >>= 1;),准备发送下一位,循环8次后完成一个字节的发送。

接收一个字节的实现

  • 接收一个字节的函数(如I2C_ReceiveByte)首先执行I2C_SDA = 1;,释放SDA总线,准备接收数据。
  • 然后通过一个for循环8次,每次循环先将SCL拉高(I2C_SCL = 1;),在SCL高电平期间读取SDA的数据。使用if判断读取的值,如果SDA为1,则将返回变量Byte的相应位置1(即Byte |= 0x80 >> i;),否则不处理。读取完一位后,将SCL拉低(I2C_SCL = 0;),准备接收下一位数据。循环8次后,完成一个字节的接收,最后返回接收的字节Byte

代码示例

代码示例
// 发送一个字节函数
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for (i = 0; i < 8; i++)
{
I2C_SDA = Byte & 0x80;
I2C_SCL = 1;
I2C_SCL = 0;
Byte >>= 1;
}
}

// 接收一个字节函数
unsigned char I2C_ReceiveByte(void)
{
unsigned char Byte = 0x00, i;
I2C_SDA = 1;
for (i = 0; i < 8; i++)
{
I2C_SCL = 1;
if (I2C_SDA)
{
Byte |= 0x80 >> i;
}
I2C_SCL = 0;
}
return Byte;
}

4. 发送应答和接收应答在I2C协议中是如何操作的?

发送应答的操作

  • 发送应答的函数(如I2C_SendAck)有一个参数AckBit,用于指定应答位的值(0表示应答,1表示非应答)。
  • 函数内部直接将SDA设置为应答位的值(即I2C_SDA = AckBit;),然后将SCL拉高(I2C_SCL = 1;),再拉低(I2C_SCL = 0;),完成发送应答操作。这一系列操作按照I2C协议规定,在接收完一个字节后,主机在下一个时钟发送一位数据作为应答信号。

接收应答的操作

  • 接收应答的函数(如I2C_ReceiveAck)首先执行I2C_SDA = 1;,释放SDA总线,准备接收应答信号。
  • 然后将SCL拉高(I2C_SCL = 1;),在SCL高电平期间读取SDA的值赋给应答位变量AckBit(即AckBit = I2C_SDA;),接着将SCL拉低(I2C_SCL = 0;),最后返回应答位AckBit。根据I2C协议,返回值为0代表有应答,返回值为1代表无应答。主机在接收之前需要释放SDA,然后在SCL高电平期间读取从机发送的应答信号。

代码示例

代码示例
// 发送应答函数
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA = AckBit;
I2C_SCL = 1;
I2C_SCL = 0;
}

// 接收应答函数
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA = 1;
I2C_SCL = 1;
AckBit = I2C_SDA;
I2C_SCL = 0;
return AckBit;
}

5. 在AT24C02中如何实现字节写入和读取操作?

字节写入操作

  • 字节写入操作通过调用一系列I2C函数来实现。首先调用I2C_Start函数,启动I2C总线,发送起始条件。
  • 接着发送AT24C02的地址(0XA0),通过I2C_SendByte函数发送,发送后调用I2C_ReceiveAck函数接收应答,检查从机是否正确响应。
  • 然后发送要写入的字节地址,再次接收应答。之后发送要写入的数据,同样接收应答。
  • 最后调用I2C_Stop函数,发送停止条件,完成字节写入操作。在写入操作后,需要延时5毫秒,因为AT24C02的写周期最长为5毫秒,这是芯片的特性要求,以确保数据正确写入。可以使用Delay函数来实现延时,例如Delay(5);

字节读取操作

  • 字节读取操作也遵循I2C协议的流程。先调用I2C_Start函数启动总线,发送起始条件。
  • 发送地址(0XA0 | 0X01表示读操作),通过I2C_SendByte函数发送,然后接收应答。
  • 接着调用I2C_ReceiveByte函数获取数据,读取一个字节后,发送非应答位(1),表示读取结束,最后调用I2C_Stop函数发送停止条件。读取操作不需要延时,但写入操作后必须延时,否则会出错,这是因为写入操作涉及到芯片内部的存储过程,需要一定时间来完成数据的写入和存储。

代码示例

代码示例
// 在AT24C02中写入一个字节的函数
void AT24C02_WriteByte(unsigned char WordAddress, Data)
{
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_SendByte(Data);
I2C_ReceiveAck();
I2C_Stop();
Delay(5); // 写入后延时5毫秒
}

// 从AT24C02中读取一个字节的函数
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS | 0x01);
I2C_ReceiveAck();
Data = I2C_ReceiveByte();
I2C_SendAck(1);
I2C_Stop();
return Data;
}