STC单片机内部EEPROM的应用

来源:本站
导读:目前正在解读《STC单片机内部EEPROM的应用》的相关信息,《STC单片机内部EEPROM的应用》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《STC单片机内部EEPROM的应用》的详细说明。
简介:在传统的单片机系统中,一般是在片外扩展存储器,单片机与存储器之间通过IIC 或SPI 等接口来进行数据通信。这样不光会增加开发成本,同时在程序开发上也要花更多的心思。在STC 单片机中内置了EEPROM(其实是采用IAP 技术读写内部FLASH 来实(EEPROM),这样就节省了片外资源,使用起来也更加方便。

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

STC 各型号单片机内置的EEPROM 的容量各有不同,见下表:(内部EEPROM 可以擦写100000 次以上)上面提到了IAP,它的意思是“在应用编程”,即在程序运行时程序存储器可由程序自

身进行擦写。正是是因为有了IAP,从而可以使单片机可以将数据写入到程序存储器中,使

得数据如同烧入的程序一样,掉电不丢失。当然写入数据的区域与程序存储区要分开来,以

使程序不会遭到破坏。

要使用IAP 功能,与以下几个特殊功能寄存器相关:

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

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

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

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

ISP_CMD: ISP/IAP 操作时的命令模式寄存器,须命令触发寄存器触发方可生效。

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

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

单片机芯片型号起始地址内置EEPROM 容量(每扇区512 字节)

STC89C51RC,STC89LE51RC 0x2000 共八个扇区

STC89C52RC,STC89LE52RC 0x2000 共八个扇区

STC89C54RD+,STC89LE54RD+ 0x8000 共五十八个扇区

STC89C55RD+,STC89LE55RD+ 0x8000 共五十八个扇区

STC89C58RD+,STC89LE58RD+ 0x8000 共五十八个扇区

寄存器标识地址名称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

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_CONTR:ISP/IAP 控制寄存器。

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 与晶体振荡器频率决定

的。(以上的建议时钟是(WT2、WT1、WT0)取不同的值时的标称时钟,用户系统中的时钟

不要过高,否则可能使操作不稳定。)

stc单片机EEPROM读写(一)

EEPROM 操作函数:

#define RdCommand 0x01

#define PrgCommand 0x02

#define EraseCommand 0x03

#define Error 1

#define Ok 0

#define WaitTime 0x01

#define PerSector 512

unsigned char xdata Ttotal[512]?

/*

打开ISP,IAP 功能

*/

void ISP_IAP_enable(void)

D7 D6 D5 D4 D3 D2 D1 D0

ISPEN SWBS SWRST - - 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

{

EA=0?/* 关中断*/

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

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

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

}

/*

关闭ISP,IAP 功能

*/

void ISP_IAP_disable(void)

{

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

ISP_TRIG=0x00?

EA=1?/* 开中断*/

}

/*

公用的触发代码

*/

void ISPgoon(void)

{

ISP_IAP_enable()?/* 打开ISP,IAP 功能*/

ISP_TRIG=0x46?/* 触发ISP_IAP 命令字节1 */

ISP_TRIG=0xb9?/* 触发ISP_IAP 命令字节2 */

_nop_()?

}

/*

字节读

*/

unsigned char 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?/* 返回读到的数据*/

}

/*

扇区擦除

*/

void sectorerase(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 功能*/

}

/*

字节写

*/

void byte_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 功能*/

}

/*

字节写并校验

*/

unsigned char 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?

}

/*

数组写入

*/

unsigned char 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<len?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?

}

/*

扇区读出

*/

/* 程序对地址没有作有效性判断,请调用前事先保证他在规定范围内*/

void arrayread(unsigned int begin_addr, unsigned char len)

{

unsigned int iSectorAddr?

unsigned int i?

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

ISP_IAP_enable()?

for(i=0?i<len?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 <stc51rd.h>

#include <intrins.h>

#include <stc_eeprom.h>

#include <ados.h>

int i?

void delay(unsigned int time)

{

while(time)

?

}

void main()

{

_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)?

}

stc单片机EEPROM读写(二)

sfr isp_data=0xe2;

sfr isp_addrh=0xe3;

sfr isp_addrl=0xe4;

sfr isp_cmd=0xe5;

sfr isp_trig=0xe6;

sfr isp_contr=0xe7;

unsigned char eeprom_read(unsigned int addres);

void eeprom_write(unsigned int address,unsigned char wdata);

void eeprom_eares(unsigned int addres);//扇区擦除。

void eeprom_eares(unsigned int addres)//扇区擦除。

{unsigned i;

isp_addrl=addres; //低位地址

isp_addrh=addres>>8; //高位地址

isp_contr=0x01;

isp_contr=isp_contr|0x80; //设时间与充ISP操作。

isp_cmd=0x03; //扇区命命令

isp_trig=0x46; //触发

isp_trig=0xb9; //触发启动。

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

isp_addrl=0xff;

isp_addrh=0xff;

isp_contr=0x00;

isp_cmd=0x00;

isp_trig=0x00;

}

void eeprom_write(unsigned int addres,unsigned char write_data)//写数据。

{unsigned char i;

isp_data=write_data; //要写入的数据。

isp_addrl=addres; //低位地址

isp_addrh=addres>>8; //高位地址

isp_contr=0x01;

isp_contr=isp_contr|0x80; //设时间与充ISP操作。

isp_cmd=0x02; //写命令

isp_trig=0x46; //触发

isp_trig=0xb9; //触发启动。

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

isp_addrl=0xff;

isp_addrh=0xff;

isp_contr=0x00;

isp_cmd=0x00;

isp_trig=0x00;

}

unsigned char eeprom_read(unsigned int addres)

{unsigned char i,z;

isp_addrl=addres; //低位地址

isp_addrh=addres>>8; //高位地址

isp_contr=0x01;

isp_contr=isp_contr|0x80; //设时间与充ISP操作。

isp_cmd=0x01; //写命令

isp_trig=0x46; //触发

isp_trig=0xb9; //触发启动。

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

isp_addrl=0xff;

isp_addrh=0xff;

isp_contr=0x00;

isp_cmd=0x00;

isp_trig=0x00;

z="isp"_data;

return(z);

}

stc单片机EEPROM读写(三)

;;; 内部EEPROM读写定义

ISP_DATA EQU 0E2H ;写入读出数据寄存器.

ISP_ADDRH EQU 0E3H ;地址寄存器高8位

ISP_ADDRL EQU 0E4H ;地址寄存器低8位

ISP_CMD EQU 0E5H ;命令模式寄存器

ISP_TRIG EQU 0E6H ;命令触发寄存器

ISP_CONTR EQU 0E7H ;ISP/IAP控制寄存器.

ISP_IAP_BYTE_READ EQU 1 ;字节读

ISP_IAP_BYTE_PROGRAM EQU 2 ;字节编程,要空才能写

ISP_IAP_SECTOR_ERASE EQU 3 ;扇区擦除,

WAIT_TIME EQU 1 ;20M以下为1

BYTE_ADDR_HIGH EQU 60H ;高位地址

BYTE_ADDR_LOW EQU 61H ;低位地址

BYTE_WRITE_DATA EQU 62H ;要写入的数据

;***********************内部EEPROM操作*************************

READ_EEPROM:MOV ISP_ADDRH,ISP_ADDRH ;送高地址

MOV ISP_ADDRL,ISP_ADDRL ;送低地址

MOV ISP_CONTR,#01h ;设置等等待时间

ORL ISP_CONTR,#80h ;允许ISP/IAP操作

MOV ISP_CMD,#01h ;送读命令

MOV ISP_TRIG,#46H ;触发

MOV ISP_TRIG,#0B9H ;触发启动.

NOP

NOP

MOV ISP_CONTR,#00H

MOV ISP_CMD,#00H

MOV ISP_TRIG,#00H

MOV ISP_ADDRH,#0FFH

MOV ISP_ADDRL,#0FFH

MOV 6AH,ISP_DATA ;读出的数据放到6AH单元中。

RET

WRITE_EARES: MOV WDT,#34H

CLR EA ;关中断

MOV ISP_ADDRH,ISP_ADDRH ;送高地址

MOV ISP_ADDRL,ISP_ADDRL ;送低地址

MOV ISP_CONTR,#1h ;设置等等待时间

ORL ISP_CONTR,#10000000B ;允许ISP/IAP操作

MOV ISP_CMD,#3h ;送扇区命令

MOV ISP_TRIG,#46H ;触发

MOV ISP_TRIG,#0B9H ;触发启动.

NOP

NOP

MOV ISP_CONTR,#00H

MOV ISP_CMD,#00H

MOV ISP_TRIG,#00H

MOV ISP_ADDRH,#0FFH

MOV ISP_ADDRL,#0FFH

SETB EA

RET

WRITE_EEPROM:MOV WDT,#34H

CLR EA

MOV ISP_DATA,BYTE_WRITE_DATA ;要写入的数据

MOV ISP_ADDRH,ISP_ADDRH ;送高地址

MOV ISP_ADDRL,ISP_ADDRL ;送低地址

MOV ISP_CONTR,#1h ;设置等等待时间

ORL ISP_CONTR,#10000000B ;允许ISP/IAP操作

MOV ISP_CMD,#02h ;送写命令

MOV ISP_TRIG,#46H ;触发

MOV ISP_TRIG,#0B9H ;触发启动.

NOP

NOP

MOV ISP_CONTR,#00H

MOV ISP_CMD,#00H

MOV ISP_TRIG,#00H

MOV ISP_ADDRH,#0FFH

MOV ISP_ADDRL,#0FFH

SETB EA ;开中断

RET

提醒:《STC单片机内部EEPROM的应用》最后刷新时间 2024-03-14 01:08:15,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《STC单片机内部EEPROM的应用》该内容的真实性请自行鉴别。