STC89C51、52內(nèi)部都自帶有2K字節(jié)的EEPROM,54、55和58都自帶有16K字節(jié)的EEPROM,STC單片機是利用IAP技術(shù)實現(xiàn)的EEPROM,內(nèi)部Flash擦寫次數(shù)可達(dá)100,000 次以上,先來介紹下ISP與IAP的區(qū)別和特點。
知識點:ISP與IAP介紹
ISP:In System Programable 是指在系統(tǒng)編程,通俗的講,就是片子已經(jīng)焊板子上,不用取下,就可以簡單而方便地對其進(jìn)行編程。比如我們通過電腦給STC單片機下載程序,或給AT89S51單片機下載程序,這就是利用了ISP技術(shù)。
IAP:In Application Programable 是指在應(yīng)用編程,就是片子提供一系列的機制(硬件/軟件上的)當(dāng)片子在運行程序的時候可以提供一種改變flash數(shù)據(jù)的方法。通俗點講,也就是說程序自己可以往程序存儲器里寫數(shù)據(jù)或修改程序。這種方式的典型應(yīng)用就是用一小段代碼來實現(xiàn)程序的下載,實際上單片機的ISP功能就是通過IAP技術(shù)來實現(xiàn)的,即片子在出廠前就已經(jīng)有一段小的boot程序在里面,片子上電后,開始運行這段程序,當(dāng)檢測到上位機有下載要求時,便和上位機通信,然后下載數(shù)據(jù)到存儲區(qū)。大家要注意千萬不要嘗試去擦除這段ISP引導(dǎo)程序,否則恐怕以后再也下載不了程序了。
STC單片機內(nèi)部有幾個專門的特殊功能寄存器負(fù)責(zé)管理ISP/IAP功能的,見表1。
表1 ISP/IAP相關(guān)寄存器列表
名稱地址功能描述D7D6D5D4D3D2D1D0復(fù)位值ISP_DATAE2hFlash數(shù)據(jù)寄存器
1111 1111ISP_ADDRHE3hFlash高字節(jié)地址寄存器
0000 0000ISP_ADDRLE4hFlash低字節(jié)地址寄存器
0000 0000ISP_CMDE5hFlash命令模式寄存器----------MS2MS1MS0xxxx x000ISP_TRIGE6hFlash命令觸發(fā)寄存器
xxxx xxxxISP_CONTRE7hISP/IAP 控制寄存器ISPENSWBSSWRST----WT2WT1WT0000x x000
ISP_DATA:ISP/IAP操作時的數(shù)據(jù)寄存器。
ISP/IAP從Flash讀出的數(shù)據(jù)放在此處,向Flash寫入的數(shù)據(jù)也需放在此處。
ISP_ADDRH:ISP/IAP操作時的地址寄存器高八位。
ISP_ADDRL:ISP/IAP操作時的地址寄存器低八位。
ISP_CMD:ISP/IAP操作時的命令模式寄存器,須命令觸發(fā)寄存器觸發(fā)方可生效。命令模式如表2所示。
表2 ISP_CMD寄存器模式設(shè)置
D7D6D5D4D3D2D1D0模式選擇保留命令選擇
----------000待機模式,無ISP操作----------001對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)讀----------010對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)編程----------011對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)扇區(qū)擦除
程序在系統(tǒng)ISP程序區(qū)時可以對用戶應(yīng)用程序區(qū)/數(shù)據(jù)Flash區(qū)(EEPROM)進(jìn)行字節(jié)讀/字節(jié)編程/扇區(qū)擦除;程序在用戶應(yīng)用程序區(qū)時,僅可以對數(shù)據(jù)Flash區(qū)(EEPROM)進(jìn)行字節(jié)讀/字節(jié)編程/扇區(qū)擦除。STC89C51RC/RD+系列單片機出廠時已經(jīng)固化有ISP引導(dǎo)碼,并設(shè)置為上電復(fù)位進(jìn)入ISP程序區(qū),并且出廠時就已完全加密。
ISP_TRIG:ISP/IAP操作時的命令觸發(fā)寄存器。
在ISPEN(ISP_CONTR.7) =1時,對ISP_TRIG 先寫入46h,再寫入B9h,ISP/IAP命令才會生效。
STC89C52RC,STC89LE52RC單片機內(nèi)部可用Data Flash(EEPROM)的地址如表3所示,其它型號單片機請查閱相關(guān)資料。
表3 STC89C52RC、STC89LE52RC單片機內(nèi)部EEPROM地址表
第一扇區(qū)第二扇區(qū)第三扇區(qū)第四扇區(qū)起始地址結(jié)束地址起始地址結(jié)束地址起始地址結(jié)束地址起始地址結(jié)束地址2000H21FFH2200H23FFH2400H25FFH2600H27FFH第五扇區(qū)第六扇區(qū)第七扇區(qū)第八扇區(qū)起始地址結(jié)束地址起始地址結(jié)束地址起始地址結(jié)束地址起始地址結(jié)束地址2800H29FFH2A00H2BFFH2C00H2DFFH2E00H2FFFH
每個扇區(qū)為512字節(jié),建議大家在寫程序時,將同一次修改的數(shù)據(jù)放在同一個扇區(qū),方便修改,因為在執(zhí)行擦除命令時,一次最少要擦除一個扇區(qū)的數(shù)據(jù)(需要提供扇區(qū)的首地址),每次在更新數(shù)據(jù)前都必須要擦除原數(shù)據(jù)方可重新寫入新數(shù)據(jù),不能直接在原來數(shù)據(jù)基礎(chǔ)上更新內(nèi)容。
注意:上面的是數(shù)據(jù)存儲區(qū)的地址,程序存儲區(qū)地址是從0~1FFF,共8K,程序區(qū)只能是ISP編程。
以下是自己寫的這部分功能代碼,因為風(fēng)格問題,不太喜歡原著代碼,感覺自己的還嚴(yán)謹(jǐn)一點。
/****************************************************************************/
/* IAP驅(qū)動 */
/****************************************************************************/
/************************************************************************************************************************/
/*ISP/IAP相關(guān)寄存器列表*/
/*名稱地址功能描述D7D6D5D4D3D2D1D0復(fù)位值*/
/*ISP_DATAE2hFlash數(shù)據(jù)寄存器1111 1111*/
/*ISP_ADDRHE3hFlash高字節(jié)地址寄存器0000 0000*/
/*ISP_ADDRLE4hFlash低字節(jié)地址寄存器0000 0000*/
/*ISP_CMDE5hFlash命令模式寄存器----------MS2MS1MS0xxxx x000*/
/*ISP_TRIGE6hFlash命令觸發(fā)寄存器xxxx xxxx*/
/*ISP_CONTRE7hISP/IAP 控制寄存器ISPENSWBSSWRST----WT2WT1WT0000x x000*/
/************************************************************************************************************************/
/************************************************************************************/
/*ISP_CMD寄存器模式設(shè)置*/
/* D7D6D5D4D3D2D1D0模式選擇*/
/*保留命令選擇*/
/* ----------000待機模式,無ISP操作*/
/* ----------001對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)讀*/
/* ----------010對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)字節(jié)編程*/
/* ----------011對用戶的應(yīng)用程序flash區(qū)及數(shù)據(jù)flash區(qū)扇區(qū)擦除*/
/************************************************************************************/
/*在ISPEN(ISP_CONTR.7) =1時,對ISP_TRIG 先寫入46h,再寫入B9h,ISP/IAP命令才會生效。*/
/* 定義常量 */
#define ERROR 0
#define OK 1
/* 定義Flash 操作等待時間 */
//#define WAIT_TIME 0x00 //mcu clock 40mhz
//#define WAIT_TIME 0x01 //mcu clock 20mhz
//#define WAIT_TIME 0x02 //mcu clock 10mhz
#define WAIT_TIME 0x03 //mcu clock 5mhz
sfr ISP_DATA= 0xe2; // Flash數(shù)據(jù)寄存器
sfr ISP_ADDRH= 0xe3;// Flash高字節(jié)地址寄存器
sfr ISP_ADDRL= 0xe4;// Flash低字節(jié)地址寄存器
sfr ISP_CMD= 0xe5;// Flash命令模式寄存器
sfr ISP_TRIG= 0xe6;// Flash命令觸發(fā)寄存器
sfr ISP_CONTR= 0xe7;// ISP/IAP 控制寄存器
#define CMD_READ0x01// 定義IAP的讀字節(jié)操作
#define CMD_PRGM0x02// 定義IAP的寫字節(jié)操作
#define CMD_ERASE0x03// 定義IAP的擦除扇區(qū)操作
/*********************** 打開 ISP,IAP 功能 ***********************/
static void ISPIAPEnable(void)
{
//EA= 0; // 關(guān)中斷
ISP_CONTR= ISP_CONTR & 0x18; // 0001,1000
ISP_CONTR= ISP_CONTR | WAIT_TIME;// 寫入硬件延時
ISP_CONTR= ISP_CONTR | 0x80; // ISPEN = 1
}
/*********************** 關(guān)閉 ISP,IAP 功能 ***********************/
static void ISPIAPDisable(void)
{
ISP_CONTR= ISP_CONTR & 0x7f;// ISPEN = 0
ISP_TRIG= 0x00;
//EA = 1; // 開中斷
}
/************************* 觸發(fā)Flash操作 *************************/
{
bit eacpy;
eacpy = EA;
EA = 0;
ISPIAPEnable();
ISP_TRIG = 0x46; // 觸發(fā)ISP_IAP命令字節(jié)1
ISP_TRIG = 0xb9; // 觸發(fā)ISP_IAP命令字節(jié)2
{UINT8 i=2; while(i--);}
ISPIAPDisable();
EA = eacpy;
}
/**************************** 讀一字節(jié) ****************************/
static UINT8 IAPReadByte(const UINT16 uiAddr)
{
ISP_ADDRH= (UINT8)(uiAddr 》》 8);// 寫地址
ISP_ADDRL= (UINT8)(uiAddr&0xFF);
ISP_CMD = ISP_CMD & 0xf8;// 清低三位
ISP_CMD = ISP_CMD | CMD_READ;// 寫入讀命令
ActiveOperate();// 觸發(fā)執(zhí)行
return (ISP_DATA); // 返回讀到的數(shù)據(jù)
}
/**************************** 寫一字節(jié) ****************************/
static void IAPWriteByte(const UINT16 uiAddr, const UINT8 ucData)
{
ISP_ADDRH= (UINT8)(uiAddr 》》 8);// 寫地址
ISP_ADDRL= (UINT8)(uiAddr&0xFF);
ISP_CMD = ISP_CMD & 0xf8;// 清低三位
ISP_CMD = ISP_CMD | CMD_PRGM;// 寫入寫命令
ISP_DATA= ucData; // 寫入數(shù)據(jù)準(zhǔn)備
ActiveOperate();// 觸發(fā)執(zhí)行
}
/**************************** 擦除一扇區(qū) ****************************/
static void IAPEarseSection(const UINT16 uiAddr)
{
UINT16uiSecAddr;
uiSecAddr= (uiAddr & 0xfe00);// 取扇區(qū)地址
ISP_ADDRH= (UINT8)(uiSecAddr 》》 8);// 寫地址
ISP_ADDRL= 0x00;
ISP_CMD= ISP_CMD & 0xf8; // 清低三位
ISP_CMD= ISP_CMD | CMD_ERASE;// 寫入擦除命令
ActiveOperate();// 觸發(fā)執(zhí)行
}
------------------------------------------------------------------------------------------------------------------------
#include//到宏晶網(wǎng)站下載頭文件或自己在現(xiàn)有的頭文件上加上相應(yīng)的寄存器定義即可。
#include
#define uchar unsigned char
#define uint unsigned int
/****************uart init***********/
void UART_inti(void)
{
AUXR=0x40;//定時器1速度是普通8051的12倍,不分頻
TMOD=0x20;//定時器1工作在方式2,用來產(chǎn)生波特率
SCON=0x50;//串口工作在方式1,允許接收
TL1=0xF7;//波特率為38400;FB為115200
TH1=0xF7;
PCON=0x00;//SMOD=0
TR1=1; //產(chǎn)生波特率
}
void ISP_write
評論