51单片机嵌入式开发:10、 STC89C52RC 使用IIC操作AC24C02实现数据读写

发布于:2024-07-15 ⋅ 阅读:(48) ⋅ 点赞:(0)


在这里插入图片描述

1 总体概述

本章节基于C51平台实现IIC通讯功能,并通过IIC实现EEPROM芯片AT24C02的数据读写操作,此类应用在工程上存在有多种应用场景,如下所列举的几种场景,实际应用中还有许多其他可能性。
(1)数据存储:AT24C02是一种串行EEPROM芯片,可以在嵌入式系统中用于存储各种类型的数据,如配置信息、校准数据、历史记录等。通过使用C51平台实现IIC通信功能,可以方便地将数据写入AT24C02芯片,并在需要时读取这些数据。
(2)系统配置:将系统的配置参数保存在AT24C02芯片中,例如网络设置、传感器校准参数等。系统启动时可以从AT24C02读取这些配置参数,避免每次启动都需要重新设置。
(3)数据日志记录:在一些数据采集系统或记录仪中,可以使用AT24C02芯片作为数据日志存储器。通过C51平台实现IIC通信功能,可以将采集到的数据写入AT24C02芯片,并在需要时读取和导出这些数据。
(4)认证和安全:AT24C02芯片具有可编程的写保护功能,可以用于存储密钥、认证信息和安全配置等敏感数据。通过C51平台实现IIC通信功能,可以实现对这些数据的安全读写和保护。
(5)设备识别和配置:使用AT24C02芯片存储设备的唯一标识符或配置信息,可以在系统启动时读取这些信息,实现设备的自动识别和配置。

2 IIC介绍

2.1 IIC概述

IIC(Inter-Integrated Circuit)是一种串行通信协议,也被称为I2C(Inter-IC)协议。它是由飞利浦(Philips)公司在1982年推出的一种用于芯片间通信的简单、低成本、高效率的通信协议。
IIC协议使用两根传输线(称为SDA和SCL)进行通信,其中SDA(Serial Data Line)是数据线,而SCL(Serial Clock Line)是时钟线。这两根线可以连接多个IIC设备,形成一个多主从结构的总线系统。
IIC协议的优点包括简单、低成本、可靠性高、适用于短距离通信等。它广泛应用于各种嵌入式系统中,如传感器、存储器芯片、显示设备、扩展模块等,为这些设备之间提供了方便的通信接口。

2.2 IIC原理

以下是IIC协议的一般工作原理:
(1)I2C,译作集成电路总线,是两线式串行通信总线,用于设备间的通讯等,标准情况下最高传送速率达100Kbps。顾名思义,I2C通讯只需要两根线,一根是数据线SDA(Serial Data Line),一根是时钟线SCL(Serial Clock Line)。主设备控制时钟线决定I2C的波特率,配合数据线进行数据的传输,这两根线分别通过上拉电阻连接到电源。

在这里插入图片描述

(2)硬件层面
I2C是多主从架构,每个设备都有唯一的地址,一个主设备理论上可以接127个从设备,设备的SDA并接在一起,SCl并接在一起。

在这里插入图片描述

I2C总线内部都是采用漏极开路驱动,示意图如图,栅极给电压时mos导通,输出低电平,栅极给0时mos关断输出呈高阻态,那么这里就无法输出高电平。

在这里插入图片描述

加上上拉电阻后可以实现高低电平的输出:开关断开时电阻趋于无穷,电流为0,电源电压为输出电压,即输出高电平;开关闭合,输出低电平。只要有一个设备拉低总线电平,总线的电平就会被拉低,这就是线与功能,便于数据的传输和仲裁。

在这里插入图片描述

(2)数据传输
I2C数据的传输也遵循一定的格式。它有开始和停止条件,中间进行8bit的数据传输,没有奇偶校验,并且在一个开始条件和停止条件可之间可以传要多少数据有多少数据。提醒一下,我们的总线默认保持高电平。

在这里插入图片描述

总体传输过程
IIC(Inter-Integrated Circuit)传输过程可以分为起始条件、地址传输、数据传输和停止条件等几个步骤。下面是一般的IIC传输过程:

  1. 起始条件(Start Condition):
    • 主设备发送起始条件信号(Start)。
    • 在起始条件时,SDA(Serial Data Line)从高电平切换到低电平,而SCL(Serial Clock Line)保持高电平。
    • 这表示通信即将开始。
  2. 地址传输(Address Transmission):
    • 主设备发送从设备的地址和读/写位。
    • 地址是一个7位或10位的二进制值,标识要与之通信的从设备。
    • 最高位指示读取(1)还是写入(0)操作。
  3. 应答(Acknowledgement):
    • 主设备等待从设备的应答信号。
    • 在地址传输后的每个字节传输结束后,接收数据的设备必须发送一个应答(ACK)信号。
    • 应答信号是一个低电平脉冲。
  4. 数据传输(Data Transmission):
    • 主设备发送或接收数据字节。
    • 数据位通过在时钟脉冲上升沿或下降沿时改变SDA线上的电平来传输。
    • 从设备在时钟脉冲上升沿或下降沿时读取SDA线上的数据。
  5. 应答或非应答(Acknowledgement or Non-Acknowledgement):
    • 在每个字节传输结束后,接收数据的设备发送应答信号(ACK)或非应答信号(NACK)。
    • 应答信号表示数据接收成功,非应答信号表示数据接收失败或通信结束。
  6. 重复起始条件(Repeated Start Condition):
    • 主设备可以在数据传输过程中发送重复起始条件信号(Repeated Start)。
    • 重复起始条件用于在不释放总线的情况下与另一个从设备进行通信。
  7. 停止条件(Stop Condition):
    • 主设备发送停止条件信号(Stop)。
    • 在停止条件时,SDA从低电平切换到高电平,而SCL保持高电平。
    • 这表示通信结束。

3 AT24C02介绍

在这里插入图片描述

3.1 AT24C02概述

AT24C01/02/04/08/16 是一个 1K/2K/4K/8K/16K 位串行 CMOS E2 PROM 内部含有 128/256/512/1024/2048 个 8 位字节 CATALYST 公司的先进 CMOS 技术实质上减少了器件的功耗 AT24C02/01 有一个 8 字节页写缓冲器 AT24C 04/08/16 有一个 16 字节页写缓冲器 该器件通过 I 2 C 总线接口进行操作 有一个专门的写保护功能。

在这里插入图片描述

注意操作芯片的作用时间,作为编程时的参考:

在这里插入图片描述

在这里插入图片描述

3.2 AT24C02原理

AT24C02芯片引脚介绍
AT24C02SC, 2K SERIAL EEPROM: Internally organized with 32 pages of 8 bytes each, the 2K requires an 8-bit data word address for random word addressing.
管脚描述
(1)SCL 串行时钟
AT24C01/02/04/08/16 串行时钟输入管脚用于产生器件所有数据发送或接收的时钟 这是一个输 入管脚
(2)SDA 串行数据/地址
AT24C01/02/04/08/16 双向串行数据/地址管脚用于器件所有数据的发送或接收 SDA 是一个开漏 输出管脚 可与其它开漏输出或集电极开路输出进行线或 wire-OR
(3)A0 A1 A2 器件地址输入端
这些输入脚用于多个器件级联时设置器件地址 当这些脚悬空时默认值为 0 (24C01 除外)。
当使用 24C01 或 24C02 时最大可级联 8 个器件 如果只有一个 24C02 被总线寻址 这三个地 址输入脚 A0 A1 A2 可悬空或连接到 Vss 如果只有一个 24C01 被总线寻址 这三个地址输入 脚 A0 A1 A2 必须连接到 Vss 。
当使用 24C04 时最多可连接 4 个器件 该器件仅使用 A1 A2 地址管脚 A0 管脚未用 可以连 接到 Vss 或悬空 如果只有一个 24C04 被总线寻址 A1 和 A2 地址管脚可悬空或连接到 Vss 。
当使用 24C08 时最多可连接 2 个器件 且仅使用地址管脚 A2 A0 A1 管脚未用 可以连接到 Vss 或悬空 如果只有一个 24C08 被总线寻址 A2 管脚可悬空或连接到 Vss 。
当使用 24C16 时最多只可连接 1 个器件 所有地址管脚 A0 A1 A2 都未用 管脚可以连接到 Vss 或悬空 。
(4)WP 写保护 如果 WP 管脚连接到 Vcc 所有的内容都被写保护 只能读 当 WP 管脚连接到 Vss 或悬空 允许 器件进行正常的读/写操作。
AT24Cxx有4位强制地址位,和最大11位内存地址位,当内存地址位小于8位时,其余3位可以作为器件寻址地址位,所以,根据内存大小的不同,AT24Cxx寻址地址位长度可能由4~7位在变化

3.3 AT24C02操作方法

我们通过三个图,来演示读写的时序
(1)向从机写数据
写操作要求主设备发送器件地址,收到应答信号后,先接收8位的字地址。接收到这个地址后EEPROM应答"0"(ACK),然后再是一个8位数据。在接收8位数据后,EEPROM应答"0"(ACK),接着必须由主器件发送停止条件来终止写序列。时序图如下

在这里插入图片描述

24C02器件按8字节/页执行页写,24C04/08/16器件按16字节/页执行页写,24C32/64器件按32字节/页执行页写。页写初始化与字节写相同,只是主器件不会在第一个数据后发送停止条件,而是在EEPROMEEPROM收到每个数据后都应答“0”。最后仍需由主器件发送停止条件,终止写序列。

接收到每个数据后,字地址的低3位 (24C02) 或4位(24C04/08/16) 或5位(24C32/64)内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个 (24C02) 或16个 (24C04/08/16) 或32个(24C32/64) 数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。

(2)向从机读数据
AT24C02的读操作有三种,分别是当前地址读,随机读和顺序读。

当前地址读
内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存当读到最后页的最后字节,地址会回转到0。当写到某页尾的最后一个字节,地址会回转到该页的首字节。接收器件地址(读/写选择位为"1") 且EEPROM应答ACK后,当前地址的数据就随时钟送出。主器件无需应答"0",但需发送停止条件。当前地址读操作时序图如下。

在这里插入图片描述

随机读
随机读需先写一个目标字地址,一旦EEPROM接收器件地址和字地址并应答了ACK,主器件就产生一个重复的起始条件。然后,主器件发送器件地址(读/写选择位为"1") ,EEPROM应答ACK,并随时钟送出数据。主器件无需应答"0",但需发送停止条件。这里的随机读就是读取任意一个字地址的数据,并不是随即返回一个数据的意思。随机读时序图如下

在这里插入图片描述

顺序读
顺序读可以通过“当前地址读”或“随机读”启动。主器件接收到一个数据后,应答ACK。只要EEPROM接收到ACK,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。主器件不应答"0",而发送停止条件,即可结束顺序读操作。顺序读时序图如下

在这里插入图片描述

4 软件实现

首先先对工程中的计时函数整理
(1)微秒延时

`此计时函数作为微秒计时不准确,请不要使用`
/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{
	while(us--)
	{
	}
}

(2)nop();

//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。
//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。

(3)毫秒计时函数
测试通过,可以使用;

/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{
	while(Ms--)
	{
		delay_us(100);
	}
}

4.1 IIC代码

/------------------------------------------------
(1)启动IIC总线
------------------------------------------------
/

void Start(void)
{
	Sda=1;
	_nop_();_nop_();
	Scl=1;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Sda=0;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Scl=0;
}

/------------------------------------------------
(2)停止IIC总线
------------------------------------------------
/

void Stop(void)
{
	Sda=0;
	_nop_();
	Scl=1;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Sda=1;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Scl=0;
}

/------------------------------------------------
(3) 应答IIC总线
------------------------------------------------
/

void Ack(void)
{
	Sda=0;
	_nop_();_nop_();_nop_();
	Scl=1;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Scl=0;
	_nop_();_nop_();
}

/------------------------------------------------
(4) 非应答IIC总线
------------------------------------------------
/

void NoAck(void)
{
	Sda=1;
	_nop_();_nop_();_nop_();
	Scl=1;
	_nop_();_nop_();_nop_();_nop_();_nop_();
	Scl=0;
	_nop_();_nop_();
}

4.2 发送接收IIC代码

/------------------------------------------------
(1) 发送一个字节
------------------------------------------------
/

void Send(unsigned char Data)
{ 
	unsigned char BitCounter=8;
	unsigned char temp;

	do
	{
		temp=Data;
		Scl=0;
		_nop_();_nop_();_nop_();_nop_();_nop_();
		if((temp&0x80)==0x80)
			Sda=1;
		else
			Sda=0;


		Scl=1;
		temp=Data<<1;
		Data=temp;
		BitCounter--;
	}
	while(BitCounter);
	Scl=0;
}

/------------------------------------------------
(2)读入一个字节并返回
------------------------------------------------
/

unsigned char Read(void)
{
	unsigned char temp=0;
	unsigned char temp1=0;
	unsigned char BitCounter=8;

	Sda=1;
	do
	{
		Scl=0;
		_nop_();_nop_();_nop_();_nop_();_nop_();
		Scl=1;
		_nop_();_nop_();_nop_();_nop_();_nop_();
		if(Sda)
			temp=temp|0x01;
		else
			temp=temp&0xfe;

		if(BitCounter-1)
		{
			temp1=temp<<1;
			temp=temp1;
		}
		BitCounter--;
	}
	while(BitCounter);
	return(temp);
}

4.3 数据读写AT24C02代码

/------------------------------------------------
(1) 写入数据
------------------------------------------------
/

void WrToROM(unsigned char Data[],unsigned char Address,unsigned char Num)
{
	unsigned char i;
	unsigned char *PData;
	PData=Data;
	for(i=0;i<Num;i++)
	{
		Start();
		Send(AddWr);    //写入芯片地址
		Ack();
		Send(Address+i);//写入存储地址
		Ack();
		Send(*(PData+i));//写数据
		Ack();
		Stop();
		delay_ms(20);
	}
}

/------------------------------------------------
(2) 读出数据
------------------------------------------------
/

void RdFromROM(unsigned char Data[],unsigned char Address,unsigned char Num)
{
	unsigned char i;
	unsigned char *PData;
	PData=Data;
	for(i=0;i<Num;i++)
	{
		Start();        //写入芯片地址
		Send(AddWr);
		Ack();
		Send(Address+i);//写入存储地址
		Ack();
		Start();
		Send(AddRd);    //读入地址
		Ack();
		*(PData+i)=Read();//读数据
		Scl=0;
		NoAck();
		Stop();
	}
}

4.4 工程应用及测试

承接上文,在原有工程基础上,新建关于AT24C02的c和h文件,并在includes.h中引用,并添加头文件:
注意:测试发现原有工程添加进去文件编译后,工程代码已经溢出,内存告急,故现在将其他文件从工程中去掉,重新整理工程,新工程文件夹C51project202407015

在这里插入图片描述

Iic.h文件:

//c51_iic.h文件

#ifndef __C51_IIC_H__
#define __C51_IIC_H__

#include "STC89C5xRC_RDP.h"


#define AddWr 0xAE   //写数据地址,需要参考24c02芯片文档
#define AddRd 0xAF   //读数据地址


#define Sda	P12       //定义总线连接端口
#define Scl	P11
#define WP	P10       //写保护,这里不使用



extern void Start(void);
extern void Stop(void);
extern void Ack(void);
extern void NoAck(void);
extern void Send(unsigned char Data);
extern unsigned char Read(void);
extern void WrToROM(unsigned char Data[],unsigned char Address,unsigned char Num);
extern void RdFromROM(unsigned char Data[],unsigned char Address,unsigned char Num);

extern void IIC_AT24C02_Test1(void);


#endif

测试代码:

void IIC_AT24C02_Test1(void)
{
	unsigned char Number[1];
	WP=0;//写保护关掉

	RdFromROM(Number,0,1);	//调用存储数据 从地址0开始写一个数据
	Number[0]++;
	WrToROM(Number,0,1);	//写入24c02
	P1 =  Number[0];		//在P1口上显示 反向显示 LED亮代表0,不亮代表1
}

主程序:

//main.c文件

#include "includes.h"



/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{
	while(us--)
	{
	}
}

/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{
	while(Ms--)
	{
		delay_us(100);
	}
}

/*------------------------------------------------
                    延时子程序
------------------------------------------------*/
void delay(unsigned int cnt) 
{
 while(--cnt);
}

/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{
	
	IIC_AT24C02_Test1();
	while (1)
	{
		delay(100);
	}
}

测试结果可知,指示灯会根据上电的次数发生变化,点击51 RESET按键,观察现象。
在这里插入图片描述

5 总结

在嵌入式行业中,通过IIC实现EEPROM芯片AT24C02的数据读写具有以下价值:
(1)数据存储和配置:嵌入式系统通常需要存储各种类型的数据,如配置信息、校准数据、历史记录等。使用AT24C02芯片进行数据存储具有非易失性,即使在断电情况下也可以保持数据的完整性。通过使用IIC通信协议,可以方便地将数据写入和读取出来,为嵌入式系统提供高效的数据存储和配置功能。
(2)节省系统资源:AT24C02芯片外部连接简单,只需要两根引脚即可实现IIC通信,相对于其他存储设备如SD卡或Flash芯片,不需要额外的控制器或复杂的引脚连接,从而节省了系统资源的使用。
(3)数据保护和安全性:AT24C02芯片具有可编程的写保护功能,可以保护存储的数据不被意外修改或擦除。这在一些需要保护数据完整性和安全性的应用中尤为重要,如认证信息、密钥存储等。
(4)系统启动和配置:通过将系统的配置参数和启动信息存储在AT24C02芯片中,可以实现系统的自动配置和启动。这样在系统上电或重启时,可以从芯片中读取这些配置信息,无需手动设置,提高了系统的可靠性和便捷性。
(5)数据日志和追溯:AT24C02芯片可以用于数据采集系统或记录仪中的数据日志存储。通过IIC通信,可以将采集到的数据写入芯片,并在需要时读取和导出这些数据,方便进行数据分析、故障排查和系统追溯。
总的来说,通过IIC实现EEPROM芯片AT24C02的数据读写在嵌入式行业中具有重要的价值,为系统提供了可靠的数据存储、配置和保护功能,简化了系统设计和开发过程,提高了系统的可靠性和安全性。