新聞中心

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

        STC89C5x系列單片機內部EEPROM

        作者: 時間:2016-11-11 來源:網絡 收藏
        //(c)Copyright2007-2017,GuozhouChen.AllRightsReserved.

        /********************************************************************************
        *個人申明:*
        *本人在運用STC89C5x系列單片機內部EEPROM時,了解其對非0xff值的存儲空間*
        *不能通過字節編程直接寫入。這一約定可能給一些人帶來應用的麻煩,所以本*
        *人決定編寫一能夠讓程序員不考慮這一約定的API。經過幾個小時的編寫和調*
        *試,基本能達到本人原本設想的目標。由于時間倉促及個人水平有限,不免會*
        *有些算法低效,還望高手指教。Email:chenguozhou1982@yahoo.com.cn。*
        **
        *本程序通過改幾個宏定義可以運用到STC的很多型號MCU上,本人只測試了*
        *STC89C5x系列*

        *本程序可以任意修改和傳播,修改者請注明修改人、修改時間,傳播過程請注*
        *明原著。不得用于任何商業目的。*
        **
        ********************************************************************************
        *FileName:EEPROM.C,V0.2.0*
        *Author:GuozhouChen*
        *Date:2007.09.15*
        **
        ********************************************************************************
        *使用數據類型說明:*
        *UINT:16位無符號整形*
        *BYTE:8位無符號字符型*
        *BOOL:1位布爾類型*
        **
        ********************************************************************************
        *直接調用的API說明:*
        **
        *讀函數原形:UINTEEPROM_ReadBytes(UINTaddr,BYTE*buf,UINTsize)*
        *函數返回為UINT類型的實際讀出數據字節數。*
        *參數說明:addr為需要讀取EEPROM區域的第一字節地址,取值范圍為內部*
        *EEPROM除最后一扇區外的地址,因最后一扇區被犧牲做為緩存。*
        *buf為目的數據區指針,即指向保存讀出數據區域的首地址。*
        *size為要求讀出數據的字節數*
        **
        *寫函數原形:UINTEEPROM_WritBytes(UINTaddr,BYTE*buf,UINTsize)*
        *函數返回為UINT類型的實際寫入數據字節數。*
        *參數說明:addr為需要寫入EEPROM區域的第一字節地址,取值范圍為內部*
        *EEPROM除最后一扇區外的地址,因最后一扇區被犧牲做為緩存。*
        *buf為源數據區指針,即指向需要寫入數據區域的首地址。*
        *size為要求寫入數據的字節數*
        **
        ********************************************************************************
        *使用說明:*
        *1、根據MCU和編譯器的實際情況修改幾個宏定義和數據類型定義。宏定義和數據類*
        *型定義部分可以單獨寫成頭文件。*
        *2、在需要使用EEPROM_ReadBytes()和EEPROM_WritBytes()函數的文件中做個*
        *原形申明。*
        *3、在需要的地方直接添入實參調用即可。*
        **
        ********************************************************************************/

        /********************************************************************************
        **
        *頭文件*
        **
        ********************************************************************************/
        #include"STC89C5x.h"

        /********************************************************************************
        **
        *數據類型定義*
        **
        ********************************************************************************/
        typedefunsignedintUINT;
        typedefunsignedcharBYTE;
        typedefbitBOOL;

        /********************************************************************************
        **
        *宏定義*
        **
        ********************************************************************************/
        #defineBYTES_EACH_SECTOR512//MCUEEPROM每扇區的字節數

        //CPU等待時間,晶振0-5M設置為3,5-10M為2,10-20M為1,大于20M為0
        #defineWAIT_TIME0

        #defineUSEING_EACH_SECTOR512//計劃每扇區要用的字節數,用量越小寫速度越快

        #defineEEPROM_ADDR_START0x2000//EEPROM起始地址
        #defineEEPROM_ADDR_END0x2fff//EEPROM結束地址


        /********************************************************************************
        **
        *從指定首地址為addr的EEPROM區域讀出size字節數據到buf指向的區域內,并返回實際讀*
        *出數據的字節數*
        **
        ********************************************************************************/

        UINTEEPROM_ReadBytes(UINTaddr,BYTE*buf,constUINTsize)
        {
        BOOLold_EA;

        BYTE*p_buf;
        UINTi,current_size;

        p_buf=buf;
        current_size=0;

        ISP_CMD=0x01;
        ISP_CONTR=0x80|WAIT_TIME;

        for(i=0;i{
        //地址越界檢測
        if((addrEEPROM_ADDR_END))
        {
        break;
        }

        ISP_ADDRH=addr>>8;
        ISP_ADDRL=addr&0x00ff;

        old_EA=EA;
        EA=0;

        ISP_TRIG=0x46;
        ISP_TRIG=0xB9;

        EA=old_EA;

        *p_buf=ISP_DATA;

        addr++;
        p_buf++;
        current_size++;

        }
        ISP_CMD=0x00;
        ISP_CONTR=0x00;

        returncurrent_size;
        }

        /********************************************************************************
        **
        *把buf指向單元內的數據寫入地址為addr的EEPROM單元內,成功返回1,或則返回0*
        **
        ********************************************************************************/
        BOOLEEPROM_WritByte(UINTaddr,BYTE*buf)
        {
        BOOLold_EA;

        if((addrEEPROM_ADDR_END))
        {
        return0;
        }

        ISP_CMD=0x02;
        ISP_CONTR=0x80|WAIT_TIME;

        ISP_DATA=(*buf);

        ISP_ADDRH=addr>>8;
        ISP_ADDRL=addr&0x00ff;

        old_EA=EA;
        EA=0;

        ISP_TRIG=0x46;
        ISP_TRIG=0xB9;

        EA=old_EA;

        ISP_CMD=0x00;
        ISP_CONTR=0x00;

        return1;
        }

        /********************************************************************************
        **
        *擦除AddrInSector地址所在的整個扇區*
        **
        ********************************************************************************/
        voidErasureAllSector(UINTAddrInSector)
        {
        BOOLold_EA;

        ISP_CMD=0x03;
        ISP_CONTR=0x80|WAIT_TIME;

        ISP_ADDRH=AddrInSector>>8;
        ISP_ADDRL=AddrInSector&0x00ff;

        old_EA=EA;
        EA=0;

        ISP_TRIG=0x46;
        ISP_TRIG=0xB9;

        EA=old_EA;

        ISP_CMD=0x00;
        ISP_CONTR=0x00;
        }

        /********************************************************************************
        **
        *從首地址為src扇區單元拷貝連續size字節數據到首地址為des的連續扇區單元內,并返*
        *回實際拷貝的字節數*
        **
        ********************************************************************************/
        UINTCopySector(UINTsrc,UINTdes,constUINTsize)
        {
        BYTEtemp;
        UINTcurrent_size,i;

        current_size=0;

        for(i=0;i{
        if(!EEPROM_ReadBytes(src,&temp,1))
        {
        break;
        }

        if(!EEPROM_WritByte(des,&temp))
        {
        break;
        }

        des++;
        src++;
        current_size++;
        }

        returncurrent_size;
        }

        /********************************************************************************
        **
        *把buf指向區域內的size字節數據寫入首地址為addr的EEPROM連續區域,并返回實際寫入*
        *數據的字節數*
        **
        ********************************************************************************/
        UINTEEPROM_WritBytes(UINTaddr,BYTE*buf,constUINTsize)
        {
        BYTE*p_buf,temp,move;

        UINTi,bufaddr,current_size,cur_sector_start_addr;

        p_buf=buf;

        move=0;
        current_size=0;

        for(i=0;i{
        if(!EEPROM_ReadBytes(addr,&temp,1))
        {
        break;
        }

        if(temp==0xff)
        {
        EEPROM_WritByte(addr,p_buf);
        }
        //發現第一個單元不是0xff,要從新寫入數據需要做擦除整個扇區
        else
        {
        //擦除用作緩沖的這個扇區
        ErasureAllSector(EEPROM_ADDR_END);

        cur_sector_start_addr=addr&0xfe00;

        //把第一個非0xff單元前的數據拷貝到緩沖扇區
        CopySector(cur_sector_start_addr
        ,(EEPROM_ADDR_END+1-BYTES_EACH_SECTOR)
        ,(addr-cur_sector_start_addr));

        //計算剩余需要存儲的數據需寫入緩沖扇區的首個單元地址
        bufaddr=(addr-cur_sector_start_addr)
        +(EEPROM_ADDR_END+1-BYTES_EACH_SECTOR);

        //把剩余要存儲的數據寫入緩沖扇區
        for(;i{
        EEPROM_WritByte(bufaddr,p_buf);

        addr++;
        bufaddr++;
        p_buf++;
        current_size++;
        }

        //把需要改變區域后的數據寫入緩沖扇區
        if(addr{
        CopySector(addr,bufaddr,USEING_EACH_SECTOR
        -(addr-cur_sector_start_addr));
        }

        //擦除當前扇區
        ErasureAllSector(cur_sector_start_addr);
        move=1;
        break;
        }

        addr++;
        p_buf++;
        current_size++;
        }

        if(move)
        {
        //把緩沖扇區數據拷貝到當前扇區
        CopySector((EEPROM_ADDR_END-BYTES_EACH_SECTOR+1)
        ,cur_sector_start_addr,USEING_EACH_SECTOR);
        }

        returncurrent_size;
        }
        /*****************************Nothingbelowthisline***************************/


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 泸西县| 庆元县| 垦利县| 青阳县| 桐乡市| 聂拉木县| 集贤县| 周口市| 台北县| 虎林市| 高青县| 乐昌市| 西安市| 措勤县| 德令哈市| 彭山县| 柳江县| 富源县| 陆河县| 宿松县| 弋阳县| 根河市| 外汇| 昭平县| 全椒县| 博乐市| 蓬溪县| 穆棱市| 昭苏县| 谷城县| 称多县| 定日县| 新巴尔虎右旗| 铜陵市| 永平县| 河津市| 天门市| 三都| 河东区| 仪征市| 长乐市|