/* 单片机内置的 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 = 0xE2; //IAP操作时的数据寄存器(从flash读数据和写数据都在此处) sfr IAP_ADDRH = 0xE3; //IAP操作时的地址寄存器高8位 sfr IAP_ADDRL = 0xE4; // IAP操作时的地址寄存器低8位 sfr IAP_CMD = 0xE5; //IAP命令模式寄存器(需命令触发寄存器触发方生效)3种模式 sfr IAP_TRIG = 0xE6; //IAP命令触发寄存器,在IAP_CONTR.7=1时;对IAP_TRIG先写//入46h,再写入B9h,IAP命令生效 sfr IAP_CONTR = 0xE7; //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 = 0x46; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xb9; //送完 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 = 0x46; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xb9; //送完 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 = 0x46; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xb9; //送完 b9h 后,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); }
时间: 2024-10-23 02:56:29