基础知识
电可擦除只读存储器,作用就是可以存储数据,板子断电之后数据不会丢失,板子再次上电,可以从里面读取数据。可以写一百万次,数据可以存100年,超级牛哔!
EEPROM有2k存储空间,可以存256个字节,可支持一次写入8个字节,一个内存地址可写入一个字节。
电路原理
A0、A1、A3:代表器件地址,因为总线上可以挂载多个器件,所以IIC协议需要器件地址以区分。
WP:写入保护,当WP为高电平时,AT24C02无法写入数据,但是蓝桥杯板直接接到了GND,所以我们就不用管这个,可以进行任意读写。
读写EEPROM
EEPROM有很多种读写方式,但是只需要掌握以下两种就可以了
//写AT24C02
void vWrite_EEPROM(u8 add, u8 dat)
{
IIC_Start();
IIC_SendByte(0xa0);//AT24C02器件地址,因为蓝桥杯板上还挂载了AD-DA芯片,必须加以区分
//读写控制信号为低电平时为写,所以最低位是0
IIC_WaitAck();
IIC_SendByte(add);//写地址
IIC_WaitAck();
IIC_SendByte(dat);//写数据
IIC_WaitAck();
IIC_Stop();
vDelay_Ms(5);//必须延时5ms,延长两次写的间隔,不然写入数据会出错,也可能损坏EEPROM
}
//读AT24C02
u8 ucRead_EEPROM(u8 add)
{
u8 dat;
IIC_Start();
IIC_SendByte(0xa0);//写地址,发送要读哪个地址上的数据
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);//读写控制信号为高电平时为读,所以最低位是1
IIC_WaitAck();
dat=IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return dat;
}
程序控制
注意事项
两次写入操作时间间隔至少为5ms
全新的EEPROM内部存储的是0xff
//统计开机次数,每次上电数码管上的数字+1;
#include "system.h"
HexToBin led_ctrl,uln_ctrl;
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /* 关闭蜂鸣器、继电器*/
led_ctrl.hex=0xff;
vDevice_Ctrl(0x80,led_ctrl.hex); /* 关闭LED*/
}
//开机次数统计
u8 start_times;
void vEEPROM_Process()
{
start_times = ucRead_EEPROM(0x20); /*AT24C02的地址范围是0x00~0xff*/
vWrite_EEPROM(0x20,++start_times);
}
//数码管操作函数
void vSMG_Process()
{
smg_buf[0]=smg_code[start_times/10];
smg_buf[1]=smg_code[start_times%10];
smg_buf[2]=0x00;
smg_buf[3]=0x00;
smg_buf[4]=0x00;
smg_buf[5]=0x00;
smg_buf[6]=0x00;
smg_buf[7]=0x00;
}
void main(void)
{
vSystem_Init();
vEEPROM_Process();
vTimer2_Init();
while(1)
{
vSMG_Process();
}
}
//中断服务程序
void vTimer2_ISR() interrupt 12 //中断入口
{
vSMG_Display();
}
EEPROM读写不同类型数据
上面基础知识说了,一个地址,只能存入一个字节数据,所以针对不同类型的数据,必须分离成单个字节的数据
如果是两个字节的数据,就要拆成高8位和低8位数据
//EEPROM一个地址,只能存入一个字节的数据。针对不同类型的数据,需要分离成单个字节的数据。
#include "system.h"
HexToBin led_ctrl,uln_ctrl;
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /* 关闭蜂鸣器、继电器*/
led_ctrl.hex=0xff;
vDevice_Ctrl(0x80,led_ctrl.hex); /* 关闭LED*/
}
//EEPROM处理函数
u16 u16_write = 1234;
u16 u16_read = 0;
float float_write = 3.1415;
float float_read = 0;
s8 minus_write = -23;
s8 minus_read = 0;
s16 minus_s16_write = -1234;
s16 minus_s16_read = 0;
u8 str_write[11]={"hello world"};
u8 str_read[11];
void vEEPROM_Process()
{
u8 i = 0;
/***************写入u16类型的数据**************/
vWrite_EEPROM(0x00,u16_write>>8);
vWrite_EEPROM(0x01,u16_write);
u16_read = (ucRead_EEPROM(0x00)<<8)+ucRead_EEPROM(0x01);
/***************写入float类型的数据,保留小数点后四位**************/
vWrite_EEPROM(0x03,(u16)(float_write*1000)/256);
vWrite_EEPROM(0x04,(u16)(float_write*1000)%256);
float_read = (ucRead_EEPROM(0x03)*256+ucRead_EEPROM(0x04))/1000.0f;
/***************写入负数,在数字电路中的存储形式是补码**************/
/***************例如-23,其最高位为符号位1(表示负数),23的二进制10111,反码1110 1000,补码1110 1001 -> 0xE9**************/
// if(minus_write<0)
// {
// vWrite_EEPROM(0x06,'-');
// vWrite_EEPROM(0x07,-minus_write);
// }
// if(ucRead_EEPROM(0x06)=='-')
// {
// minus_read = 0 - ucRead_EEPROM(0x07);
// }
vWrite_EEPROM(0x06,minus_write);
minus_read = ucRead_EEPROM(0x06);
vWrite_EEPROM(0x08,minus_s16_write>>8); //取出高8位
vWrite_EEPROM(0x09,minus_s16_write); //取出低8位
minus_s16_read = (ucRead_EEPROM(0x08)<<8)+ucRead_EEPROM(0x09);
/***************写入字符串,字符以ASCII码存储**************/
for(i=0;i<sizeof(str_write);i++)
{
vWrite_EEPROM(0x10+i,str_write[i]);
}
for(i=0;i<sizeof(str_write);i++)
{
str_read[i]=ucRead_EEPROM(0x10+i);
}
}
//数码管操作函数
void vSMG_Process()
{
smg_buf[0]=0x00;
smg_buf[1]=0x00;
smg_buf[2]=0x00;
smg_buf[3]=0x00;
smg_buf[4]=0x00;
smg_buf[5]=0x00;
smg_buf[6]=0x00;
smg_buf[7]=0x00;
}
void main(void)
{
vSystem_Init();
vEEPROM_Process();
vTimer2_Init();
while(1)
{
vSMG_Process();
}
}
//中断服务程序
void vTimer2_ISR() interrupt 12 //中断入口
{
vSMG_Display();
}
利用共用体读写EEPROM
利用共用体可以不用自己拆分多字节数据,可以实现自动拆分成单字节数据。
#include "system.h"
HexToBin led_ctrl,uln_ctrl;
void vSystem_Init(void)
{
vDevice_Ctrl(0xa0,0); /* 关闭蜂鸣器、继电器*/
led_ctrl.hex=0xff;
vDevice_Ctrl(0x80,led_ctrl.hex); /* 关闭LED*/
}
//EEPROM处理函数,利用共用体读写EEPROM
union eeprom_u16
{
u16 a;
u8 b[2];
}u16_write,u16_read;
union eeprom_s16
{
s16 a;
u8 b[2];
}s16_write,s16_read;
union eeprom_float
{
float a;
u8 b[4];
}float_write,float_read;
union eeprom_u32
{
u32 a;
u8 b[4];
}u32_write;
void vEEPROM_Process()
{
u8 i = 0;
/***************2个字节数据的读写*************/
u16_write.a = 1234;
for(i=0;i<sizeof(s16);i++)
{
vWrite_EEPROM(0x30+i,u16_write.b[i]);
}
for(i=0;i<sizeof(s16);i++)
{
u16_read.b[i]=ucRead_EEPROM(0x30+i);
}
/***************负数的读写*************/
s16_write.a = -1234;
for(i=0;i<sizeof(s16);i++)
{
vWrite_EEPROM(0x20+i,s16_write.b[i]);
}
for(i=0;i<sizeof(s16);i++)
{
s16_read.b[i]=ucRead_EEPROM(0x20+i);
}
/***************float小数的读写**************/
float_write.a = 3.1415926;
for(i=0;i<sizeof(float);i++)
{
vWrite_EEPROM(0x10+i,float_write.b[i]);
}
for(i=0;i<sizeof(float);i++)
{
float_read.b[i]=ucRead_EEPROM(0x10+i);
}
}
//数码管操作函数
void vSMG_Process()
{
smg_buf[0]=0x00;
smg_buf[1]=0x00;
smg_buf[2]=0x00;
smg_buf[3]=0x00;
smg_buf[4]=0x00;
smg_buf[5]=0x00;
smg_buf[6]=0x00;
smg_buf[7]=0x00;
}
void main(void)
{
vSystem_Init();
vEEPROM_Process();
vTimer2_Init();
while(1)
{
vSMG_Process();
}
}
//中断服务程序
void vTimer2_ISR() interrupt 12 //中断入口
{
vSMG_Display();
}
以上所有工程文件见百度云
链接:https://pan.baidu.com/s/1p95KCRzdqfjCsS7-pO6lyg
提取码:1815