#AT24C02存储器#

①介绍

功能:存储数据

大小:2K Bit,256个字节

②原理图(数据手册)通信协议IIC

总结步骤(写操作)

  1. 开始
  2. 发送器件地址(写)0xa0
  3. 等待应答
  4. 发送字节地址
  5. 等待应答
  6. 发送数据
  7. 等待应答
  8. 停止

总结步骤(读操作)

  1. 开始
  2. 发送器件地址(写)
  3. 等待应答
  4. 发送字节地址
  5. 等待应答
  6. 开始
  7. 发送器件地址(读)0xa1
  8. 等待应答
  9. 读数据
  10. 不应答
  11. 停止

注意:页写一次最多写8个,多余的会从头开始覆盖

  • 内存可以当作小房间(存放二进制数据),02存储器看成多栋楼,每栋楼都有八层,每层八个房间
  • 连续读写:一栋一栋的把数据输入(效率高)
  • 索引地址最好是每栋楼的第一层,地址是8的整数倍

使用指针:一个数组八个数据,数组名为数组的首地址,数组之间传递使用指针

③代码编写

1.IIC.c代码编写

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>//此库函数确保AT24C02的正常使用
#define DELAY_TIME	5

sbit sda =P2^1;
sbit scl=P2^0;//看原理图将引脚标注
//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

void AT24C02_Write( unsigned char addr , unsigned char dat )
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}
 
unsigned char AT24C02_Read( unsigned char addr)
{
	unsigned char power_count_temp;
	
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	power_count_temp = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return power_count_temp;
}

//页写函数,与写函数类似,多一个循环
void AT24C02_Write_Page(unsigned char *buf,unsigned char addr,unsigned char num)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	while(num--)//数据有几个,就执行几次
	{
		I2CSendByte(*buf++);//先*buf,再buf++
	  I2CWaitAck();
	}
	I2CStop();
}


//页读函数,与随机读函数类似,注意,随机读有一个返回值,而页读直接存放到数组中,不需要返回值
void AT24C02_Read_Page(unsigned char *buf,unsigned char addr,unsigned char num)
{
	//unsigned char i;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	/*for(i=0;i<8;i++)
	{
	    buf[i]=I2CReceiveByte();
	if(num)
		{
			I2CSendAck(0);//应答
		}
		else
		{
			I2CSendAck(1);//非应答
   }
	*/ 
	while(num--)
	{
		*buf++ = I2CReceiveByte();
		if(num)
		{
			I2CSendAck(0);//应答
		}
		else
		{
			I2CSendAck(1);//非应答
		}	
	}
	I2CStop();
}

2.IIC.h头文件编写

#ifndef __IIC_H__
#define __IIC_H__
 
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
unsigned char AT24C02_Read( unsigned char addr);
void AT24C02_Write( unsigned char addr , unsigned char dat );
void AT24C02_Write_Page(unsigned char *buf,unsigned char addr,unsigned char num);
void AT24C02_Read_Page(unsigned char *buf,unsigned char addr,unsigned char num);
//不知道在主函数使用哪一个函数的话,就将c文件内所有函数复制在内
#endif

           

④注意事项

存数字永久,除非覆盖数字

读取开机次数

write函数后一定要延时,确保数据输入成功(collect_dly<10ms)

第一次有write函数,输入1234,read读出1234

第二次将write函数注释,输入2345,read读出还是1234

注意:write→delay10ms→read(数据为输入数据)

注意:直接read(无论输入何值。都是前一次有write的情况下输入的值,02芯片有保存数据的功能)

读函数:只需要读取数据所对应的字节地址即可,后面的数据是收取地址读取内容,只需要一个变量接受即可所以只有addr

写函数:需要发送字节地址和发送数据,所以有dat和addr

⑤代码案例

1.读取数字

#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
	//初定义

sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;

code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
////uint temp;//读取数据的值
//规定一下初值
uint temp=1234;
uint count ;
//hc573定义
void hc573(uint channel)
{
	switch(channel)
	{
		case 4:LSA=0;LSB=0;LSC=1;break;
		case 5:LSA=1;LSB=0;LSC=1;break;
		case 6:LSA=0;LSB=1;LSC=1;break;
		case 7:LSA=1;LSB=1;LSC=1;break;
	}
}
//延时函数
void delay_ms(uint xms)	//@12.000MHz
{
	for( ;xms>0;xms--)
	{
		unsigned char data i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
//初始化
void init_sys()
{
	hc573(4);
	P0=0xff;
	hc573(5);
	P0=0x00;

}

//数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
	hc573(7);
	P0=0xff;
	hc573(6);
	P0=0x01<<(pos-1);
	hc573(7);
	P0=smg_number[num];
	delay_ms(1);
}
//数码管显示
void display()
{
	smg(5,temp/1000);
	smg(6,temp/100%10);
	smg(7,temp%100/10);
	smg(8,temp%10);
}

//主函数
void main()
{
	init_sys();
	AT24C02_Write(0x00,temp%256);//低八位提取
	delay_ms(10);
	AT24C02_Write(0x01,temp/256);//高八位提取
	delay_ms(10);
	temp=AT24C02_Read(0x00)+AT24C02_Read(0x01)*256;//还原成16位
	while(1)
	{
		display();
	}
}

2.读取开机次数

#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
	初定义

sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;

code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
//uint temp;//读取数据的值
规定一下初值
uint temp=1234;
uint count ;
hc573定义
void hc573(uint channel)
{
	switch(channel)
	{
		case 4:LSA=0;LSB=0;LSC=1;break;
		case 5:LSA=1;LSB=0;LSC=1;break;
		case 6:LSA=0;LSB=1;LSC=1;break;
		case 7:LSA=1;LSB=1;LSC=1;break;
	}
}
延时函数
void delay_ms(uint xms)	//@12.000MHz
{
	for( ;xms>0;xms--)
	{
		unsigned char data i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
初始化
void init_sys()
{
	hc573(4);
	P0=0xff;
	hc573(5);
	P0=0x00;
	AT24C02_Write(0x01,0);//内存初始化为0,存放开机次数
	delay_ms(10);//写函数后面必须延时十毫秒
}

数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
	hc573(7);
	P0=0xff;
	hc573(6);
	P0=0x01<<(pos-1);
	hc573(7);
	P0=smg_number[num];
	delay_ms(1);
}
数码管显示
void display()
{
	smg(5,temp/1000);
	smg(6,temp/100%10);
	smg(7,temp%100/10);
	smg(8,temp%10);
}


/////////////////////
void key()
{
	if(S7==0)
	{
		delay_ms(10);
		if(S7==0)
		{
			while(S7==0)
			{
				display();
			}
			temp++;
			AT24C02_Write(0x01,temp);//输入新的数值
		}
	}
}
void main()
{
	init_sys();
    temp=AT24C02_Read(0x01);//temp为开机次数
	temp++;
	AT24C02_Write(0x01,temp);//数字写进去,一定要延时10ms,时间等待才可应答
	delay_ms(10);
	temp=AT24C02_Read(0x01);//检验
	while(1)
	{
		
		display();
		key();
	}
}

3.页存储数据

#include <reg52.h>
#include <intrins.h>
#include <iic.h>
#define uint unsigned int
#define uchar unsigned char
	初定义

sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S7=P3^0;

code uchar smg_number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0x7f};
//uint temp;//读取数据的值
规定一下初值
uint temp=1234;
uint count ;
hc573定义
void hc573(uint channel)
{
	switch(channel)
	{
		case 4:LSA=0;LSB=0;LSC=1;break;
		case 5:LSA=1;LSB=0;LSC=1;break;
		case 6:LSA=0;LSB=1;LSC=1;break;
		case 7:LSA=1;LSB=1;LSC=1;break;
	}
}
延时函数
void delay_ms(uint xms)	//@12.000MHz
{
	for( ;xms>0;xms--)
	{
		unsigned char data i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
初始化
void init_sys()
{
	hc573(4);
	P0=0xff;
	hc573(5);
	P0=0x00;


数码管设置,消隐与独立显示
void smg(uint pos,uint num)
{
	hc573(7);
	P0=0xff;
	hc573(6);
	P0=0x01<<(pos-1);
	hc573(7);
	P0=smg_number[num];
	delay_ms(1);
}


//////////////////
uchar BUFF[8]={1,2,3,4,5,6,7,8};
void display()
{
	smg(1,BUFF[0]);
	smg(2,BUFF[1]);
	smg(3,BUFF[2]);
	smg(4,BUFF[3]);
	smg(5,BUFF[4]);
	smg(6,BUFF[5]);
	smg(7,BUFF[6]);
	smg(8,BUFF[7]);
}
void main()
{
	init_sys();
	AT24C02_Write_Page(BUFF,0x00,8);
	delay_ms(10);
	AT24C02_Read_Page(BUFF,0x00,8);
	while(1)
	{
		display();
	}
}

4.存储数字(永不变,除非覆盖数字)

#include <STC15F2K60S2.H>
#include "intrins.h"
#include "iic2.h"
#define uint unsigned int
#define uchar unsigned char
uchar temp;

code unsigned char segment[] =  
{ 
0xc0,  
0xf9,  
0xa4,  
0xb0,  
0x99,  
0x92,  
0x82,  
0xf8,  
0x80,  
0x90,
0xff }; 
void hc573(uchar channel)
{
	switch(channel)
	{
		case 4:P2=P2&0x1f |0x80;break;
		case 5:P2=P2&0x1f |0xa0;break;
		case 6:P2=P2&0x1f |0xc0;break;
		case 7:P2=P2&0x1f |0xe0;break;

	}
	P2=P2&0x1f;
}
void delay_ms(uchar xms)	//@12.000MHz
{
	for( ; xms>0;xms--)
	{
			unsigned char data i, j;

			i = 12;
			j = 169;
			do
			{
				while (--j);
			} while (--i);
	}
}

void init_sys()
{
	P0=0xff;
	hc573(4);
	P0=0x00;
	hc573(5);
	write(0x01,235);//写函数
	delay_ms(10);
}

void smg(uchar pos,uchar dot ,uchar num)
{
	P0=0xff;
	hc573(7);
	P0=0x01<<(pos-1);
	hc573(6);
	if(dot)
	{
		P0=segment[num]&0x7f;
	}
	else
	{
		P0=segment[num];
	}
	hc573(7);
	delay_ms(1);
}

void display()
{
	smg(1,0,10);
	smg(2,0,10);
	smg(3,0,10);
	smg(4,0,10);
	smg(5,0,10);
	smg(6,0,temp/100);
	smg(7,0,temp%100/10);
	smg(8,0,temp%10);
}

void main()
{
	init_sys();
	while(1)
	{
		temp=read(0x01);//读取之前初始化的235
		display();
	}
}

#STC15F2K60S2是ISP编译的专属头文件,里面的引脚定义很全,相较于reg52.h更便捷哦^_^#

#使用AT24C02得添加intrins.h头文件,要不然IIC文件缺失条件#

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐