【蓝桥杯】AT24C02存储扩展

备赛目录

1、AT24C02简介

AT24C02芯片是一种EEPROM器件。EEPROM是电可擦除可编程只读存储器,是ROM的一种。它是只读存储器,即掉电可继续存储数据,而同时又可以在高于普通电压的作用下擦除和重写。
AT24C02:256字节(256×8位);

电路连接图

在这里插入图片描述在这里插入图片描述

2、通信方式

和学过的PCF8591(没看过的可以点我)一样,它也是挂接在P20、P21这条IIC总线上的,也就是说,AT24C02的通信方式也是IIC通信(详情)

2.1器件地址

1、我看器件地址有啥用??

所有采用IIC通信的设备都必须要有自己的一个地址,IIC总线才能知道这个器件在哪,它是一个8位的地址。就好比我们的身份证号码一样。

2、器件地址怎么知道??

难道这玩意是自己编吗??不完全是的,
我们先看它与单片机的连接图 CT107D单片机AT24C02电路连接图:
在这里插入图片描述
A0、A1、A3:组成器件地址的低3位。前四位固定为1001。最后一位是方向位W/R,
A0、A1和A3可用于硬件地址编程,也就是编写器件地址第2、3、4位。最后一位地址的最后一位为方向位R/W ,当主控器对A/D器件进行读操作时为1,进行写操作时为0。前四位固定为1001,因此允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。


即0XA0——写操作地址+器件地址 0XA1——读操作地址+器件地址

3、AT24C02写入与读取

3.1写入操作流程

我怎么才能写东西进去??我可以写在哪??我能写多少??
第一步启动IIC,然后发送器件地址,(我要找到这个器件)

我们已经知道,AT24C02的通信方式是IIC通信,因此就要遵循IIC的规定来操作,要先找到器件在哪,然后和它建立通信。
——0XA0、0XA1都是AT24C02的器件地址,有什么区别呢?
最后一位地址的最后一位为方向位R/W ,当主控器对A/D器件进行读操作时为1,进行写操作时为0。因此0XA0是写操作。0XA1是写操作。
因此我们这里发送0XA0;>

IIC_SendByte(0xA0);//向器件发送写命令+器件地址
IIC_WaitAck();//向单片机发送应答信号

第二步,我要从哪开始存??

首先发送存储的首地址,从0到256都可以存,每个地址能放8bit,也就是一个地址放1个字节。
比如0、1、2、3这些数字就好了,表示地址0、地址1.。。。

IIC_SendByte(add);//向器件发送存储首地址
IIC_WaitAck();//向单片机发送应答信号

第三步,发送存的数据,我放的数据不止一个字节怎么办??

不用担心。如果你发送的数据,不止一个字节,它会自动把你的数据往后面的地址进行存储。换句话说,我们只需要发送首地址就好了。

IIC_SendByte(dat1);//向器件发送存储数据,这里可以是多个字节,存储地址依次延后
IIC_WaitAck();//向单片机发送应答信号
IIC_SendByte(dat2);
IIC_WaitAck();

最后一步,那必然是发送完数据,结束IIC咯
在这里插入图片描述

IIC_Stop();//结束总线
Delay2ms();//短暂延时,写入数据

3.2写入操作函数

void writeRom(unsigned char address,unsigned char dat)
{
  	IIC_Start();//启动总线
	
	IIC_SendByte(0xA0);//向器件发送写命令+器件地址
	IIC_WaitAck();//向单片机发送应答信号
	IIC_SendByte(add);//向器件发送存储首地址
	IIC_WaitAck();//向单片机发送应答信号
	IIC_SendByte(dat);//向器件发送存储数据,这里可以是多个字节,存储地址依次延后
	IIC_WaitAck();//向单片机发送应答信号
	IIC_Stop();//结束总线
	Delay2ms();//短暂延时,写入数据
}

3.3读取操作流程

还是IIC通信,能存当然能读,和写入操作流程一样,我就照搬一手了。
我怎么才能读东西出来??我可以读哪写地址??我能读多少??
第一步启动IIC,然后发送器件地址,(我要找到这个器件)我们是要先发送写命令

——0XA0、0XA1都是AT24C02的器件地址,有什么区别呢?
最后一位地址的最后一位为方向位R/W ,当主控器对A/D器件进行读操作时为1,进行写操作时为0。因此0XA0是写操作。0XA1是写操作。
因此我们这里发送0XA0;

IIC_SendByte(0XA0);//向器件发送写命令+器件地址
IIC_WaitAck();//向单片机发送应答信号

第二步,我要从哪开始读??

存在哪里,就发送哪里的地址
比如我存在了地址5.我就发送5
需要注意的是,我们发送命令一定要先给一个写命令0XA0

    IIC_Start();//启动总线
	IIC_SendByte(SlaveAddrW);//向器件发送写命令+器件地址
	IIC_WaitAck();//向单片机发送应答信号
	IIC_SendByte(add);//存储地址
	IIC_WaitAck();//向单片机发送应答信号

第三步、接收数据

接收数据前必须要发送读命令才行。

IIC_SendByte(0XA1);//向器件发送读命令+器件地址
IIC_WaitAck();//向单片机发送应答信号

然后开始接收

dat=IIC_RecByte();//接收数据
IIC_SendAck(1); //发送非应答信号,停止接收

最后一步,那必然是读取完数据,结束IIC咯

IIC_Stop();//停止总线

我要读的数据不止一个字节怎么办??

如果是顺序存储的,就地址一次加一往后读,
不是的话,就要发送数据在的地址了

在这里插入图片描述

3.4读取操作函数

unsigned char readRom(unsigned char add)
{	unsigned char dat;
    IIC_Start();//启动总线
	IIC_SendByte(SlaveAddrW);//向器件发送写命令+器件地址
	IIC_WaitAck();//向单片机发送应答信号
	IIC_SendByte(add);//存储地址
	IIC_WaitAck();//向单片机发送应答信号

	IIC_Start();//重启总线,输入命令
	IIC_SendByte(SlaveAddrR);//向器件发送读命令+器件地址
	IIC_WaitAck();//向单片机发送应答信号
	dat=IIC_RecByte();//接收数据
	IIC_SendAck(1); //发送非应答信号,停止接收
	IIC_Stop();//停止总线

	return dat;
}

3、AT24C02存取实验

直接复制就能跑!
我们向AT24C02中写入数据,然后关闭电源,看掉电是否还能再把它读取出来

writeRom(0,10);//地址0写入10
writeRom(1,20);//地址1写入20
writeRom(2,40);//地址2写入40
temp1 = readRom(0);//读取地址0的数据
temp2 = readRom(1);//读取地址1的数据
temp3 = readRom(2);//读取地址2的数据
实验1(检测写入读取是否成功):我们向前三个地址写入了10,20,40三个数据,然后读取出来,在数码管上显示,
实验二(检测是否防掉电):注释掉写入函数,重新编译烧录,看之前写的数据是否还能读取出来。
通过实验我们可以知道,实验功能正常

#include <STC15F2K60S2.H> 
#include "intrins.h"
#include <stdio.H> 
#define DELAY_TIME 5
#define u8 unsigned char
#define u16 unsigned int
//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
unsigned char buf[10],duanma[10];
int temp1,temp2,temp3;
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}
  void Delay2ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	    IIC_Delay(DELAY_TIME);
	    da <<= 1;
	    if(SDA) da |= 1;
	    SCL = 0;
	    IIC_Delay(DELAY_TIME);
    }
    return da;    
}
//器件地址0xa0
void writeRom(u8 add,u8 dat)
{
  	IIC_Start();
	
	IIC_SendByte(SlaveAddrW);//写命令+器件地址
	IIC_WaitAck();
	IIC_SendByte(add);//存储地址
	IIC_WaitAck();
	IIC_SendByte(dat);//存储数据
	IIC_WaitAck();
	IIC_Stop();
	Delay2ms();
}
unsigned char readRom(u8 add)
{	u8 dat;
    IIC_Start();
	IIC_SendByte(SlaveAddrW);//写命令+器件地址
	IIC_WaitAck();
	IIC_SendByte(add);//存储地址
	IIC_WaitAck();

	IIC_Start();
	IIC_SendByte(SlaveAddrR);
	IIC_WaitAck();
	dat=IIC_RecByte();
	IIC_SendAck(1); //发送非应答信号
	IIC_Stop();

	return dat;
}
void Conversion(u8 *buf,u8 *duanma)
{
  u8 i,j=0,temp;
  for(i=0;i<8;i++,j++)
  {
    switch(buf[j])
	{
	  //根据要显示的字符获取共阳极数码管编码
			case '0': temp = 0xc0; break;
			case '1': temp = 0xf9; break;
			case '2': temp = 0xa4; break;
			case '3': temp = 0xb0; break;
			case '4': temp = 0x99; break;
			case '5': temp = 0x92; break;
			case '6': temp = 0x82; break;
			case '7': temp = 0xf8; break;
			case '8': temp = 0x80; break;
			case '9': temp = 0x90; break;
			case 'A': temp = 0x88; break;
			case 'B': temp = 0x83; break;
			case 'C': temp = 0xc6; break;
			case 'D': temp = 0xA1; break;
			case 'E': temp = 0x86; break;
			case 'F': temp = 0x8E; break;
			case 'H': temp = 0x89; break;
			case 'L': temp = 0xC7; break;
			case 'N': temp = 0xC8; break;
			case 'P': temp = 0x8c; break;
			case 'U': temp = 0xC1; break;
			case '-': temp = 0xbf; break;
			case ' ': temp = 0xff; break;
			default: temp = 0xff;
	}
	if(buf[j+1]=='.')
	{
	  temp = temp&0x7f;
	  j++;
	}
	duanma[i] = temp;
  }
}
void display(u8 *duanma,u8 position)
{
  P0 = 0XFF;//段码消影
  P2 = (P2&0X1F)|0XE0;//允许段码更新
  P2 &= 0X1F;
					 
  P0 = 1<<position;//送位码
  P2 = (P2&0X1F)|0XC0;
  P2 &= 0X1F;

  P0 = duanma[position]; //送段码
  P2 = P2 & 0x1F | 0xE0; //允许段码锁存器更新
  P2 &= 0x1F; //锁存段码锁存器
}
void main()
{
 
  Timer0Init();
  EA = 1;ET0 = 1;
  writeRom(0,10);//地址0写入10
  writeRom(1,20);//地址1写入20
  writeRom(2,40);//地址2写入40
  temp1 = readRom(0);//读取地址0的数据
  temp2 = readRom(1);//读取地址1的数据
  temp3 = readRom(2);//读取地址2的数据
  while(1)
  {     
        
	   sprintf(buf,"%d %d %d",temp1,temp2,temp3);
	   Conversion(&buf,&duanma);	   
  }
}
void Timer0() interrupt 1
{
  static unsigned char i;

  if(++i==8){i=0;}display(&duanma,i);
}

实验现象:
在这里插入图片描述
请添加图片描述

版权声明:本文为CSDN博主「学到地中海」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/C_white_llj/article/details/122764569

生成海报
点赞 0

学到地中海

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

【蓝桥杯】IIC通信协议

1、IIC通信简介 I2C总线是PHLIPS(飞利浦)公司推出的一种串行(集成电路总线)总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。 I2