您的位置 首页 资料

STC单片机内部EEPROM的使用

单片机运行时的数据都存在于RAM(随机存储器)中,在掉电后RAM中的数据是无法保留的,那么怎样使数据在掉电后不丢失呢?这就需要使用EEPR…

单片机运转时的数据都存在于RAM(随机存储器)中,在掉电后RAM中的数据是无法保存的,那么怎样使数据在掉电后不丢掉呢?这就需求运用EEPROM或FLASHROM等存储器来完成。在传统的单片机体系中,一般是在片外扩展存储器,单片机与存储器之间经过IIC或SPI等接口来进行数据通信。这样不光会添加开发本钱,一起在程序开发上也要花更多的心思。在STC单片机中内置了EEPROM(其实是选用IAP技能读写内部FLASH来完成EEPROM),这样就节省了片外资源,运用起来也愈加便利。下面就详细介绍STC单片机内置EEPROM及其运用方法。

STC各类型单片机内置的EEPROM的容量各有不同,见下表:

单片机芯片类型

开端地址

内置EEPROM容量(每扇区512字节)

STC89C51RC,STC89LE51RC

0x2000

共八个扇区

STC89C52RC,STC89LE52RC

0x2000

共八个扇区

STC89C54RD+,STC89LE54RD+

0x8000

共五十八个扇区

STC89C55RD+,STC89LE55RD+

0x8000

共五十八个扇区

STC89C58RD+,STC89LE58RD+

0x8000

共五十八个扇区

内部EEPROM能够擦写100000次以上)

上面提到了IAP,它的意思是“在运用编程”,即在程序运转时程序存储器可由程序本身进行擦写。正是是因为有了IAP,然后能够使单片机能够将数据写入到程序存储器中,使得数据好像烧入的程序相同,掉电不丢掉。当然写入数据的区域与程序存储区要分开来,以使程序不会遭到损坏。

要运用IAP功用,与以下几个特别功用寄存器相关:

寄存器标识

地址

称号

7

6

5

4

3

2

1

0

初始值

ISP_DATA

0xE2

ISP/IAP闪存数据寄存器

11111111

ISP_ADDRH

0xE3

ISP/IAP闪存地址高位

00000000

ISP_ADDRL

0xE4

ISP/IAP闪存地址低位

00000000

ISP_CMD

0xE5

ISP/IAP闪存指令寄存器

MS2

MS1

MS0

xxxxx000

ISP_TRIG

0xE6

ISP/IAP闪存指令触发

xxxxxxxx

ISP_CONTR

0xE7

ISP/IAP操控寄存器

ISPEN

SWBS

SWRST

WT2

WT1

WT0

00xx000

ISP_DATA: ISP/IAP操作时的数据寄存器。

ISP/IAP从Flash读出的数据放在此处,向Flash写的数据也需放在此处

ISP_ADDRH:ISP/IAP操作时的地址寄存器高八位。

ISP_ADDRL:ISP/IAP操作时的地址寄存器低八位。

ISP_CMD: ISP/IAP操作时的指令形式寄存器,须指令触发寄存器触发方可收效。

B7

B6

B5

B4

B3

B2

B1

B0

指令/操作形式挑选

保存

指令挑选

0

0

0

待机形式,无ISP/IAP操作

0

0

1

对用户的运用程序Flash区及数据Flash区字节读

0

1

0

对用户的运用程序Flash区及数据Flash区字节编程

0

1

1

对用户的运用程序Flash区及数据Flash区扇区擦除

ISP_TRIG:ISP/IAP操作时的指令触发寄存器。

当ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入0x46,再写入0xb9,ISP/IAP指令才会收效。

ISP_CONTR:ISP/IAP操控寄存器。

D7

D6

D5

D4

D3

D2

D1

D0

ISPEN

SWBS

SWRST

WT2

WT1

WT0

ISPEN:ISP/IAP功用答应位。0:制止ISP/IAP编程改动Flash,1:答应编程改动Flash

SWBS:软件挑选从用户主程序区发动(0),仍是从ISP程序区发动(1)。

SWRST:0:不操作,1:发生软件体系复位,硬件主动清零。

ISP_CONTR中的SWBS与SWRST这两个功用位,能够完成单片机的软件发动,并发动到ISP区或用户程序区,这在“STC单片机主动下载”一节,亦有所运用。

如:

ISP_CONTR=0x60; 则能够完成从用户运用程序区软件复位到ISP程序区开端运转程序。

ISP_CONTR=0x20; 则能够完成从ISP程序区软件复位到用户运用程序区开端运转程序。

用IAP向Flash中读写数据,是需求必定的读写时刻的,读写数据指令宣布后,要等候一段时刻才能够读写成功。这个等候时刻便是由WT2、WT1、WT0与晶体振荡器频率决议的。

设置等候时刻

CPU等候时刻(机器周期)

WT2

WT1

WT0

读取

编程

扇区擦除

主张的体系时钟

0

1

1

6

30

5471

5MHz

0

1

0

11

60

10942

10MHz

0

0

1

22

120

21885

20MHz

0

0

0

43

240

43769

40MHz

(以上的主张时钟是(WT2、WT1、WT0)取不同的值时的标称时钟,用户体系中的时钟不要过高,不然可能使操作不稳定。)

以下是详细的完成代码:

EEPROM操作函数:

#define RdCommand 0x01

#define PrgCommand 0x02

#define EraseCommand 0x03

#define Error 1

#define Ok 0

#define WaitTime 0x01

#define PerSector 512

unsignedchar xdata Ttotal[512];

/*

———————————————————————

翻开 ISP,IAP功用

———————————————————————

*/

voidISP_IAP_enable(void)

{

EA=0;/*关中止*/

ISP_CONTR|=0x18;/*0001,1000*/

ISP_CONTR|=WaitTime;/*写入硬件延时*/

ISP_CONTR|=0x80;/*ISPEN=1*/

}

/*

———————————————————————

封闭 ISP,IAP功用

———————————————————————

*/

voidISP_IAP_disable(void)

{

ISP_CONTR&=0x7f;/* ISPEN = 0 */

ISP_TRIG=0x00;

EA=1;/*开中止 */

}

/*

———————————————————————-

共用的触发代码

———————————————————————-

*/

voidISPgoon(void)

{

ISP_IAP_enable();/*翻开 ISP,IAP功用 */

ISP_TRIG=0x46;/*触发ISP_IAP指令字节1 */

ISP_TRIG=0xb9;/*触发ISP_IAP指令字节2 */

_nop_();

}

/*

———————————————————————–

字节读

———————————————————————–

*/

unsignedchar byte_read(unsigned int byte_addr)

{

ISP_ADDRH=(unsigned char)(byte_addr>>8); /*地址赋值*/

ISP_ADDRL=(unsigned char)(byte_addr&0x00ff);

ISP_CMD&=0xf8; /*铲除低3位 */

ISP_CMD|=RdCommand;/*写入读指令*/

ISPgoon();/*触发履行*/

ISP_IAP_disable();/*封闭ISP,IAP功用*/

return ISP_DATA;/*回来读到的数据*/

}

/*

————————————————————————

扇区擦除

————————————————————————

*/

voidsectorerase(unsigned int sector_addr)

{

unsigned int iSectorAddr;

iSectorAddr=(sector_addr&0xfe00);/*取扇区地址*/

ISP_ADDRH=(unsigned char)(iSectorAddr>>8);

ISP_ADDRL=0x00;

ISP_CMD&=0xf8;/*清空低3位*/

ISP_CMD|=EraseCommand;/*擦除指令3*/

ISPgoon();/*触发履行 */

ISP_IAP_disable();/*封闭ISP,IAP功用*/

}

/*

————————————————————————————-

字节写

————————————————————————————-

*/

voidbyte_write(unsigned int byte_addr, unsigned char original_data)

{

ISP_ADDRH=(unsigned char)(byte_addr>>8); /*取地址*/

ISP_ADDRL=(unsigned char)(byte_addr & 0x00ff);

ISP_CMD&=0xf8;/*清低3位*/

ISP_CMD|=PrgCommand;/*写指令2*/

ISP_DATA=original_data;/*写入数据预备*/

ISPgoon();/*触发履行*/

ISP_IAP_disable();/*封闭IAP功用*/

}

/*

—————————————————————–

字节写并校验

—————————————————————–

*/

unsignedchar byte_write_verify(unsigned int byte_addr, unsigned char original_data)

{

ISP_ADDRH=(unsigned char)(byte_addr>>8); /*取地址*/

ISP_ADDRL=(unsigned char)(byte_addr&0xff);

ISP_CMD&=0xf8;/*清低3位*/

ISP_CMD|=PrgCommand;/*写指令2*/

ISP_DATA=original_data;

ISPgoon();/*触发履行*/

/*开端读,没有在此重复给地址,地址不会被主动改动*/

ISP_DATA=0x00;/*清数据传递寄存器*/

ISP_CMD&=0xf8;/*清低3位*/

ISP_CMD|=RdCommand;/*读指令1*/

ISP_TRIG=0x46;/*触发ISP_IAP指令字节1 */

ISP_TRIG=0xb9;/*触发ISP_IAP指令字节2 */

_nop_();/*延时*/

ISP_IAP_disable();/*封闭IAP功用*/

if(ISP_DATA==original_data)/*读写数据校验*/

return Ok;/*回来校验成果*/

else

return Error;

}

/*

————————————————————————–

数组写入

————————————————————————–

*/

unsignedchar arraywrite(unsigned int begin_addr, unsigned int len, unsigned char *array)

{

unsigned int i;

unsigned int in_addr;

/*判是否是有用规模,此函数不答应跨扇区操作 */

if(len > PerSector)

return Error;

in_addr = begin_addr & 0x01ff;/*扇区内偏移量 */

if((in_addr+len)>PerSector)

return Error;

in_addr = begin_addr;

/*逐一写入并校正 */

ISP_IAP_enable();/*翻开IAP功用 */

for(i=0;i

{

/*写一个字节 */

ISP_ADDRH=(unsigned char)(in_addr >> 8);

ISP_ADDRL=(unsigned char)(in_addr & 0x00ff);

ISP_DATA=array[i]; /*取数据 */

ISP_CMD&=0xf8;/*清低3位 */

ISP_CMD|=PrgCommand;/*写指令2 */

ISP_TRIG=0x46;/*触发ISP_IAP指令字节1 */

ISP_TRIG=0xb9;/*触发ISP_IAP指令字节2 */

_nop_();

/*读回来 */

ISP_DATA=0x00;

ISP_CMD&=0xf8;/*清低3位*/

ISP_CMD|=RdCommand;/*读指令1*/

ISP_TRIG=0x46;/*触发ISP_IAP指令字节1 */

ISP_TRIG=0xb9;/*触发ISP_IAP指令字节2 */

_nop_();

/*比较对错 */

if(ISP_DATA!=array[i])

{

ISP_IAP_disable();

return Error;

}

in_addr++;/*指向下一个字节*/

}

ISP_IAP_disable();

return Ok;

}

/*

—————————————————————————–

扇区读出

—————————————————————————–

*/

/*程序对地址没有作有用性判别,请调用前事前确保他在规则规模内 */

voidarrayread(unsigned int begin_addr, unsigned char len)

{

unsigned int iSectorAddr;

unsigned int i;

iSectorAddr = begin_addr; // & 0xfe00; /*取扇区地址*/

ISP_IAP_enable();

for(i=0;i

{

ISP_ADDRH=(unsigned char)(iSectorAddr>>8);

ISP_ADDRL=(unsigned char)(iSectorAddr & 0x00ff);

ISP_CMD&=0xf8;/*清低3位*/

ISP_CMD|=RdCommand;/*读指令1*/

ISP_DATA=0;

ISP_TRIG=0x46;/*触发ISP_IAP指令字节1 */

ISP_TRIG=0xb9;/*触发ISP_IAP指令字节2 */

_nop_();

Ttotal[i]=ISP_DATA;

iSectorAddr++;

}

ISP_IAP_disable();/*封闭IAP功用*/

}

主函数对EEPROM操作函数进行调用:

#include c51rd.h>

#include

#include

#include

inti;

voiddelay(unsigned int time)

{

while(time–);

}

voidmain()

{

_ADOS(22.1184);

//ADOS主动下载

//for(i=0;i<100;i++)

//{

//Ttotal[i]=i;

//}

//arraywrite(0x8000,100,Ttotal);

/*

第一次运转时向EEPROM中写入数据

然后再将写入函数注释掉,将从前写

入的数据读出,输出在P2口上。

*/

arrayread(0x8000,100);

for(i=0;i<100;i++)

{

P2=~Ttotal[i];

delay(10000);

}

while(1);

}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ziliao/272542.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部