AT24C02_EEPROM驱动-模拟IIC通讯

写的不知道好不好,有什么不对的地方还请指出,谢了。

1、上节已经单独写好了IIC驱动代码,本次驱动AT24C02就直接拿来用了。

2、首先,运用了go to语句,不知道如何使用的可自行学习。

3、驱动AT24C02,接口代码5个:写1字节数据、读1字节数据、页写(1页16个字节)、页读(1字节,搭配for循环可以16个字节)、擦除EEPROM。

4、本代码里加入了判断通讯是否异常,感觉好啰嗦,应该单独写一个测试代码(测试代码以后在写),把正常通讯的精简一下。

#ifndef __AT24C02_H__
#define	__AT24C02_H__

//向某个器件存入数据,字节写,ddr表示器件地址,a_datax表示要将数据准备写入eeprom哪个地方,datax表示要写入到eeprom里的数据
//函数返回1表示写入成功,0表示写入失败
bit write_1byte_at24c02(unsigned char ddr, unsigned char a_datax, unsigned char datax);

//向器件存入数据,页写,ddr表示器件地址,a_datax表示要EEPROM地址,数组datax【16】表示要写入16个数据
//函数返回1表示写入成功,0表示写入失败
bit write_page_at24c02(unsigned char ddr, unsigned char a_datax, unsigned char datax[16]);

//向器件读取数据,字节读
//函数返回0表示通讯失败,不为0则读取正常。
unsigned char read_1byte_at24c02(unsigned char ddr, unsigned char a_datax);

//向器件读取数据,页读    本函数只读取一个字节的数据,需要搭配for循环使用
unsigned char read_page_at24c02(unsigned char ddr, unsigned char a_datax);

//擦除器件数据 ddr为器件地址,本开发板器件地址为0xa0 (0xa0写  0xa1读)
//函数返回1表示擦除成功,0表示擦除失败,并且iic通讯异常
bit erase_at24c02(unsigned char ddr);

#endif // !__AT24C02_H__

//P2^1;//时钟连接P2.1口
//P2^0;//时钟连接P2.0口

//at24c02芯片地址为1010 xxxy最后4位看原理图,在本单片机里芯片地址位1010 000y其中y位表示是读取器件还是向器件写入
//at24c02芯片内部地址为256字节,一页16个字节,共计16页,高4位为页地址(0-16),低4位为页单元地址(0-16)
//页写:发送16个字节的数据,每发送一个字节,芯片响应一个应答信号,同时,寻址字节低位自动加1,而高位不变。
//字节写:写地址,写数据,接收应答,然后在写地址,再写数据,在接收应答。。。。。。。
#include "iic.h"
#include"delay.h"

//向某个器件存入数据,字节写,ddr表示器件地址,a_datax表示要将数据准备写入eeprom哪个地方,datax表示要写入到eeprom里的数据
//函数返回1表示写入成功,0表示写入失败
bit write_1byte_at24c02(unsigned char ddr,unsigned char a_datax,unsigned char datax)
{
	unsigned char x;
	do
	{
		START_IIC();
		write_1_byte_IIC(ddr);//器件
		if (read_ACK_IIC() == 0)
		{
			write_1_byte_IIC(a_datax);//地址
			if (read_ACK_IIC() == 0)
			{
				write_1_byte_IIC(datax);//数据
				if (read_ACK_IIC() == 0)
				{
					STOP_IIC();
					delay_ms(60);//延迟一段时间让at24c02开始写数据进入eeprom里面
					return 1;//函数返回1,iic通讯正常
				}
				else
				{
					STOP_IIC();
				}
			}
			else STOP_IIC();
		}
		else STOP_IIC();
		x++;
		if (x == 10)//如果循环10次还没有写入数据进去,表示通讯有异常
		{
			STOP_IIC();
			return 0;//函数返回0,iic通讯异常
		}
	}while (1);
	
}

//向器件存入数据,页写,ddr表示器件地址,a_datax表示要EEPROM地址,数组datax【16】表示要写入16个数据
//函数返回1表示写入成功,0表示写入失败
bit write_page_at24c02(unsigned char ddr,unsigned char a_datax, unsigned char datax[16])
{
	unsigned char x = 0;//流水号
	unsigned char y;
page:
	START_IIC();//iic通讯开始信号
	write_1_byte_IIC(ddr);//0xa0表示at24c02器件地址,0表示要向它接下来写入数据
	if (!read_ACK_IIC())//检测从器件ACK信号
	{
			write_1_byte_IIC(a_datax);//a_datax页,第0地址准备写入数据
			if (!read_ACK_IIC())//检测从器件ACK信号
			{
				for (y = 0;y < 16;y++)//共计写16个字节数据,每次写入一页
				{
					write_1_byte_IIC(datax[y]);//开始向eeprom写入数据
					if (!read_ACK_IIC());//读取ACK
					else
					{
						x++;//流水号
						STOP_IIC();//未收到ack则结束本次通讯
						goto page;//从头开始
					}
					if (y == 15)
					{
						STOP_IIC();//第y页写入完成
						delay_ms(10);//结束本页擦除,延迟10ms,让芯片处理擦除操作
						return 1;//函数返回1,本次通讯结束
					}
				}
			}
			else//器件未发送应答信号,本次通讯异常,需要重新建立通讯
			{
				x++;//流水号
				STOP_IIC();
				goto page;
			}
	}
	else
	{
		x++;//流水号
		STOP_IIC();
		if (x >10) return 0;//如果芯片不发送ack应答信号10次则返回0表示iic通讯异常
		goto page;//重新发送器件地址
	}
}

//选择地址从器件读取数据,字节读
//函数返回0表示通讯失败,不为0则读取正常。
unsigned char read_1byte_at24c02(unsigned char ddr, unsigned char a_datax)
{
	unsigned char datax;
	unsigned char i = 0;
read:											//先开始信号,空写器件,接收应答,发送空写eeprom地址,接收应答,发送开始信号,发送读器件,接收应答,接收发来的数据
	START_IIC();//开始信号
	write_1_byte_IIC(ddr&0xfe);//操作地址  空写
	if(!read_ACK_IIC())
		write_1_byte_IIC(a_datax);//eeprom地址
	if(!read_ACK_IIC())
		START_IIC();
		write_1_byte_IIC(ddr);//器件地址及准备读取数据
	if (!read_ACK_IIC())
	{
		datax = read_1_byte_IIC();
		write_ACK_IIC(1);//发送No ack
		STOP_IIC();//结束本次通讯
		return datax;//返回结果给函数
	}
	else
	{
		i++;
		if (i > 10)
		{
			STOP_IIC();
			return 0;
		}
		else
		{
			STOP_IIC();
			goto read;
		}
	}
}

//向器件读取数据,页读    本函数只读取一个字节的数据,需要搭配for循环使用
unsigned char read_page_at24c02(unsigned char ddr, unsigned char a_datax)
{
	unsigned char datax;
	START_IIC();
	write_1_byte_IIC(ddr);
	read_ACK_IIC();
	write_1_byte_IIC(a_datax);
	read_ACK_IIC();
	datax = read_1_byte_IIC();
	write_ACK_IIC(1);
	STOP_IIC();
	return datax;
}

//擦除器件数据 ddr为器件地址,本开发板器件地址为0xa0 (0xa0写  0xa1读)
//函数返回1表示擦除成功,0表示擦除失败,并且iic通讯异常
bit erase_at24c02(unsigned char ddr)
{
	unsigned char x=0;
	unsigned char i;
	unsigned char y;
	erase:
	START_IIC();//iic通讯开始信号
	write_1_byte_IIC(ddr);//0xa0表示at24c02器件地址,0表示要向它接下来写入数据
	if (!read_ACK_IIC())//检测从器件ACK信号
	{
		for (i = 0;i < 16;i++)//循环16页
		{
			write_1_byte_IIC(0x00 + i * 16);//向i页,第0地址准备写入数据
			if (!read_ACK_IIC())//检测从器件ACK信号
			{
				for (y=0;y < 16;y++)//共计写16个字节数据,每次擦除一页
				{
					write_1_byte_IIC(0xff);//开始写1即擦除eeprom
					if (!read_ACK_IIC());//读取ACK
					else
					{
						STOP_IIC();//未收到ack则结束本次通讯
						goto erase;//从头开始
					}
					if (y == 15)
					{
						STOP_IIC();//第i页写入完成
						delay_ms(10);//结束本页擦除,延迟10ms,让芯片处理擦除操作

						START_IIC();//开始i+1页写入
						write_1_byte_IIC(ddr);//器件地址
						if (!read_ACK_IIC());
						else
						{
							if (i == 15)//判断没有ack应答16页是否传送完了,若传送完了就结束通讯
							{
								STOP_IIC();//16页传送完成,结束擦除
								return 1;	//函数返回1表示本次擦除eeprom成功
							}
							
							else
							{
								STOP_IIC();//未收到ack则结束本次通讯
								goto erase;//从头开始
							}
						}
					}
				}
			}
			else//器件未发送应答信号,本次通讯异常,需要重新建立通讯
			{
				i--;
				STOP_IIC();
				goto erase;
			}
			if (i==15)
			{
				STOP_IIC();
				return 1;//擦除成功,函数返回1

			}
		}
	}
	else
	{
		x++;
		STOP_IIC();
		if (x == 10) return 0;//如果芯片不发送ack应答信号10次则返回0表示iic通讯异常
		goto erase;//重新发送器件地址
	}
}

猜你喜欢

转载自blog.csdn.net/qq_44829055/article/details/107430430