STC89C51、52內部都自帶有2K字節的EEPROM,54、55和58都自帶有16K字節的EEPROM,STC單片機是利用IAP技術實現的EEPROM,內部Flash擦寫次數可達100,000 次以上,先來介紹下ISP與IAP的區別和特點。
ISP:In System Programable 是指在系統編程,通俗的講,就是片子已經焊板子上,不用取下,就可以簡單而方便地對其進行編程。比如我們通過電腦給STC單片機下載程序,或給AT89S51單片機下載程序,這就是利用了ISP技術。
IAP:In Application Programable 是指在應用編程,就是片子提供一系列的機制(硬件/軟件上的)當片子在運行程序的時候可以提供一種改變flash數據的方法。通俗點講,也就是說程序自己可以往程序存儲器里寫數據或修改程序。這種方式的典型應用就是用一小段代碼來實現程序的下載,實際上單片機的ISP功能就是通過IAP技術來實現的,即片子在出廠前就已經有一段小的boot程序在里面,片子上電后,開始運行這段程序,當檢測到上位機有下載要求時,便和上位機通信,然后下載數據到存儲區。大家要注意千萬不要嘗試去擦除這段ISP引導程序,否則恐怕以后再也下載不了程序了。STC單片機內部有幾個專門的特殊功能寄存器負責管理ISP/IAP功能的,見表1。
表1 ISP/IAP相關寄存器列表
名稱
地址
功能描述
D7
D6
D5
D4
D3
D2
D1
D0
復位值
ISP_DATA
E2h
Flash數據寄存器
1111 1111
ISP_ADDRH
E3h
Flash高字節地址寄存器
0000 0000
ISP_ADDRL
E4h
Flash低字節地址寄存器
0000 0000
ISP_CMD
E5h
Flash命令模式寄存器
--
--
--
--
--
MS2
MS1
MS0
xxxx x000
ISP_TRIG
E6h
Flash命令觸發寄存器
xxxx xxxx
ISP_CONTR
E7h
ISP/IAP 控制寄存器
ISPEN
SWBS
SWRST
--
--
WT2
WT1
WT0
000x x000
ISP_DATA:ISP/IAP操作時的數據寄存器。
ISP/IAP從Flash讀出的數據放在此處,向Flash寫入的數據也需放在此處。
ISP_ADDRH:ISP/IAP操作時的地址寄存器高八位。
ISP_ADDRL:ISP/IAP操作時的地址寄存器低八位。
ISP_CMD:ISP/IAP操作時的命令模式寄存器,須命令觸發寄存器觸發方可生效。命令模式如表2所示。表2 ISP_CMD寄存器模式設置
D7
D6
D5
D4
D3
D2
D1
D0
模式選擇
保留
命令選擇
--
--
--
--
--
0
0
0
待機模式,無ISP操作
--
--
--
--
--
0
0
1
對用戶的應用程序flash區及數據flash區字節讀
--
--
--
--
--
0
1
0
對用戶的應用程序flash區及數據flash區字節編程
--
--
--
--
--
0
1
1
對用戶的應用程序flash區及數據flash區扇區擦除
程序在系統ISP程序區時可以對用戶應用程序區/數據Flash區(EEPROM)進行字節讀/字節編程/扇區擦除;程序在用戶應用程序區時,僅可以對數據Flash區(EEPROM)進行字節讀/字節編程/扇區擦除。STC89C51RC/RD+系列單片機出廠時已經固化有ISP引導碼,并設置為上電復位進入ISP程序區,并且出廠時就已完全加密。
ISP_TRIG:ISP/IAP操作時的命令觸發寄存器。
在ISPEN(ISP_CONTR.7)=1時,對ISP_TRIG 先寫入46h,再寫入B9h,ISP/IAP命令才會生效。
STC89C52RC,STC89LE52RC單片機內部可用DataFlash(EEPROM)的地址如表3所示,其它型號單片機請查閱相關資料。
表3STC89C52RC、STC89LE52RC單片機內部EEPROM地址表
第一扇區
第二扇區
第三扇區
第四扇區
起始地址
結束地址
起始地址
結束地址
起始地址
結束地址
起始地址
結束地址
2000H
21FFH
2200H
23FFH
2400H
25FFH
2600H
27FFH
第五扇區
第六扇區
第七扇區
第八扇區
起始地址
結束地址
起始地址
結束地址
起始地址
結束地址
起始地址
結束地址
2800H
29FFH
2A00H
2BFFH
2C00H
2DFFH
2E00H
2FFFH
每個扇區為512字節,建議大家在寫程序時,將同一次修改的數據放在同一個扇區,方便修改,因為在執行擦除命令時,一次最少要擦除一個扇區的數據,每次在更新數據前都必須要擦除原數據方可重新寫入新數據,不能直接在原來數據基礎上更新內容。
下面通過一個例子來講解STC系列單片機EEPROM的具體用法。
【例】:在實驗板上實現如下描述,操作STC單片機自帶的EEPROM,存儲一組按秒遞增的二位數據,并且將數據實時顯示在數碼管上,數據每變化一次就往EEPROM中寫入一次,當關閉實驗板電源,再次開啟電源時,從EEPROM中讀取先前存儲的數據,接著遞增顯示。
#include
#include //52系列單片機頭文件
#define uchar unsigned char
#define uint unsigned int
#define RdCommand 0x01 //定義ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定義CPU的等待時間
sfr ISP_DATA=0xe2;//寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
sbit dula=P2^6;//申明U1鎖存器的鎖存端
sbit wela=P2^7;//申明U2鎖存器的鎖存端
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uchar num;
void delayms(uint xms)
{
uint i,j;
for(i=xms;i》0;i--)//i=xms即延時約xms毫秒
for(j=110;j》0;j--);
}
void display(uchar shi,uchar ge)//顯示子函數
{
dula=1;
P0=table[shi];//送十位段選數據
dula=0;
P0=0xff;//送位選數據前關閉所有顯示,防止打開位選鎖存時
wela=1;//原來段選數據通過位選鎖存器造成混亂
P0=0xfe;//送位選數據
wela=0;
delayms(5); //延時
dula=1;
P0=table[ge];//送個位段選數據
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delayms(5);
}
void ISP_IAP_enable(void)
{
EA = 0;
ISP_CONTR =ISP_CONTR & 0x18;
ISP_CONTR =ISP_CONTR | WaitTime;
ISP_CONTR =ISP_CONTR | 0x80;
}
void ISP_IAP_disable(void)
{
ISP_CONTR =ISP_CONTR & 0x7f;
ISP_TRIG = 0x00;
EA=1;
}
void ISPgoon(void)
{
ISP_IAP_enable();
ISP_TRIG =0x46;
ISP_TRIG =0xb9;
_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= ISP_CMD & 0xf8;
ISP_CMD= ISP_CMD | RdCommand;
ISPgoon();
ISP_IAP_disable();
return(ISP_DATA);
}
void SectorErase(unsigned int sector_addr)
{
unsigned intiSectorAddr;
iSectorAddr =(sector_addr & 0xfe00);
ISP_ADDRH =(unsigned char)(iSectorAddr 》》 8);
ISP_ADDRL =0x00;
ISP_CMD =ISP_CMD & 0xf8;
ISP_CMD = ISP_CMD| EraseCommand;
ISPgoon();
ISP_IAP_disable();
}
void byte_write(unsigned int byte_addr, unsigned charoriginal_data)
{
ISP_ADDRH =(unsigned char)(byte_addr 》》 8);
ISP_ADDRL =(unsigned char)(byte_addr & 0x00ff);
ISP_CMD= ISP_CMD & 0xf8;
ISP_CMD= ISP_CMD | PrgCommand;
ISP_DATA =original_data;
ISPgoon();
ISP_IAP_disable();
}
void main()
{
uchar a,b,num1;
TMOD=0x01; //設置定時器0為工作方式1(0000 0001)
TH0=(65536-50000)/256;
TL0=(65536-50000)%6;
EA=1;
ET0=1;
TR0=1;
num1=byte_read(0x2000);//程序開始時讀取EEPROM中數據
if(num1》=60)//防止首次上電時讀取出錯
num1=0;
while(1)
{
if(num》=20)
{
num=0;
num1++;
SectorErase(0x2000);//擦除扇區
byte_write(0x2000,num1);//重新寫入數據
if(num1==60)
{
num1=0;
}
a=num1/10;
b=num1;
}
display(a,b);
}
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%6;
num++;
}
評論
查看更多