蓝桥杯 模板Template Part10:AT24C02存储器
● 改编自国信长天蓝桥杯官方蓝皮书例程,按照自己的习惯进行了补充和修改
【蓝桥杯】—{模块}—{AT24C02存储器Part_1}
【蓝桥杯】—{模块}—{AT24C02存储器Part_2}
一、原理图
只需关注:
●主机通过IIC总线对AT24C02存储器进行读写。
●AT24C02的引脚地址A0,A1,A2都为0。这一个AT24C02的总线地址(外部地址)。
二、AT24C02存储器内部存储结构的形象解释
1、存储结构
Notes:
●AT24C02容量为2KB,也就是 256*8。
●一共256个字节(Byte),每个字节8位(bits)。
●每8个字节是一页,一共32页(pages)。
2、存储结构的地址编码
Notes:
●一共256个字节,每个字节对应一个地址,一共256个地址,将其称为内部地址。
●从第一页第一个字节,到最后一页最后一个字节,依次对应0X00
到0XFF
。
3、第一页的形象化结构图
三、通过IIC对AT24C02的写操作
流程图
时序图
Notes:
Step1:主机发送总线启动信号,开始总线操作。
Step2:主机进行总线操作时,发送的第一个字节为地址字节 即总线地址,PCF8591和AT24C02共用IIC总线,选择接收数据的从机,和数据传输方向(写操作时最后一位为0,写入)。主机等待从机发出应答。
Step3:写操作时,主机发送的第二个字节为内部地址的首地址 ,从AT24C02存储器内部256个字节选择一个字节作为开始写入的第一个字节
。主机等待从机发出应答。
Step4:写操作时,主机发送的第三个字节为数据字节 ,从内部地址的首地址开始写入。主机等待从机发出应答。
主机可以继续发送数据字节,自动写入首地址的下一个地址。地址的低三位在收到每个数据字后都会自动加一,数据字地址的高位字节保持不变,以保持存储器页地址不变。写入字节的个数最多为8,即8个字节即一页。若一次写入的字节数超过8个字节,数据字地址将重复滚动,以前的数据将被覆盖。只能手动更改页面地址。
在这一步中只写入一个字节,叫作写字节
。一次写入8个字节叫作写页面
,允许部分页面写入
即一次写入的个数大于一个小于八个。
Step5:主机发送数据完毕,主机发送总线停止信号,结束总线操作。
Step6:从机AT24C02存储器接收到总线停止信号后,,进入一个内计时固定存储器写入周期。时间大约为5ms。需要软件延时等待。
5ms的延时为等待EEPROM的写入周期结束。可理解为刚才写入的一个字节数据只是存放在EEPROM的缓冲区,在这个写入周期内EEPROM将缓冲区的数据写入非易失性存储器内。在此写入周期内,所有输入均被禁用,并且在写入操作完成之前EEPROM不会响应
。
程序模板
//--------------------------通过IIC总线向EEPROM写数据_写页面-------------//
void EEPROM_Write(uchar *EEPROM_Write_Buf,uchar addr,uchar num)
{ //写入EEPROM内数据的数组; 首地址;写入字节的个数
IIC_Start(); //总线启动
IIC_SendByte(0XA0); //地址字节 写数据
IIC_WaitAck(); //等待应答
IIC_SendByte(addr); //内部地址的首地址
IIC_WaitAck();
while(num--)
{
IIC_SendByte(*EEPROM_Write_Buf++); //写入一个字节,循环8次写入一页
IIC_WaitAck(); //每写入一字节8位后,等待从机AT24C02产生应答
}
IIC_Stop(); //总线停止
Delay5ms(); //EEPROM的写入周期
}
四、通过IIC对AT24C02的读操作
时序图
Notes:
Step1:主机发送总线启动信号,开始总线操作。
Step2:主机进行总线操作时,发送的第一个字节为地址字节 即总线地址,PCF8591和AT24C02共用IIC总线,选择接收数据的从机,和数据传输方向(写操作时最后一位为0,写入)。主机等待从机发出应答。
读数据的操作中,先是主机向从机写入数据,包含从机的总线地址和内部地址;再重新启动总线,改变传送数据的方向,主机开始接收数据;
Step3:写操作时,主机发送的第二个字节为内部地址的首地址 ,从AT24C02存储器内部256个字节选择一个字节作为开始读取
的第一个字节 。主机等待从机发出应答。
Step3:主机发送总线停止信号,结束总线操作。在写模式下,通过发送下一次数据传输开始条件来终止本次数据传输,所以此步可忽略。
Step4:主机发送总线启动信号,开始总线操作。
Step5:主机进行总线操作时,发送的第一个字节为地址字节 即总线地址,PCF8591和AT24C02共用IIC总线,选择接收数据的从机,和数据传输方向(读操作时最后一位为1,读取)。主机等待从机发出应答。
Step6:主机随即进入接受模式,一次只接收一个字节,主机接收到一个字节后,通过总线向从机发出一个应答信号,告诉从机: 一个字节已经接收完毕,准备开始接收下一个字节。之后从机检测到主机发出的应答信号后继续通过总线向主机发送数据。主机在接收完最后一个字节后,向从机发送非应答信号
,告诉从机 我不要了,别发送了。此时从机检测到非应答信号,就停止发送数据。
Step7:主机接收数据完毕,主机发送总线停止信号,结束总线操作。
程序模板
//--------------------------通过IIC总线读取EEPROM的数据_随机地址读取-------------//
void EEPROM_Read(uchar *EEPROM_Read_Buf,uchar addr,uchar num)
{
IIC_Start(); //总线启动
IIC_SendByte(0XA0); //地址字节 写数据
IIC_WaitAck(); //等待应答
IIC_SendByte(addr); //内地址的首地址,
IIC_WaitAck(); //等待应答
IIC_Stop(); //总线停止
IIC_Start();
IIC_SendByte(0XA1); //地址字节 读数据
IIC_WaitAck(); //等待应答
while(num--)
{
*EEPROM_Read_Buf++ = IIC_RecByte();
if(num) IIC_SendAck(0); //num不为0还未读取完,接收设备主机产生应答
else IIC_SendAck(1); //num为0已读取完,接收设备主机产生非应答
}
IIC_Stop(); //总线停止
}
五、全局定义及显示信息的处理
//-------------------------------------AT24C02 存储器--------------------------------//
uchar idata EEPROM_Read_Buf[16]; //EEPROM页面读出缓冲数组——两页
uchar idata EEPROM_Write_Buf[16]={1,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15};//EEPROM页面写入缓冲数组——两页
……
//数码管显示信息处理,数码管处理函数
if(uc_Key_Value == 11)
{
//sprintf(puc_SEG_Buf,"%04u",(uint)*EEPROM_Read_Buf);
sprintf(puc_SEG_Buf,"%01u%01u%01u%01u",(uint)EEPROM_Read_Buf[0],(uint)EEPROM_Read_Buf[1],(uint)EEPROM_Read_Buf[2],(uint)EEPROM_Read_Buf[3]);
}
……
方法二:
strcpy(puc_SEG_Buf,puc_EEPROM_Read_Buf); //在头文件<string.h>中,将后一个字符串复制到前一个字符串
六、备用拓展模板
1、通过写入ID,来判断EEPROM是否被写入过
1、两个存储区:
题目要求的数据存储区 的地址题目有要求则按要求来,没有要求则可以自己规定。(在此规定为起始地址0x00
,存储大小为8个字节,即一页)。
自定义的ID验证存储区 用来存储自己定义的ID,用来判断是否是第一次上电,ID的内容和存储的地址都可以自己规定。
2、ID的内容:
字符型数据是以ASCII码的形式存储的。一般存储的是可打印字符。所以可以使用ASCII控制字符(不可打印)作为ID。 ID验证存储区首地址选用最后一页0xF8
,存储大小选为8个字节。
uchar idata puc_EEPROM_ID_Buf[9] = {0X06,0X07,0X08,0X09,0X0A,0X0B,0X0C,0X0D};
3、代码:
void EEPROM_Init(void)
{
EEPROM_Read(puc_EEPROM_Read_Buf,0xF8,8); //读ID 读取最后一页的八个字节 ,起始地址为0XF8
if( strcmp(puc_EEPROM_Read_Buf,puc_EEPROM_ID_Buf) == 0 ) //两个字符串相等,已经写入过ID。不是第一次上电
{
//读取数据存储区
EEPROM_Read(puc_EEPROM_Read_Buf,0x00,8);
//可以进行数据合理性的判断
//是否在某个范围内
//是否是2或者5的倍数
}
else //两个字符串不相等,没有写入过ID。是第一次上电
{
//进行EEPROM的初始化
//可以写0,或者写入要求的参数
sprintf(puc_EEPROM_Write_Buf,"00000000");
EEPROM_Write(puc_EEPROM_Write_Buf,0x00,8); //EEPROM的初始化
Delay6ms();
EEPROM_Write(puc_EEPROM_ID_Buf,0xF8,8); //写入ID
}
}
2、连续写入两页
写入一页八个字节后,只能写IIC_Stop();
总线停止后,延时等待6ms写入周期,在重新写入下一页。