一、概述:
STC8H系统单片机内部集成了大容量的EEPROM,这是传统C51单片机所不具备,例如:STC8H8K64U单片机内部集成了64K的EEPROM的存储空间,绝大一部分用作存储用户程序外其中一部分可以划分出来用于存储用户数据,而传统的c51单片机用户数据的存储必须外挂24CXX等芯片实现,除了宝贵IO资源浪费外,存储速度慢。
内部EEPROM操作具体来说分为三种:读、写、擦除。其中读的速度最快,写操作的前提是必须先擦除操作。读操作有两种方式可以实现,第一种是IAP方式,按照IAP流程完成数据的读取,第二种方式是MOVC寻址方式。每次擦除以块的方式完成,每一个块的大小为512字节,即每次擦除最小操作大小为512字节,但不管是读还是写,最小操作单位为1字节,写操作之前必须是完成过的擦除操作。
以下的程序按下K1,数码管在原来的数字的基础上加1,并存入EEPROM中,重启后可读取存入的数据值,K2为手动擦除操作。
二、知识链接:
1、IAP控制寄存器(IAP_CONTR):
其中IAPEN为IAP的使能位,置1时可进行IAP操作。
2、TPS时间设置:
设置TPS的时间操作,这个时间与工作频率同步,当sysclk=12M,TPS=12。
3、命令寄存器(IAP_CMD):
当CMD=1时读操作,当CMD=2时写操作,当CMD=3时擦除操作
4、地址计算:
例如:以STC8H8K64U型号为例,已知EEPROM=64K,其中ISP下载时设定用户EEPROM=4K,程序大小60K。
用户EEPROM的IAP起始地址为:0x0000,可读、写、擦
MOVC起起始地址为:60*1024=64110=0xF000
三、实验平台搭建:
1、MCU:STC-打狗棒系列核心实验板 V2.3
2、实验板平台:德飞莱LY-51s
3、硬件连接表:
K0------>P20 按键加1并存入0x0000
K1------>P21 按下擦除起始0x0000
数码管----->P0 指示存入的值
四、测试源代码:
#include <STC8H.h>
#include "intrins.h"
sbit Led1=P0^0;
sbit Led2=P0^1;
sbit Led3=P0^2;
sbit Led4=P0^3;
#define Offset 0xF000
unsigned char code Num[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
void EEPROM_Eraser(unsigned int addr);//擦除操作
unsigned char EEPROM_Read(unsigned int addr);//读操作
unsigned char Movc_read(unsigned int addr);//寻址方式读
void EEPROM_Write(unsigned int addr,unsigned char dat);//写操作
void Delay1ms(unsigned char x);//当主时钟频率为12M,1ms延时为基准
void init_IO();//初始化IO
void main()
{
unsigned char i=0;
P_SW2 |= 0x80; //扩展寄存器XFR访问使能
init_IO();
//EEPROM_Write(0x0000,8);
//EEPROM_Eraser(0x0000);
//Delay1ms(200);
//i=EEPROM_Read(0x0000);
while(1)
{
i=0;
//i=EEPROM_Read(0x0000);
i=Movc_read(0x0000);//寻址方式读
Delay1ms(100);
P0=Num[i];
if(P20==0)//K0按下时存储值加1
{
Delay1ms(50);
if(P20==0)
{
i=EEPROM_Read(0x0000);
Delay1ms(1);
EEPROM_Eraser(0x0000);
Delay1ms(1);
EEPROM_Write(0x0000,i+1);//写之前必须先擦除
Delay1ms(1);
while(!P20);
}
}
if(P21==0)//K1按下时清空所有值
{
Delay1ms(50);
if(P21==0)
{
EEPROM_Eraser(0x0000);
Delay1ms(200);
while(!P21);
}
}
}
}
void init_IO()
{
RSTCFG=0x50; //开启RST键进入ISP模式
P0M1 = 0x11; P0M0 = 0x11; //设置P0口为开漏模式
P1M1 = 0x00; P1M0 = 0x00; //设置P1口为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置P2口为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置P3口为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置P3口为准双向口
}
void Delay1ms(unsigned char x) //@12.000MHz
{
unsigned char i, j;
while(x--)
{
i = 16;
j = 147;
do
{
while (--j);
} while (--i);
}
}
void EEPROM_Eraser(unsigned int addr)
{
IAP_CONTR=0x80;//开IAP
IAP_TPS=0x0C;//设置操作时间
IAP_CMD=0x03;//擦除命令
IAP_ADDRH=addr>>8;//取地址高位
IAP_ADDRL=addr;//取地址低位
IAP_TRIG=0x5A;//开始执行
IAP_TRIG=0xA5;
IAP_CONTR=0x00;//关闭IAP,清空数据
IAP_TRIG=0;
IAP_ADDRL=0;
IAP_ADDRH=0;
IAP_DATA=0;
}
unsigned char EEPROM_Read(unsigned int addr)
{
unsigned char i=0;
IAP_CONTR=0x80;//开IAP
IAP_TPS=0x0C;//设置操作时间
IAP_CMD=0x01;//读命令
IAP_ADDRH=addr>>8;//取地址高位
IAP_ADDRL=addr;//取地址低位
IAP_TRIG=0x5A;//开始执行
IAP_TRIG=0xA5;
i=IAP_DATA;
IAP_CONTR=0x00;//关闭IAP
IAP_TRIG=0;
IAP_ADDRL=0;
IAP_ADDRH=0;
IAP_DATA=0;
return i; //读取
}
void EEPROM_Write(unsigned int addr,unsigned char dat)
{
IAP_CONTR=0x80;//开IAP
IAP_TPS=0x0C;//设置操作时间
IAP_CMD=0x02;//写命令
IAP_ADDRH=addr>>8;//取地址高位
IAP_ADDRL=addr;//取地址低位
IAP_DATA=dat;//存放值
IAP_TRIG=0x5A;//开始执行
IAP_TRIG=0xA5;
IAP_CONTR=0x00;//关闭IAP
IAP_TRIG=0;
IAP_ADDRL=0;
IAP_ADDRH=0;
IAP_DATA=0;
}
unsigned char Movc_read(unsigned int addr)
{
addr+=Offset;
return *(char code *)(addr);
}