完整的51單片機EEPROM 使用代碼!
版權聲明:此文章與內容皆為科技小宅神原創(chuàng)!僅供參考學習,禁止一切商用目的與盈利用途!違者必究!
#ifndef _EEPROM51_H_
#define _EEPROM51_H_
/********STC89C51扇區(qū)分布*******
第一扇區(qū):1000H--11FF
第二扇區(qū):1200H--13FF
第三扇區(qū):1400H--15FF
第四扇區(qū):1600H--17FF
第五扇區(qū):1800H--19FF
第六扇區(qū):1A00H--1BFF
第七扇區(qū):1C00H--1DFF
第八扇區(qū):1E00H--1FFF
*****************/
/********STC89C52扇區(qū)分布*******
第一扇區(qū):2000H--21FF
第二扇區(qū):2200H--23FF
第三扇區(qū):2400H--25FF
第四扇區(qū):2600H--27FF
第五扇區(qū):2800H--29FF
第六扇區(qū):2A00H--2BFF
第七扇區(qū):2C00H--2DFF
第八扇區(qū):2E00H--2FFF
*****************/
//注釋:本程序是對51和52本身自帶的eeprom的操作!
//完全按照芯片數據手冊編寫
//定義ISP的操作命令
#define RdCommand 0x01? ? //對用戶的應用程序flash區(qū)及數據flash區(qū)字節(jié)讀?
#define PrgCommand 0x02? ?//對用戶的應用程序flash區(qū)及數據flash區(qū)字節(jié)編程
#define EraseCommand 0x03 //對用戶的應用程序flash區(qū)及數據flash區(qū)扇區(qū)擦除
#define Error 1? //應答1
#define Ok 0? ? ?//應答0
#define WaitTime 0x01 //定義CPU的等待時間
?//寄存器申明(寄存器地址)
sfr ISP_DATA=0xe2;? ?//Flash數據寄存器?
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 控制寄存器 從Flash讀出的數據放在此處,向Flash寫入的數據也需放在此處。
// ==========打開 ISP,IAP 功能 ============ //
void ISP_IAP_enable(void)
{
?EA = 0;??
// 關中斷, 此時各中斷請求,會被掛起,一開中斷,立即響應
?ISP_CONTR = ISP_CONTR & 0x18;??
?// 0001,1000?
?// 左到右看,第一個0:ISPEN: ISP/IAP 功能允許位 —— 0:禁止ISP/IAP編程改變Flash,1:允許編程改變 Flash
?// 左到右看,第二個0:SWBS? —— 軟件選擇從用戶主程序區(qū)啟動 ( 0 ),還是從 ISP 程序區(qū)啟動( 1 )。
?// 左到右看,第三個0:SWRST —— 0: 不操作; 1: 產生軟件系統復位,硬件自動清零。
?// 左到右看,第四個1: 無意義,此處填1、0都可
?// 左到右看,第五個1: 無意義,此處填1、0都可
?// 左到右看,第6-8的0: WT2-WT1-WT0 ——為CPU等待時間(周期),000為40MHZ。?
ISP_CONTR = ISP_CONTR | WaitTime; /* 寫入硬件延時 */
ISP_CONTR = ISP_CONTR | 0x80;? ? ?//ISPEN=1 允許ISP/IAP 操作? 此兩句可以合成一句,并且只送一次就夠了
}
// ==========關閉 ISP,IAP 功能 ============= //
void ISP_IAP_disable(void)
{
ISP_CONTR = ISP_CONTR & 0x7f;?
// ISPEN = 0? 0:禁止ISP/IAP編程改變Flash
ISP_TRIG = 0x00;?
//防止ISP/IAP 命令誤觸發(fā)
EA? ?=? ?1;? ? ??
//開中斷??
}
// ==========?公用的觸發(fā)代碼 ============== //
void ISPgoon(void)
{
ISP_IAP_enable(); //打開 ISP,IAP 功能??
ISP_TRIG = 0x46;??
//觸發(fā)ISP_IAP命令字節(jié)1 先送46h,再送B9h 到ISP/IAP 觸發(fā)寄存器,每次都需如此
ISP_TRIG = 0xb9;??
//觸發(fā)ISP_IAP命令字節(jié)2 送完 B9h 后,ISP/IAP 命令立即被觸發(fā)起動
_nop_();?
//數據讀出到 ISP_DATA 寄存器后,CPU 繼續(xù)執(zhí)行程序
}
// ==============?字節(jié)讀 ================= //
unsigned char byte_read(unsigned int byte_addr)
{
EA = 0;
//---地址需要改變時才需重新送地址
ISP_ADDRH = (unsigned char)(byte_addr >> 8);? ??
//地址賦值?
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff); ?
//---送字節(jié)讀命令,命令不需改變時,不需重新送命令
ISP_CMD? ?= ISP_CMD & 0xf8;? //清除低3位??
ISP_CMD? ?= ISP_CMD | RdCommand; //寫入讀命令?
ISPgoon();??//觸發(fā)執(zhí)行??
ISP_IAP_disable();??//關閉ISP,IAP功能?
EA? = 1;
return (ISP_DATA);? ? //返回讀到的數據?
// CPU等待 IAP 動作完成后,才會繼續(xù)執(zhí)行程序,要先關中斷(EA ),
//再送 46h,B9h 到 ISP/IAP 觸發(fā)寄存器,起動ISP/IAP 命令,關中斷在觸發(fā)之前即可
}
// =============?扇區(qū)擦除================ //
void SectorErase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
//---地址需要改變時才需重新送地址
iSectorAddr = (sector_addr & 0xfe00);? ? ? ?
//取扇區(qū)地址?
ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
ISP_ADDRL = 0x00;
//送扇區(qū)擦除命令,命令不需改變時,不需重新送命令
ISP_CMD = ISP_CMD & 0xf8;??//清空低3位??
ISP_CMD = ISP_CMD | EraseCommand; //擦除命令
ISPgoon();? //觸發(fā)執(zhí)行??
ISP_IAP_disable();? //關閉ISP,IAP功能?
}
// ============?字節(jié)寫 ============//
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
EA? = 0;
?//---地址需要改變時才需重新送地址
ISP_ADDRH = (unsigned char)(byte_addr >> 8);? ?
// 取地址?
ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
//送字節(jié)編程命令
ISP_CMD? = ISP_CMD & 0xf8;??//清低3位?
ISP_CMD? = ISP_CMD | PrgCommand; //寫命令2?
ISP_DATA = original_data;??//寫入數據準備?
ISPgoon();? // 觸發(fā)執(zhí)行??
ISP_IAP_disable();? ?// 關閉IAP功能?
EA =1; ?
//開中斷,CPU 處理完 ISP/IAP 動作即可開中斷
// CPU等待 IAP 動作完成后,才會繼續(xù)執(zhí)行程序,要先關中斷(EA ),
//再送 46h,B9h 到 ISP/IAP 觸發(fā)寄存器,起動ISP/IAP 命令,關中斷在觸發(fā)之前即可
}
#endif