以前在STC官网上下载的EEPROM的例子程序,用到STC12C5608AD,经过反复测试,得出结果是不行的,后在网上搜索得到下面修改后的代码,通过测试,EEPROM可以字节读取、字节编辑、扇擦出的操作。
下面是修改后的代码,代码只需要保存为*.C就可以了,要用到头文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #include "stc12c56xxad.h" typedef unsigned char uchar; typedef unsigned int uint; #define ISP_IAP_BYTE_READ 0x1; //字节读 #define ISP_IAP_BYTE_PROGRAM 0x2; //字节编程, 可以将1 写成0 ,要将1 变成0 ,必须执行字节编程 #define ISP_IAP_SECTOR_ERASE 0x3; //扇区擦除, 可以将0 擦成1 ,要将0 变成1 ,必须擦除整个扇区 //定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数 //#define ENABLE_ISP 0x80 //系统工作时钟<30MHz 时,对IAP_CONTR 寄存器设置此值 #define ENABLE_ISP 0x81; //系统工作时钟<24MHz 时,对ISP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x82 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x84 //系统工作时钟<6MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x85 //系统工作时钟<3MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x86 //系统工作时钟<2MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x87 //系统工作时钟<1MHz 时,对IAP_CONTR 寄存器设置此值 void iap_disable () { ISP_ADDRL = 0xff; ISP_ADDRH = 0xff; ISP_CONTR = 0; //关闭 IAP 功能 ISP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用 ISP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用 } uchar byte_read (uint address){ uchar i; ISP_ADDRL = address; //设置目标单元地址 ISP_ADDRH = address >> 8; ISP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置 Flash 操作等待时间 ISP_CMD = ISP_IAP_BYTE_READ; //设置为IAP/ISP/EEPROM 字节读模式命令 //EA=0; ISP_TRIG = 0x46; ISP_TRIG = 0xb9; //先送46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此,送完B9h 后,ISP/IAP 命令立即被触发起动 for (i = 0;i < 30;i++); //EA=1; iap_disable (); //;关闭 IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 i = ISP_DATA; //读出的数据在ISP_DATA 单元中,送入累加器A return i; } void byte_program (uint address,uchar wr_data) { uchar i; ISP_ADDRL = address; //设置目标单元地址 ISP_ADDRH = address >> 8; ISP_DATA = wr_data; //要编程的数据先送进ISP_DATA 寄存器 ISP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置 Flash 操作等待时间 ISP_CMD = ISP_IAP_BYTE_PROGRAM; //设置为IAP/ISP/EEPROM 字节编程模式命令 //EA=0; ISP_TRIG = 0x46; ISP_TRIG = 0xb9; //先送46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此,送完B9h 后,ISP/IAP 命令立即被触发起动 for (i = 0;i < 30;i++); //EA=1; iap_disable (); //;关闭 IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态 } void sector_erase (uint address) { uchar i; ISP_ADDRL = address; //设置目标单元地址 ISP_ADDRH = address >> 8; ISP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置 Flash 操作等待时间 ISP_CMD = ISP_IAP_SECTOR_ERASE; //设置为IAP/ISP/EEPROM 扇区擦除模式命令 //EA=0; ISP_TRIG = 0x46; ISP_TRIG = 0xb9; //先送46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此,送完B9h 后,ISP/IAP 命令立即被触发起动 for (i = 0;i < 30;i++); //EA=1; iap_disable (); } |
原始官方代码(当然测试程序也没有说可以支持STC12C56XXAD系列的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | /* 一个完整的EEPROM 测试程序,用宏晶的下载板可以直接测试 STC12C5AxxAD 系列单片机 EEPROM/IAP 功能测试程序演示 STC12C52xxAD 系列单片机 EEPROM/IAP 功能测试程序演示 STC11xx 系列单片机 EEPROM/IAP 功能测试程序演示 STC10xx 系列单片机 EEPROM/IAP 功能测试程序演示 --- STC International Limited ------------------ --- 宏晶科技 设计 2009/1/12 V1.0 -------------- --- Mobile: 13922805190 ------------------------ --- Fax: 0755-82944243 ------------------------- --- Tel: 0755-82948412 ------------------------- --- Web: www.MCU-Memory.com -------------------- 本演示程序在STC-ISP Ver 3.0A.PCB 的下载编程工具上测试通过,EEPROM 的数据 在P1 口上显示, 如果要在程序中使用或在文章中引用该程序,请在程序中或文章中 注明使用了宏晶科技的资料及程序 */ #include <reg51.H> #include <intrins.H> typedef unsigned char INT8U; typedef unsigned int INT16U; sfr IAP_DATA = 0xC2; sfr IAP_ADDRH = 0xC3; sfr IAP_ADDRL = 0xC4; sfr IAP_CMD = 0xC5; sfr IAP_TRIG = 0xC6; sfr IAP_CONTR = 0xC7; //定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数 //#define ENABLE_ISP 0x80 //系统工作时钟<30MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x81 //系统工作时钟<24MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x82 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值 #define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x84 //系统工作时钟<6MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x85 //系统工作时钟<3MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x86 //系统工作时钟<2MHz 时,对IAP_CONTR 寄存器设置此值 //#define ENABLE_ISP 0x87 //系统工作时钟<1MHz 时,对IAP_CONTR 寄存器设置此值 #define DEBUG_DATA 0x5A //本测试程序最终存储在 EEPROM 单元的数值 #define DATA_FLASH_START_ADDRESS 0x00 //STC5Axx 系列 EEPROM 测试起始地址 union union_temp16 { INT16U un_temp16; INT8U un_temp8[2]; }my_unTemp16; INT8U Byte_Read(INT16U add); //读一字节,调用前需打开IAP 功能 void Byte_Program(INT16U add, INT8U ch); //字节编程,调用前需打开IAP 功能 void Sector_Erase(INT16U add); //擦除扇区 void IAP_Disable(); //关闭IAP 功能 void Delay(); void main (void) { INT16U eeprom_address; INT8U read_eeprom; P1 = 0xF0; //演示程序开始,让 P1[3:0] 控制的灯亮 Delay(); //延时 P1 = 0x0F; //演示程序开始,让 P1[7:4] 控制的灯亮 Delay() ; //延时 //将EEPROM 测试起始地址单元的内容读出 eeprom_address = DATA_FLASH_START_ADDRESS; //将测试起始地址送eeprom_address read_eeprom = Byte_Read(eeprom_address); //读EEPROM的值,存到read_eeprom if (DEBUG_DATA == read_eeprom) { //数据是对的,亮 P1.7 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来 P1 = ~0x80; Delay() ; //延时 P1 = ~read_eeprom; } else { //数据是错的,亮 P1.3 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来 //再将该EEPROM所在的扇区整个擦除,将正确的数据写入后,亮 P1.5 控制的灯 P1 = ~0x08; Delay() ; //延时 P1 = ~read_eeprom; Delay() ; //延时 Sector_Erase(eeprom_address); //擦除整个扇区 Byte_Program(eeprom_address, DEBUG_DATA);//将 DEBUG_DATA 写入 EEPROM P1 = ~0x20; //熄灭 P1.3 控制的灯,亮 P1.5 控制的灯 } while (1); //CPU 在此无限循环执行此句 } //读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节 INT8U Byte_Read(INT16U add) { IAP_DATA = 0x00; IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令 my_unTemp16.un_temp16 = add; IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址 IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址 //EA = 0; IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动 _nop_(); //EA = 1; IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 return (IAP_DATA); } //字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据 void Byte_Program(INT16U add, INT8U ch) { IAP_CONTR = ENABLE_ISP; //打开 IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令 my_unTemp16.un_temp16 = add; IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址 IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址 IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器 //EA = 0; IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动 _nop_(); //EA = 1; IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 } //擦除扇区, 入口:DPTR = 扇区地址 void Sector_Erase(INT16U add) { IAP_CONTR = ENABLE_ISP; //打开IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令 my_unTemp16.un_temp16 = add; IAP_ADDRH = my_unTemp16.un_temp8[0]; //设置目标单元地址的高8 位地址 IAP_ADDRL = my_unTemp16.un_temp8[1]; //设置目标单元地址的低8 位地址 //EA = 0; IAP_TRIG = 0x5A; //先送 5Ah,再送A5h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xA5; //送完A5h 后,ISP/IAP 命令立即被触发起动 _nop_(); //EA = 1; IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 } void IAP_Disable() { //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 IAP_CONTR = 0; //关闭IAP 功能 IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用 IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用 IAP_ADDRH = 0; IAP_ADDRL = 0; } void Delay() { INT8U i; INT16U d=5000; while (d--) { i=255; while (i--); } } |