新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STC單片機內部EEPROM的應用

        STC單片機內部EEPROM的應用

        作者: 時間:2016-11-13 來源:網絡 收藏
        單片機運行時的數據都存在于RAM(隨機存儲器)中,在掉電后RAM中的數據是無法保留的,那么怎樣使數據在掉電后不丟失呢?這就需要使用EEPROM或FLASHROM等存儲器來實現。在傳統的單片機系統中,一般是在片外擴展存儲器,單片機與存儲器之間通過IIC或SPI等接口來進行數據通信。這樣不光會增加開發成本,同時在程序開發上也要花更多的心思。在STC單片機中內置了EEPROM(其實是采用IAP技術讀寫內部FLASH來實現EEPROM),這樣就節省了片外資源,使用起來也更加方便。下面就詳細介紹STC單片機內置EEPROM及其使用方法。

        STC各型號單片機內置的EEPROM的容量各有不同,見下表:

        本文引用地址:http://www.104case.com/article/201611/316202.htm

        單片機芯片型號

        起始地址

        內置EEPROM容量(每扇區512字節)

        STC89C51RC,STC89LE51RC

        0x2000

        共八個扇區

        STC89C52RC,STC89LE52RC

        0x2000

        共八個扇區

        STC89C54RD+,STC89LE54RD+

        0x8000

        共五十八個扇區

        STC89C55RD+,STC89LE55RD+

        0x8000

        共五十八個扇區

        STC89C58RD+,STC89LE58RD+

        0x8000

        共五十八個扇區

        內部EEPROM可以擦寫100000次以上)

        上面提到了IAP,它的意思是“在應用編程”,即在程序運行時程序存儲器可由程序自身進行擦寫。正是是因為有了IAP,從而可以使單片機可以將數據寫入到程序存儲器中,使得數據如同燒入的程序一樣,掉電不丟失。當然寫入數據的區域與程序存儲區要分開來,以使程序不會遭到破壞。

        要使用IAP功能,與以下幾個特殊功能寄存器相關:

        寄存器標識

        地址

        名稱

        7

        6

        5

        4

        3

        2

        1

        0

        初始值

        ISP_DATA

        0xE2

        ISP/IAP閃存數據寄存器

        11111111

        ISP_ADDRH

        0xE3

        ISP/IAP閃存地址高位

        00000000

        ISP_ADDRL

        0xE4

        ISP/IAP閃存地址低位

        00000000

        ISP_CMD

        0xE5

        ISP/IAP閃存命令寄存器

        -

        -

        -

        -

        -

        MS2

        MS1

        MS0

        xxxxx000

        ISP_TRIG

        0xE6

        ISP/IAP閃存命令觸發

        xxxxxxxx

        ISP_CONTR

        0xE7

        ISP/IAP控制寄存器

        ISPEN

        SWBS

        SWRST

        -

        -

        WT2

        WT1

        WT0

        00xx000

        ISP_DATA: ISP/IAP操作時的數據寄存器。

        ISP/IAP從Flash讀出的數據放在此處,向Flash寫的數據也需放在此處

        ISP_ADDRH:ISP/IAP操作時的地址寄存器高八位。

        ISP_ADDRL:ISP/IAP操作時的地址寄存器低八位。

        ISP_CMD: ISP/IAP操作時的命令模式寄存器,須命令觸發寄存器觸發方可生效。

        B7

        B6

        B5

        B4

        B3

        B2

        B1

        B0

        命令/操作模式選擇

        保留

        命令選擇

        0

        0

        0

        待機模式,無ISP/IAP操作

        0

        0

        1

        對用戶的應用程序Flash區及數據Flash區字節讀

        0

        1

        0

        對用戶的應用程序Flash區及數據Flash區字節編程

        0

        1

        1

        對用戶的應用程序Flash區及數據Flash區扇區擦除

        ISP_TRIG:ISP/IAP操作時的命令觸發寄存器。

        當ISPEN(ISP_CONTR.7)=1時,對ISP_TRIG先寫入0x46,再寫入0xb9,ISP/IAP命令才會生效。

        ISP_CONTR:ISP/IAP控制寄存器。

        D7

        D6

        D5

        D4

        D3

        D2

        D1

        D0

        ISPEN

        SWBS

        SWRST

        WT2

        WT1

        WT0

        ISPEN:ISP/IAP功能允許位。0:禁止ISP/IAP編程改變Flash,1:允許編程改變Flash

        SWBS:軟件選擇從用戶主程序區啟動(0),還是從ISP程序區啟動(1)。

        SWRST:0:不操作,1:產生軟件系統復位,硬件自動清零。

        ISP_CONTR中的SWBS與SWRST這兩個功能位,可以實現單片機的軟件啟動,并啟動到ISP區或用戶程序區,這在“STC單片機自動下載”一節,亦有所應用。

        如:

        ISP_CONTR=0x60; 則可以實現從用戶應用程序區軟件復位到ISP程序區開始運行程序。

        ISP_CONTR=0x20; 則可以實現從ISP程序區軟件復位到用戶應用程序區開始運行程序。

        用IAP向Flash中讀寫數據,是需要一定的讀寫時間的,讀寫數據命令發出后,要等待一段時間才可以讀寫成功。這個等待時間就是由WT2、WT1、WT0與晶體振蕩器頻率決定的。

        設置等待時間

        CPU等待時間(機器周期)

        WT2

        WT1

        WT0

        讀取

        編程

        扇區擦除

        建議的系統時鐘

        0

        1

        1

        6

        30

        5471

        5MHz

        0

        1

        0

        11

        60

        10942

        10MHz

        0

        0

        1

        22

        120

        21885

        20MHz

        0

        0

        0

        43

        240

        43769

        40MHz

        (以上的建議時鐘是(WT2、WT1、WT0)取不同的值時的標稱時鐘,用戶系統中的時鐘不要過高,否則可能使操作不穩定。)

        以下是具體的實現代碼:

        EEPROM操作函數:

        #define RdCommand 0x01

        #define PrgCommand 0x02

        #define EraseCommand 0x03

        #define Error 1

        #define Ok 0

        #define WaitTime 0x01

        #define PerSector 512

        unsignedchar xdata Ttotal[512];

        /*

        ---------------------------------------------------------------------

        打開 ISP,IAP功能

        ---------------------------------------------------------------------

        */

        voidISP_IAP_enable(void)

        {

        EA=0;/*關中斷*/

        ISP_CONTR|=0x18;/*0001,1000*/

        ISP_CONTR|=WaitTime;/*寫入硬件延時*/

        ISP_CONTR|=0x80;/*ISPEN=1*/

        }

        /*

        ---------------------------------------------------------------------

        關閉 ISP,IAP功能

        ---------------------------------------------------------------------

        */

        voidISP_IAP_disable(void)

        {

        ISP_CONTR&=0x7f;/* ISPEN = 0 */

        ISP_TRIG=0x00;

        EA=1;/*開中斷 */

        }

        /*

        ----------------------------------------------------------------------

        公用的觸發代碼

        ----------------------------------------------------------------------

        */

        voidISPgoon(void)

        {

        ISP_IAP_enable();/*打開 ISP,IAP功能 */

        ISP_TRIG=0x46;/*觸發ISP_IAP命令字節1 */

        ISP_TRIG=0xb9;/*觸發ISP_IAP命令字節2 */

        _nop_();

        }

        /*

        -----------------------------------------------------------------------

        字節讀

        -----------------------------------------------------------------------

        */

        unsignedchar byte_read(unsigned int byte_addr)

        {

        ISP_ADDRH=(unsigned char)(byte_addr>>8); /*地址賦值*/

        ISP_ADDRL=(unsigned char)(byte_addr&0x00ff);

        ISP_CMD&=0xf8; /*清除低3位 */

        ISP_CMD|=RdCommand;/*寫入讀命令*/

        ISPgoon();/*觸發執行*/

        ISP_IAP_disable();/*關閉ISP,IAP功能*/

        return ISP_DATA;/*返回讀到的數據*/

        }

        /*

        ------------------------------------------------------------------------

        扇區擦除

        ------------------------------------------------------------------------

        */

        voidsectorerase(unsigned int sector_addr)

        {

        unsigned int iSectorAddr;

        iSectorAddr=(sector_addr&0xfe00);/*取扇區地址*/

        ISP_ADDRH=(unsigned char)(iSectorAddr>>8);

        ISP_ADDRL=0x00;

        ISP_CMD&=0xf8;/*清空低3位*/

        ISP_CMD|=EraseCommand;/*擦除命令3*/

        ISPgoon();/*觸發執行 */

        ISP_IAP_disable();/*關閉ISP,IAP功能*/

        }

        /*

        -------------------------------------------------------------------------------------

        字節寫

        -------------------------------------------------------------------------------------

        */

        voidbyte_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&=0xf8;/*清低3位*/

        ISP_CMD|=PrgCommand;/*寫命令2*/

        ISP_DATA=original_data;/*寫入數據準備*/

        ISPgoon();/*觸發執行*/

        ISP_IAP_disable();/*關閉IAP功能*/

        }

        /*

        -----------------------------------------------------------------

        字節寫并校驗

        -----------------------------------------------------------------

        */

        unsignedchar byte_write_verify(unsigned int byte_addr, unsigned char original_data)

        {

        ISP_ADDRH=(unsigned char)(byte_addr>>8); /*取地址*/

        ISP_ADDRL=(unsigned char)(byte_addr&0xff);

        ISP_CMD&=0xf8;/*清低3位*/

        ISP_CMD|=PrgCommand;/*寫命令2*/

        ISP_DATA=original_data;

        ISPgoon();/*觸發執行*/

        /*開始讀,沒有在此重復給地址,地址不會被自動改變*/

        ISP_DATA=0x00;/*清數據傳遞寄存器*/

        ISP_CMD&=0xf8;/*清低3位*/

        ISP_CMD|=RdCommand;/*讀命令1*/

        ISP_TRIG=0x46;/*觸發ISP_IAP命令字節1 */

        ISP_TRIG=0xb9;/*觸發ISP_IAP命令字節2 */

        _nop_();/*延時*/

        ISP_IAP_disable();/*關閉IAP功能*/

        if(ISP_DATA==original_data)/*讀寫數據校驗*/

        return Ok;/*返回校驗結果*/

        else

        return Error;

        }

        /*

        --------------------------------------------------------------------------

        數組寫入

        --------------------------------------------------------------------------

        */

        unsignedchar arraywrite(unsigned int begin_addr, unsigned int len, unsigned char *array)

        {

        unsigned int i;

        unsigned int in_addr;

        /*判是否是有效范圍,此函數不允許跨扇區操作 */

        if(len > PerSector)

        return Error;

        in_addr = begin_addr & 0x01ff;/*扇區內偏移量 */

        if((in_addr+len)>PerSector)

        return Error;

        in_addr = begin_addr;

        /*逐個寫入并校對 */

        ISP_IAP_enable();/*打開IAP功能 */

        for(i=0;i

        {

        /*寫一個字節 */

        ISP_ADDRH=(unsigned char)(in_addr >> 8);

        ISP_ADDRL=(unsigned char)(in_addr & 0x00ff);

        ISP_DATA=array[i]; /*取數據 */

        ISP_CMD&=0xf8;/*清低3位 */

        ISP_CMD|=PrgCommand;/*寫命令2 */

        ISP_TRIG=0x46;/*觸發ISP_IAP命令字節1 */

        ISP_TRIG=0xb9;/*觸發ISP_IAP命令字節2 */

        _nop_();

        /*讀回來 */

        ISP_DATA=0x00;

        ISP_CMD&=0xf8;/*清低3位*/

        ISP_CMD|=RdCommand;/*讀命令1*/

        ISP_TRIG=0x46;/*觸發ISP_IAP命令字節1 */

        ISP_TRIG=0xb9;/*觸發ISP_IAP命令字節2 */

        _nop_();

        /*比較對錯 */

        if(ISP_DATA!=array[i])

        {

        ISP_IAP_disable();

        return Error;

        }

        in_addr++;/*指向下一個字節*/

        }

        ISP_IAP_disable();

        return Ok;

        }

        /*

        -----------------------------------------------------------------------------

        扇區讀出

        -----------------------------------------------------------------------------

        */

        /*程序對地址沒有作有效性判斷,請調用前事先保證他在規定范圍內 */

        voidarrayread(unsigned int begin_addr, unsigned char len)

        {

        unsigned int iSectorAddr;

        unsigned int i;

        iSectorAddr = begin_addr; // & 0xfe00; /*取扇區地址*/

        ISP_IAP_enable();

        for(i=0;i

        {

        ISP_ADDRH=(unsigned char)(iSectorAddr>>8);

        ISP_ADDRL=(unsigned char)(iSectorAddr & 0x00ff);

        ISP_CMD&=0xf8;/*清低3位*/

        ISP_CMD|=RdCommand;/*讀命令1*/

        ISP_DATA=0;

        ISP_TRIG=0x46;/*觸發ISP_IAP命令字節1 */

        ISP_TRIG=0xb9;/*觸發ISP_IAP命令字節2 */

        _nop_();

        Ttotal[i]=ISP_DATA;

        iSectorAddr++;

        }

        ISP_IAP_disable();/*關閉IAP功能*/

        }

        主函數對EEPROM操作函數進行調用:

        #include c51rd.h>

        #include

        #include

        #include

        inti;

        voiddelay(unsigned int time)

        {

        while(time--);

        }

        voidmain()

        {

        _ADOS(22.1184);

        //ADOS自動下載

        //for(i=0;i<100;i++)

        //{

        //Ttotal[i]=i;

        //}

        //arraywrite(0x8000,100,Ttotal);

        /*

        第一次運行時向EEPROM中寫入數據

        然后再將寫入函數注釋掉,將先前寫

        入的數據讀出,輸出在P2口上。

        */

        arrayread(0x8000,100);

        for(i=0;i<100;i++)

        {

        P2=~Ttotal[i];

        delay(10000);

        }

        while(1);

        }



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 景谷| 历史| 福鼎市| 岳普湖县| 长宁县| 张家川| 塔河县| 沅江市| 定边县| 昌宁县| 蒲城县| 象州县| 攀枝花市| 从江县| 墨玉县| 壤塘县| 治多县| 康马县| 罗田县| 汪清县| 镇沅| 正阳县| 南溪县| 上饶市| 沅陵县| 泰和县| 临城县| 平安县| 鲁山县| 府谷县| 镇江市| 安岳县| 沈阳市| 大邑县| 五峰| 徐汇区| 虞城县| 晋宁县| 九寨沟县| 洪洞县| 九江市|