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引導程序,否則恐怕以后再也下載不了程序了。
程序在系統ISP程序區時可以對用戶應用程序區/數據Flash區(EEPROM)進行字節讀/字節編程/扇區擦除;程序在用戶應用程序區時,僅可以對數據Flash區(EEPROM)進行字節讀/字節編程/扇區擦除。STC89C51RC/RD+系列單片機出廠時已經固化有ISP引導碼,並設置為上電復位進入ISP程序區,並且出廠時就已完全加密。
在ISPEN(ISP_CONTR.7) =1時,對ISP_TRIG 先寫入46h,再寫入B9h,ISP/IAP命令才會生效。
STC89C52RC,STC89LE52RC單片機內部可用Data Flash(EEPROM)的地址如表3所示,其它型號單片機請查閱相關資料。
每個扇區為512字節,建議大家在寫程序時,將同一次修改的數據放在同一個扇區,方便修改,因為在執行擦除命令時,一次最少要擦除一個扇區的數據(需要提供扇區的首地址),每次在更新數據前都必須要擦除原數據方可重新寫入新數據,不能直接在原來數據基礎上更新內容。
/****************************************************************************/
/* IAP驅動 */
/****************************************************************************/
/************************************************************************************************************************/
/*ISP/IAP相關寄存器列表*/
/*名稱地址功能描述D7D6D5D4D3D2D1D0復位值*/
/*ISP_DATAE2hFlash數據寄存器1111 1111*/
/*ISP_ADDRHE3hFlash高字節地址寄存器0000 0000*/
/*ISP_ADDRLE4hFlash低字節地址寄存器0000 0000*/
/*ISP_CMDE5hFlash命令模式寄存器----------MS2MS1MS0xxxx x000*/
/*ISP_TRIGE6hFlash命令觸發寄存器xxxx xxxx*/
/*ISP_CONTRE7hISP/IAP 控制寄存器ISPENSWBSSWRST----WT2WT1WT0000x x000*/
/************************************************************************************************************************/
/************************************************************************************/
/* ISP_CMD寄存器模式設置*/
/* D7D6D5D4D3D2D1D0模式選擇*/
/* 保留命令選擇*/
/* ----------000待機模式,無ISP操作*/
/* ----------001對用戶的應用程序flash區及數據flash區字節讀*/
/* ----------010對用戶的應用程序flash區及數據flash區字節編程*/
/* ----------011對用戶的應用程序flash區及數據flash區扇區擦除*/
/************************************************************************************/
/*在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數據寄存器
sfr ISP_ADDRH= 0xe3;// Flash高字節地址寄存器
sfr ISP_ADDRL= 0xe4;// Flash低字節地址寄存器
sfr ISP_CMD= 0xe5;// Flash命令模式寄存器
sfr ISP_TRIG= 0xe6;// Flash命令觸發寄存器
sfr ISP_CONTR= 0xe7;// ISP/IAP 控制寄存器
#define CMD_READ 0x01 // 定義IAP的讀字節操作
#define CMD_PRGM 0x02// 定義IAP的寫字節操作
#define CMD_ERASE 0x03 // 定義IAP的擦除扇區操作
/*********************** 打開 ISP,IAP 功能 ***********************/
static void ISPIAPEnable(void)
{
//EA = 0; // 關中斷
ISP_CONTR = ISP_CONTR & 0x18; // 0001,1000
ISP_CONTR = ISP_CONTR | WAIT_TIME; // 寫入硬件延時
ISP_CONTR = ISP_CONTR | 0x80; // ISPEN = 1
}
/*********************** 關閉 ISP,IAP 功能 ***********************/
static void ISPIAPDisable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f; // ISPEN = 0
ISP_TRIG = 0x00;
//EA = 1; // 開中斷
}
/************************* 觸發Flash操作 *************************/
static ActiveOperate(void)
{
bit eacpy;
eacpy = EA;
EA = 0;
ISPIAPEnable();
ISP_TRIG = 0x46; // 觸發ISP_IAP命令字節1
ISP_TRIG = 0xb9; // 觸發ISP_IAP命令字節2
{UINT8 i=2; while(i--);}
ISPIAPDisable();
EA = eacpy;
}
/**************************** 讀一字節 ****************************/
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();// 觸發執行
return (ISP_DATA); // 返回讀到的數據
}
/**************************** 寫一字節 ****************************/
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; // 寫入數據准備
ActiveOperate();// 觸發執行
}
/**************************** 擦除一扇區 ****************************/
static void IAPEarseSection(const UINT16 uiAddr)
{
UINT16uiSecAddr;
uiSecAddr = (uiAddr & 0xfe00); // 取扇區地址
ISP_ADDRH = (UINT8)(uiSecAddr >> 8);// 寫地址
ISP_ADDRL = 0x00;
ISP_CMD = ISP_CMD & 0xf8; // 清低三位
ISP_CMD = ISP_CMD | CMD_ERASE; // 寫入擦除命令
ActiveOperate();// 觸發執行
}
------------------------------------------------------------------------------------------------------------------------
#include<stc12c5410ad.h>//到宏晶網站下載頭文件或自己在現有的頭文件上加上相應的寄存器定義即可。
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
/****************uart init***********/
void UART_inti(void)
{
AUXR=0x40;//定時器1速度是普通8051的12倍,不分頻
TMOD=0x20;//定時器1工作在方式2,用來產生波特率
SCON=0x50;//串口工作在方式1,允許接收
TL1=0xF7;//波特率為38400;FB為115200
TH1=0xF7;
PCON=0x00;//SMOD=0
TR1=1; //產生波特率
}
void ISP_write(uint ISP_addr,uchar ISP_data)//stc12c5404啟始地址2800h ;IAP_CMD 1讀,2寫,3擦除
{
ISP_DATA=ISP_data; //送數據
ISP_ADDRL=ISP_addr%256;
ISP_ADDRH=ISP_addr/256;//送高低地址
ISP_CONTR=0x83;//IAP ENABLE ,SET CPU WAIT TIME
ISP_CMD=2;//寫字節模式
ISP_TRIG=0x46;
ISP_TRIG=0xB9;//觸發啟動ISP
_nop_();//等待寫入
ISP_CONTR=0x00;//禁止ISP/IAp操作
ISP_CMD=0;
ISP_TRIG=0x00;
}
uchar ISP_read(uint ISP_addr)//stc12c5404啟始地址2800h ;IAP_CMD 1讀,2寫,3擦除
{uchar recivedata;
ISP_ADDRL=ISP_addr%256;
ISP_ADDRH=ISP_addr/256;//送高低地址
ISP_CONTR=0x83;//IAP ENABLE ,SET CPU WAIT TIME
ISP_CMD=1;//寫字節模式
ISP_TRIG=0x46;
ISP_TRIG=0xB9;//觸發啟動ISP
_nop_();//等待讀
recivedata=ISP_DATA;
ISP_CONTR=0x00;//禁止ISP/IAp操作
ISP_CMD=0;
ISP_TRIG=0x00;
return recivedata;
}
void ISP_erase(uint ISP_addr)//stc12c5404啟始地址2800h ;IAP_CMD 1讀,2寫,3擦除
{ISP_ADDRL=ISP_addr%256;
ISP_ADDRH=ISP_addr/256;//送高低地址
ISP_CONTR=0x83;//IAP ENABLE ,SET CPU WAIT TIME
ISP_CMD=3;//寫字節模式
ISP_TRIG=0x46;
ISP_TRIG=0xB9;//觸發啟動ISP
_nop_();//等待擦除
ISP_CONTR=0x00;//禁止ISP/IAp操作
ISP_CMD=0;
ISP_TRIG=0x00;
}
//主程序只為測試時隨意編寫的,可以根據需要做相應的修改即可。
void main(void)
{
uchar returndata;
uint textdata=0x2660;
UART_inti();
while(1)
{SBUF=5;
while(!TI);
TI=0;
while(!RI);
RI=0;
ISP_erase(0x2800);
ISP_write(0x2800,textdata%256);
ISP_write(0x2801,textdata/256);
returndata=ISP_read(0x2800);
SBUF=returndata;
while(!TI);
TI=0;
returndata=ISP_read(0x2801);
SBUF=returndata;
while(!TI);
TI=0;
}
}
//聲明下這是應用在STC的單片機中的。不同的型號地址不一樣,改下IAP的地址即可。新出的產品像STC12C5A60S2等,觸發的命令也不一樣ISP_TRIG=0x46;ISP_TRIG=0xB9;也就是這兩條要根據手冊修改下即可。。
https://www.cnblogs.com/sky1991/archive/2012/07/01/2572168.html