1、/* STC89C54RD+的 flash 空间从 0x40000xf3ff 共 90 个扇区,每扇区 512 字节 */ #define BaseAddr 0x1000 /* 51rc */ #define EndSectoraddr 0x3d00 /* 51rc */ #define EndAddr 0x3fff /* 51rc 12K eeprom */#define BaseAddr 0x4000#define EndSectoraddr 0xf200#define EndAddr 0xf3ff#define UseAddr 0x1000/* - 定义扇区大小 - */#define
2、PerSector 512/* 用户程序需要记忆的数组 , 用户实际使用了 n-1 个数据,数组长度规整到2 4 8 16 32 64 上 */uchar Ttotal16 =0x55, /* 作为判别引导头使用,用户程序请不要修改它 */* 用户保存记忆的数据 */0x01, /* 用途说明*/0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,;uint timerForDelay, /* 专供延时用的变量 */i, /* 循环变量 */EepromPtr; /* eeprom 读写指针 */* - 命
3、令定义 - */#define RdCommand 0x01 /* 字节读 */#define PrgCommand 0x02 /* 字节写 */#define EraseCommand 0x03 /* 扇区擦除 */* 定义常量 */#define Error 1#define Ok 0/* 定义 Flash 对应于 20MHz 晶振系统的操作等待时间 */* 时钟倍频时 WaitTime 用 0x00*/#define WaitTime 0x01/* = 打开 ISP,IAP 功能 = */void ISP_IAP_enable(void)EA = 0; /* 关中断 */ISP_CONT
4、R = ISP_CONTR /* 0001,1000 */ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */* = 关闭 ISP,IAP 功能 = */void ISP_IAP_disable(void)ISP_CONTR = ISP_CONTR /* ISPEN = 0 */ISP_TRIG = 0x00;EA = 1; /* 开中断 */* = 公用的触发代码 = */void ISPgoon(void)ISP_IAP_enable(); /* 打开 ISP,IA
5、P 功能 */ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */_nop_();/* = 字节读 = */uchar byte_read(uint byte_addr)ISP_ADDRH = (uchar)(byte_addr 8); /* 地址赋值 */ISP_ADDRL = (uchar)(byte_addr ISP_CMD = ISP_CMD /* 清除低 3 位 */ISP_CMD = ISP_CMD | RdCommand; /* 写入读命令 */ISPgoon(); /*
6、触发执行 */ISP_IAP_disable(); /* 关闭 ISP,IAP 功能 */return (ISP_DATA); /* 返回读到的数据 */* = 扇区擦除 = */void SectorErase(uint sector_addr)uint iSectorAddr;iSectorAddr = (sector_addr /* 取扇区地址 */ISP_ADDRH = (uchar)(iSectorAddr 8);ISP_ADDRL = 0x00;ISP_CMD = ISP_CMD /* 清空低 3 位 */ISP_CMD = ISP_CMD | EraseCommand; /* 擦
7、除命令 3 */ISPgoon(); /* 触发执行 */ISP_IAP_disable(); /* 关闭 ISP,IAP 功能 */* = 字节写 = */void byte_write(uint byte_addr, uchar original_data)ISP_ADDRH = (uchar)(byte_addr 8); /* 取地址 */ISP_ADDRL = (uchar)(byte_addr ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD = ISP_CMD | PrgCommand; /* 写命令 2 */ISP_DATA = original_dat
8、a; /* 写入数据准备 */ISPgoon(); /* 触发执行 */ISP_IAP_disable(); /* 关闭 IAP 功能 */* = 字节写并校验 = */uchar byte_write_verify(uint byte_addr, uchar original_data)ISP_ADDRH = (uchar)(byte_addr 8); /* 取地址 */ISP_ADDRL = (uchar)(byte_addr ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD = ISP_CMD | PrgCommand; /* 写命令 2 */ISP_DATA
9、= original_data;ISPgoon(); /* 触发执行 */* 开始读,没有在此重复给地址,地址不会被自动改变 */ISP_DATA = 0x00; /* 清数据传递寄存器 */ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD = ISP_CMD | RdCommand; /* 读命令 1 */ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */_nop_(); /* 延时 */ISP_IAP_disable(); /* 关闭 IAP 功能 */i
10、f(ISP_DATA = original_data) /* 读写数据校验 */return Ok; /* 返回校验结果 */elsereturn Error;/* = 数组写入 = */uchar ArrayWrite(uint begin_addr, uint len, uchar *array)uint i;uint in_addr;/* 判是否是有效范围,此函数不允许跨扇区操作 */if(len PerSector)return Error;in_addr = begin_addr /* 扇区内偏移量 */if(in_addr + len) PerSector)return Error
11、;in_addr = begin_addr;/* 逐个写入并校对 */ISP_IAP_enable(); /* 打开 IAP 功能 */for(i = 0; i 8);ISP_ADDRL = (uchar)(in_addr ISP_DATA = arrayi; /* 取数据 */ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD = ISP_CMD | PrgCommand; /* 写命令 2 */ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */_nop_()
12、;/* 读回来 */ISP_DATA = 0x00;ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD = ISP_CMD | RdCommand; /* 读命令 1 */ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */_nop_();/* 比较对错 */if(ISP_DATA != arrayi)ISP_IAP_disable();return Error;in_addr+; /* 指向下一个字节 */ISP_IAP_disable();return Ok;
13、/* = 扇区读出 = */* 程序对地址没有作有效性判断,请调用方事先保证他在规定范围内 */void ArrayRead(uint begin_addr, uchar len)/ uchar xdata data_buffer; /* 整个扇区读取缓存区 */uint iSectorAddr;uint i;iSectorAddr = begin_addr; / /* 取扇区地址 */ISP_IAP_enable();for(i = 0; i 8);ISP_ADDRL = (uchar)(iSectorAddr ISP_CMD = ISP_CMD /* 清低 3 位 */ISP_CMD =
14、ISP_CMD | RdCommand; /* 读命令 1 */ISP_DATA = 0;ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */_nop_();Ttotali = ISP_DATA;iSectorAddr+;ISP_IAP_disable(); /* 关闭 IAP 功能 */* =从 eeprom 中读取数据= */void DataRestore()EepromPtr = BaseAddr; /* 指向 eeprom 的起始点 */while(EepromPtr = EndAddr) /* 如果照遍都没有,是新片*/EepromPtr = BaseAddr; /* 指向 eeprom 的起始点 */for(i=0;i=EndAddr) /* 已经用完了最后一个区域 */EepromPtr = BaseAddr; /* 从头开始 */* - 数据存入前的准备 - */* 。 。 。 。 。 。 。 。 。 。 。 。 。 。转移、处理 */Ttotal0 = 0x55; /* 重申启用标记 */if(ArrayWrite(EepromPtr, 0x10, Ttotal) /* 数据写入,如果有错换一块 */goto NextArea;