STC89C51、52內(nèi)部都自帶有2K字節(jié)的EEPROM,54、55和58都自帶有16K字節(jié)的EEPROM,STC單片機(jī)是利用IAP技術(shù)實(shí)現(xiàn)的EEPROM,內(nèi)部Flash擦寫(xiě)次數(shù)可達(dá)100,000 次以上,先來(lái)介紹下ISP與IAP的區(qū)別和特點(diǎn)。
知識(shí)點(diǎn):ISP與IAP介紹
ISP:In System Programable 是指在系統(tǒng)編程,通俗的講,就是片子已經(jīng)焊板子上,不用取下,就可以簡(jiǎn)單而方便地對(duì)其進(jìn)行編程。比如我們通過(guò)電腦給STC單片機(jī)下載程序,或給AT89S51單片機(jī)下載程序,這就是利用了ISP技術(shù)。
IAP:In Application Programable 是指在應(yīng)用編程,就是片子提供一系列的機(jī)制(硬件/軟件上的)當(dāng)片子在運(yùn)行程序的時(shí)候可以提供一種改變flash數(shù)據(jù)的方法。通俗點(diǎn)講,也就是說(shuō)程序自己可以往程序存儲(chǔ)器里寫(xiě)數(shù)據(jù)或修改程序。這種方式的典型應(yīng)用就是用一小段代碼來(lái)實(shí)現(xiàn)程序的下載,實(shí)際上單片機(jī)的ISP功能就是通過(guò)IAP技術(shù)來(lái)實(shí)現(xiàn)的,即片子在出廠前就已經(jīng)有一段小的boot程序在里面,片子上電后,開(kāi)始運(yùn)行這段程序,當(dāng)檢測(cè)到上位機(jī)有下載要求時(shí),便和上位機(jī)通信,然后下載數(shù)據(jù)到存儲(chǔ)區(qū)。大家要注意千萬(wàn)不要嘗試去擦除這段ISP引導(dǎo)程序,否則恐怕以后再也下載不了程序了。
STC單片機(jī)內(nèi)部有幾個(gè)專(zhuān)門(mén)的特殊功能寄存器負(fù)責(zé)管理ISP/IAP功能的,見(jiàn)表1。
表1 ISP/IAP相關(guān)寄存器列表
名稱 |
地址 |
功能描述 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
復(fù)位值 |
ISP_DATA |
E2h |
Flash數(shù)據(jù)寄存器 |
1111 1111 | ||||||||
ISP_ADDRH |
E3h |
Flash高字節(jié)地址寄存器 |
0000 0000 | ||||||||
ISP_ADDRL |
E4h |
Flash低字節(jié)地址寄存器 |
0000 0000 | ||||||||
ISP_CMD |
E5h |
Flash命令模式寄存器 |
-- |
-- |
-- |
-- |
-- |
MS2 |
MS1 |
MS0 |
xxxx x000 |
ISP_TRIG |
E6h |
Flash命令觸發(fā)寄存器 |
xxxx xxxx | ||||||||
ISP_CONTR |
E7h |
ISP/IAP 控制寄存器 |
ISPEN |
SWBS |
SWRST |
-- |
-- |
WT2 |
WT1 |
WT0 |
000x x000 |
ISP_DATA:ISP/IAP操作時(shí)的數(shù)據(jù)寄存器。
ISP/IAP從Flash讀出的數(shù)據(jù)放在此處,向Flash寫(xiě)入的數(shù)據(jù)也需放在此處。
ISP_ADDRH:ISP/IAP操作時(shí)的地址寄存器高八位。
ISP_ADDRL:ISP/IAP操作時(shí)的地址寄存器低八位。
ISP_CMD:ISP/IAP操作時(shí)的命令模式寄存器,須命令觸發(fā)寄存器觸發(fā)方可生效。命令模式如表2所示。
表2 ISP_CMD寄存器模式設(shè)置
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
模式選擇 |
保留 |
命令選擇 |
|||||||
-- |
-- |
-- |
-- |
-- |
0 |
0 |
0 |
待機(jī)模式,無(wú)ISP操作 |
-- |
-- |
-- |
-- |
-- |
0 |
0 |
1 |
對(duì)用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)讀 |
-- |
-- |
-- |
-- |
-- |
0 |
1 |
0 |
對(duì)用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)編程 |
-- |
-- |
-- |
-- |
-- |
0 |
1 |
1 |
對(duì)用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)扇區(qū)擦除 |
程序在系統(tǒng)ISP程序區(qū)時(shí)可以對(duì)用戶應(yīng)用程序區(qū)/數(shù)據(jù)Flash區(qū)(EEPROM)進(jìn)行字節(jié)讀/字節(jié)編程/扇區(qū)擦除;程序在用戶應(yīng)用程序區(qū)時(shí),僅可以對(duì)數(shù)據(jù)Flash區(qū)(EEPROM)進(jìn)行字節(jié)讀/字節(jié)編程/扇區(qū)擦除。STC89C51RC/RD+系列單片機(jī)出廠時(shí)已經(jīng)固化有ISP引導(dǎo)碼,并設(shè)置為上電復(fù)位進(jìn)入ISP程序區(qū),并且出廠時(shí)就已完全加密。
ISP_TRIG:ISP/IAP操作時(shí)的命令觸發(fā)寄存器。
在ISPEN(ISP_CONTR.7) =1時(shí),對(duì)ISP_TRIG 先寫(xiě)入46h,再寫(xiě)入B9h,ISP/IAP命令才會(huì)生效。
STC89C52RC,STC89LE52RC單片機(jī)內(nèi)部可用Data Flash(EEPROM)的地址如表3所示,其它型號(hào)單片機(jī)請(qǐng)查閱相關(guān)資料。
表3 STC89C52RC、STC89LE52RC單片機(jī)內(nèi)部EEPROM地址表
第一扇區(qū) |
第二扇區(qū) |
第三扇區(qū) |
第四扇區(qū) | ||||
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
2000H |
21FFH |
2200H |
23FFH |
2400H |
25FFH |
2600H |
27FFH |
第五扇區(qū) |
第六扇區(qū) |
第七扇區(qū) |
第八扇區(qū) | ||||
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
起始地址 |
結(jié)束地址 |
2800H |
29FFH |
2A00H |
2BFFH |
2C00H |
2DFFH |
2E00H |
2FFFH |
每個(gè)扇區(qū)為512字節(jié),建議大家在寫(xiě)程序時(shí),將同一次修改的數(shù)據(jù)放在同一個(gè)扇區(qū),方便修改,因?yàn)樵趫?zhí)行擦除命令時(shí),一次最少要擦除一個(gè)扇區(qū)的數(shù)據(jù),每次在更新數(shù)據(jù)前都必須要擦除原數(shù)據(jù)方可重新寫(xiě)入新數(shù)據(jù),不能直接在原來(lái)數(shù)據(jù)基礎(chǔ)上更新內(nèi)容。
下面通過(guò)一個(gè)例子來(lái)講解STC系列單片機(jī)EEPROM的具體用法。
【例】:在實(shí)驗(yàn)板上實(shí)現(xiàn)如下描述,操作STC單片機(jī)自帶的EEPROM,存儲(chǔ)一組按秒遞增的二位數(shù)據(jù),并且將數(shù)據(jù)實(shí)時(shí)顯示在數(shù)碼管上,數(shù)據(jù)每變化一次就往EEPROM中寫(xiě)入一次,當(dāng)關(guān)閉實(shí)驗(yàn)板電源,再次開(kāi)啟電源時(shí),從EEPROM中讀取先前存儲(chǔ)的數(shù)據(jù),接著遞增顯示。
新建文件part3.4.4.c,程序代碼如下:
#include <intrins.h>
#include <reg52.h> //52系列單片機(jī)頭文件
#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的等待時(shí)間
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即延時(shí)約xms毫秒
for(j=110;j>0;j--);
}
void display(uchar shi,uchar ge) //顯示子函數(shù)
{
dula=1;
P0=table[shi]; //送十位段選數(shù)據(jù)
dula=0;
P0=0xff; //送位選數(shù)據(jù)前關(guān)閉所有顯示,防止打開(kāi)位選鎖存時(shí)
wela=1; //原來(lái)段選數(shù)據(jù)通過(guò)位選鎖存器造成混亂
P0=0xfe; //送位選數(shù)據(jù)
wela=0;
delayms(5); //延時(shí)
dula=1;
P0=table[ge]; //送個(gè)位段選數(shù)據(jù)
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
delayms(5);
}
/* ================ 打開(kāi) ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
EA = 0; /* 關(guān)中斷 */
ISP_CONTR = ISP_CONTR & 0x18; /* 0001,1000 */
ISP_CONTR = ISP_CONTR | WaitTime; /* 寫(xiě)入硬件延時(shí) */
ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */
}
/* =============== 關(guān)閉 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
ISP_TRIG = 0x00;
EA = 1; /* 開(kāi)中斷 */
}
/* ================ 公用的觸發(fā)代碼 ==================== */
void ISPgoon(void)
{
ISP_IAP_enable(); /* 打開(kāi) ISP,IAP 功能 */
ISP_TRIG = 0x46; /* 觸發(fā)ISP_IAP命令字節(jié)1 */
ISP_TRIG = 0xb9; /* 觸發(fā)ISP_IAP命令字節(jié)2 */
_nop_();
}
/* ==================== 字節(jié)讀 ======================== */
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; /* 清除低3位 */
ISP_CMD = ISP_CMD | RdCommand; /* 寫(xiě)入讀命令 */
ISPgoon(); /* 觸發(fā)執(zhí)行 */
ISP_IAP_disable(); /* 關(guān)閉ISP,IAP功能 */
return (ISP_DATA); /* 返回讀到的數(shù)據(jù) */
}
/* ================== 扇區(qū)擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
iSectorAddr = (sector_addr & 0xfe00); /* 取扇區(qū)地址 */
ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
ISP_ADDRL = 0x00;
ISP_CMD = ISP_CMD & 0xf8; /* 清空低3位 */
ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3 */
ISPgoon(); /* 觸發(fā)執(zhí)行 */
ISP_IAP_disable(); /* 關(guān)閉ISP,IAP功能 */
}
/* ==================== 字節(jié)寫(xiě) ======================== */
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 = ISP_CMD & 0xf8; /* 清低3位 */
ISP_CMD = ISP_CMD | PrgCommand; /* 寫(xiě)命令2 */
ISP_DATA = original_data; /* 寫(xiě)入數(shù)據(jù)準(zhǔn)備 */
ISPgoon(); /* 觸發(fā)執(zhí)行 */
ISP_IAP_disable(); /* 關(guān)閉IAP功能 */
}
void main()
{
uchar a,b,num1;
TMOD=0x01; //設(shè)置定時(shí)器0為工作方式1(0000 0001)
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
num1=byte_read(0x2000);//程序開(kāi)始時(shí)讀取EEPROM中數(shù)據(jù)
if(num1>=60) //防止首次上電時(shí)讀取出錯(cuò)
num1=0;
while(1)
{
if(num>=20)
{
num=0;
num1++;
SectorErase(0x2000);//擦除扇區(qū)
byte_write(0x2000,num1);//重新寫(xiě)入數(shù)據(jù)
if(num1==60)
{
num1=0;
}
a=num1/10;
b=num1%10;
}
display(a,b);
}
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
num++;
}
分析:程序中關(guān)健部分已經(jīng)用注釋加以說(shuō)明,請(qǐng)讀者編譯程序下載后觀察實(shí)際演示效果。
我的怎么不行 啊,只顯示倒A和6,一直就這樣
你買(mǎi)的是不是 最新的這種板子?加我qq 125739409我?guī)湍憧聪?/p>
又用上了。謝謝。。。
說(shuō)明的很好哦
阿亮666 發(fā)表于 2018-8-7 15:59
跟郭天祥的一模一樣??
歡迎光臨 (http://www.zg4o1577.cn/bbs/) | Powered by Discuz! X3.1 |