完整的51单片机EEPROM 使用代码!
版权声明:此文章与内容皆为科技小宅神原创!仅供参考学习,禁止一切商用目的与盈利用途!违者必究!
#ifndef _EEPROM51_H_
#define _EEPROM51_H_
/********STC89C51扇区分布*******
第一扇区:1000H--11FF
第二扇区:1200H--13FF
第三扇区:1400H--15FF
第四扇区:1600H--17FF
第五扇区:1800H--19FF
第六扇区:1A00H--1BFF
第七扇区:1C00H--1DFF
第八扇区:1E00H--1FFF
*****************/
/********STC89C52扇区分布*******
第一扇区:2000H--21FF
第二扇区:2200H--23FF
第三扇区:2400H--25FF
第四扇区:2600H--27FF
第五扇区:2800H--29FF
第六扇区:2A00H--2BFF
第七扇区:2C00H--2DFF
第八扇区:2E00H--2FFF
*****************/
//注释:本程序是对51和52本身自带的eeprom的操作!
//完全按照芯片数据手册编写
//定义ISP的操作命令
#define RdCommand 0x01 //对用户的应用程序flash区及数据flash区字节读
#define PrgCommand 0x02 //对用户的应用程序flash区及数据flash区字节编程
#define EraseCommand 0x03 //对用户的应用程序flash区及数据flash区扇区擦除
#define Error 1 //应答1
#define Ok 0 //应答0
#define WaitTime 0x01 //定义CPU的等待时间
//寄存器申明(寄存器地址)
sfr ISP_DATA=0xe2; //Flash数据寄存器
sfr ISP_ADDRH=0xe3; //Flash高字节地址寄存器
sfr ISP_ADDRL=0xe4; //Flash低字节地址寄存器
sfr ISP_CMD=0xe5; //Flash命令模式寄存器
sfr ISP_TRIG=0xe6; //Flash命令触发寄存器
sfr ISP_CONTR=0xe7; //ISP/IAP 控制寄存器 从Flash读出的数据放在此处,向Flash写入的数据也需放在此处。
// ==========打开 ISP,IAP 功能 ============ //
void ISP_IAP_enable(void)
{
EA = 0;
// 关中断, 此时各中断请求,会被挂起,一开中断,立即响应
ISP_CONTR = ISP_CONTR & 0x18;
// 0001,1000
// 左到右看,第一个0:ISPEN: ISP/IAP 功能允许位 —— 0:禁止ISP/IAP编程改变Flash,1:允许编程改变 Flash
// 左到右看,第二个0:SWBS —— 软件选择从用户主程序区启动 ( 0 ),还是从 ISP 程序区启动( 1 )。
// 左到右看,第三个0:SWRST —— 0: 不操作; 1: 产生软件系统复位,硬件自动清零。
// 左到右看,第四个1: 无意义,此处填1、0都可
// 左到右看,第五个1: 无意义,此处填1、0都可
// 左到右看,第6-8的0: WT2-WT1-WT0 ——为CPU等待时间(周期),000为40MHZ。
ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
ISP_CONTR = ISP_CONTR | 0x80; //ISPEN=1 允许ISP/IAP 操作 此两句可以合成一句,并且只送一次就够了
}
// ==========关闭 ISP,IAP 功能 ============= //
void ISP_IAP_disable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f;
// ISPEN = 0 0:禁止ISP/IAP编程改变Flash
ISP_TRIG = 0x00;
//防止ISP/IAP 命令误触发
EA = 1;
//开中断
}
// ========== 公用的触发代码 ============== //
void ISPgoon(void)
{
ISP_IAP_enable(); //打开 ISP,IAP 功能
ISP_TRIG = 0x46;
//触发ISP_IAP命令字节1 先送46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此
ISP_TRIG = 0xb9;
//触发ISP_IAP命令字节2 送完 B9h 后,ISP/IAP 命令立即被触发起动
_nop_();
//数据读出到 ISP_DATA 寄存器后,CPU 继续执行程序
}
// ============== 字节读 ================= //
unsigned char byte_read(unsigned int byte_addr)
{
EA = 0;
//---地址需要改变时才需重新送地址
ISP_ADDRH = (unsigned char)(byte_addr >> 8);
//地址赋值
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
//---送字节读命令,命令不需改变时,不需重新送命令
ISP_CMD = ISP_CMD & 0xf8; //清除低3位
ISP_CMD = ISP_CMD | RdCommand; //写入读命令
ISPgoon(); //触发执行
ISP_IAP_disable(); //关闭ISP,IAP功能
EA = 1;
return (ISP_DATA); //返回读到的数据
// CPU等待 IAP 动作完成后,才会继续执行程序,要先关中断(EA ),
//再送 46h,B9h 到 ISP/IAP 触发寄存器,起动ISP/IAP 命令,关中断在触发之前即可
}
// ============= 扇区擦除================ //
void SectorErase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
//---地址需要改变时才需重新送地址
iSectorAddr = (sector_addr & 0xfe00);
//取扇区地址
ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
ISP_ADDRL = 0x00;
//送扇区擦除命令,命令不需改变时,不需重新送命令
ISP_CMD = ISP_CMD & 0xf8; //清空低3位
ISP_CMD = ISP_CMD | EraseCommand; //擦除命令
ISPgoon(); //触发执行
ISP_IAP_disable(); //关闭ISP,IAP功能
}
// ============ 字节写 ============//
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
EA = 0;
//---地址需要改变时才需重新送地址
ISP_ADDRH = (unsigned char)(byte_addr >> 8);
// 取地址
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
//送字节编程命令
ISP_CMD = ISP_CMD & 0xf8; //清低3位
ISP_CMD = ISP_CMD | PrgCommand; //写命令2
ISP_DATA = original_data; //写入数据准备
ISPgoon(); // 触发执行
ISP_IAP_disable(); // 关闭IAP功能
EA =1;
//开中断,CPU 处理完 ISP/IAP 动作即可开中断
// CPU等待 IAP 动作完成后,才会继续执行程序,要先关中断(EA ),
//再送 46h,B9h 到 ISP/IAP 触发寄存器,起动ISP/IAP 命令,关中断在触发之前即可
}
#endif