/*
单片机内置的 EEPROM测试程序
适用 :
STC12C5A60S2 只有两个扇区 0x0000~0x01FF,0x0200~02FF
测试晶振:11.05926M 12M 都可以用
功能:
读取指定地址的一个字节内容,并显示在8 P1总线上
擦除一个扇区,修改取指定地址的一个字节内容,并显示在8 P1总线上
*/
#include <reg51.h>
#include <intrins.h>
/******************EEPROM用到的sfr中的寄存器地址stc型号不同地址不同*****************************************/
sfr IAP_DATA = 0xC2; //IAP操作时的数据寄存器(从flash读数据和写数据都在此处)
sfr IAP_ADDRH = 0xC3; //IAP操作时的地址寄存器高8位
sfr IAP_ADDRL = 0xC4; // IAP操作时的地址寄存器低8位
sfr IAP_CMD = 0xC5; //IAP命令模式寄存器(需命令触发寄存器触发方生效)3种模式
sfr IAP_TRIG = 0xC6; //IAP命令触发寄存器,在IAP_CONTR.7=1时;对IAP_TRIG先写//入46h,再写入B9h,IAP命令生效
sfr IAP_CONTR = 0xC7; //IAP控制寄存器
/***********定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数(属于IAP_CONTR寄存器)***********/
#define ENABLE_ISP 0x82 //实测 12M 11.0592M 都可以使用
void DELAY_MS (unsigned int a)
{
unsigned int i;
while ( --a != 0 )
{
for (i=0;i<=600;i++);
}
}
/*************关闭IAP功能子程序*****************************/
void IAP_Disable() //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
{ //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
IAP_CONTR = 0; //关闭IAP 功能
IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用
IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
IAP_ADDRH = 0; //高八位地址清0
IAP_ADDRL = 0; //低八位地址清0
}
/**********EEPROM读一字节子程序***********************/
unsigned char Byte_Read(unsigned int add) //读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
{
IAP_DATA = 0x00; //IAP数据寄存器清0
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令
IAP_ADDRH = (unsigned char)(add>>8); //设置目标单元地址的高8 位地址
IAP_ADDRL = (unsigned char)(add&0xff); //设置目标单元地址的低8 位地址
EA = 0;
IAP_TRIG = 0x5a; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xa5; //送完 B9h 后,ISP/IAP 命令立即被触发起动
_nop_();
EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
return (IAP_DATA);
}
/************EEPROM字节编程子程序**************************/
void Byte_Program(unsigned int add,unsigned char ch) //字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
{
IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令
IAP_ADDRH = (unsigned char)(add>>8); //设置目标单元地址的高8 位地址
IAP_ADDRL = (unsigned char)(add&0xff); //设置目标单元地址的低8 位地址
IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器
EA = 0;
IAP_TRIG = 0x5a; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xa5; //送完 B9h 后,ISP/IAP 命令立即被触发起动
_nop_();
EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
/*************EEPROM擦除扇区子程序**************************/
void Sector_Erase(unsigned int add) //擦除扇区, 入口:DPTR = 扇区地址
{
IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间
IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令
IAP_ADDRH = (unsigned char)(add>>8); //设置目标单元地址的高8 位地址
IAP_ADDRL = (unsigned char)(add&0xff); //设置目标单元地址的低8 位地址
EA = 0;
IAP_TRIG = 0x5a; //先送 5ah,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
IAP_TRIG = 0xa5; //送完 a5h 后,ISP/IAP 命令立即被触发起动
_nop_();
EA = 1;
IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
//一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
}
void main (void){
unsigned char mydata1 = 0xF0;
unsigned char mydata2 = 0x0F;
unsigned int address1 = 0x0000; // 属于第一个扇区
unsigned int address2 = 0x01FF; // 属于第一个扇区
/************ 系统初始化时 读取一次两个扇区状态 ******************************/
P1 = Byte_Read(address1); //显示出来
DELAY_MS(500);
P1 = Byte_Read(address2); //显示出来
DELAY_MS(500);
/************ 擦除这个扇区的512字节 并写入显得数据 读取一次两个扇区状态 ******************************/
//Sector_Erase(address1); //无论是擦除address1还是address2
Sector_Erase(address2); //无论是擦除address1还是address2
Byte_Program(address1,mydata1);
Byte_Program(address2,mydata2);
P1 = Byte_Read(address1); //显示出来
DELAY_MS(500);
P1 = Byte_Read(address2); //显示出来
DELAY_MS(500);
/************ 擦除这个扇区的512字节 并写入显得数据 读取一次两个扇区状态 ******************************/
//Sector_Erase(address1); //无论是擦除address1还是address2
Sector_Erase(address2); //无论是擦除address1还是address2
P1 = Byte_Read(address1); //P1 的led灯都不亮
DELAY_MS(500);
P1 = Byte_Read(address2); //P1 的led灯都不亮
DELAY_MS(500);
/*
可以证明:
A和B属于用一个扇区
擦除A或者B 字节的地址
再次读取A或B 都已经改变为0xFF
*/
while(1);
}