色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STC單片機(jī)內(nèi)部EEPROM的應(yīng)用

          STC單片機(jī)內(nèi)部EEPROM的應(yīng)用

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

          STC各型號單片機(jī)內(nèi)置的EEPROM的容量各有不同,見下表:

          本文引用地址:http://cafeforensic.com/article/201611/316202.htm

          單片機(jī)芯片型號

          起始地址

          內(nèi)置EEPROM容量(每扇區(qū)512字節(jié))

          STC89C51RC,STC89LE51RC

          0x2000

          共八個扇區(qū)

          STC89C52RC,STC89LE52RC

          0x2000

          共八個扇區(qū)

          STC89C54RD+,STC89LE54RD+

          0x8000

          共五十八個扇區(qū)

          STC89C55RD+,STC89LE55RD+

          0x8000

          共五十八個扇區(qū)

          STC89C58RD+,STC89LE58RD+

          0x8000

          共五十八個扇區(qū)

          內(nèi)部EEPROM可以擦寫100000次以上)

          上面提到了IAP,它的意思是“在應(yīng)用編程”,即在程序運(yùn)行時程序存儲器可由程序自身進(jìn)行擦寫。正是是因?yàn)橛辛薎AP,從而可以使單片機(jī)可以將數(shù)據(jù)寫入到程序存儲器中,使得數(shù)據(jù)如同燒入的程序一樣,掉電不丟失。當(dāng)然寫入數(shù)據(jù)的區(qū)域與程序存儲區(qū)要分開來,以使程序不會遭到破壞。

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

          寄存器標(biāo)識

          地址

          名稱

          7

          6

          5

          4

          3

          2

          1

          0

          初始值

          ISP_DATA

          0xE2

          ISP/IAP閃存數(shù)據(jù)寄存器

          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閃存命令觸發(fā)

          xxxxxxxx

          ISP_CONTR

          0xE7

          ISP/IAP控制寄存器

          ISPEN

          SWBS

          SWRST

          -

          -

          WT2

          WT1

          WT0

          00xx000

          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ā)方可生效。

          B7

          B6

          B5

          B4

          B3

          B2

          B1

          B0

          命令/操作模式選擇

          保留

          命令選擇

          0

          0

          0

          待機(jī)模式,無ISP/IAP操作

          0

          0

          1

          對用戶的應(yīng)用程序Flash區(qū)及數(shù)據(jù)Flash區(qū)字節(jié)讀

          0

          1

          0

          對用戶的應(yīng)用程序Flash區(qū)及數(shù)據(jù)Flash區(qū)字節(jié)編程

          0

          1

          1

          對用戶的應(yīng)用程序Flash區(qū)及數(shù)據(jù)Flash區(qū)扇區(qū)擦除

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

          當(dāng)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:軟件選擇從用戶主程序區(qū)啟動(0),還是從ISP程序區(qū)啟動(1)。

          SWRST:0:不操作,1:產(chǎn)生軟件系統(tǒng)復(fù)位,硬件自動清零。

          ISP_CONTR中的SWBS與SWRST這兩個功能位,可以實(shí)現(xiàn)單片機(jī)的軟件啟動,并啟動到ISP區(qū)或用戶程序區(qū),這在“STC單片機(jī)自動下載”一節(jié),亦有所應(yīng)用。

          如:

          ISP_CONTR=0x60; 則可以實(shí)現(xiàn)從用戶應(yīng)用程序區(qū)軟件復(fù)位到ISP程序區(qū)開始運(yùn)行程序。

          ISP_CONTR=0x20; 則可以實(shí)現(xiàn)從ISP程序區(qū)軟件復(fù)位到用戶應(yīng)用程序區(qū)開始運(yùn)行程序。

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

          設(shè)置等待時間

          CPU等待時間(機(jī)器周期)

          WT2

          WT1

          WT0

          讀取

          編程

          扇區(qū)擦除

          建議的系統(tǒng)時鐘

          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)取不同的值時的標(biāo)稱時鐘,用戶系統(tǒng)中的時鐘不要過高,否則可能使操作不穩(wěn)定。)

          以下是具體的實(shí)現(xiàn)代碼:

          EEPROM操作函數(shù):

          #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;/*關(guān)中斷*/

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

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

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

          }

          /*

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

          關(guān)閉 ISP,IAP功能

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

          */

          voidISP_IAP_disable(void)

          {

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

          ISP_TRIG=0x00;

          EA=1;/*開中斷 */

          }

          /*

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

          公用的觸發(fā)代碼

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

          */

          voidISPgoon(void)

          {

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

          ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節(jié)1 */

          ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節(jié)2 */

          _nop_();

          }

          /*

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

          字節(jié)讀

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

          */

          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();/*觸發(fā)執(zhí)行*/

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

          return ISP_DATA;/*返回讀到的數(shù)據(jù)*/

          }

          /*

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

          扇區(qū)擦除

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

          */

          voidsectorerase(unsigned int sector_addr)

          {

          unsigned int iSectorAddr;

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

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

          ISP_ADDRL=0x00;

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

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

          ISPgoon();/*觸發(fā)執(zhí)行 */

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

          }

          /*

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

          字節(jié)寫

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

          */

          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;/*寫入數(shù)據(jù)準(zhǔn)備*/

          ISPgoon();/*觸發(fā)執(zhí)行*/

          ISP_IAP_disable();/*關(guān)閉IAP功能*/

          }

          /*

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

          字節(jié)寫并校驗(yàn)

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

          */

          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();/*觸發(fā)執(zhí)行*/

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

          ISP_DATA=0x00;/*清數(shù)據(jù)傳遞寄存器*/

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

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

          ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節(jié)1 */

          ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節(jié)2 */

          _nop_();/*延時*/

          ISP_IAP_disable();/*關(guān)閉IAP功能*/

          if(ISP_DATA==original_data)/*讀寫數(shù)據(jù)校驗(yàn)*/

          return Ok;/*返回校驗(yàn)結(jié)果*/

          else

          return Error;

          }

          /*

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

          數(shù)組寫入

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

          */

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

          {

          unsigned int i;

          unsigned int in_addr;

          /*判是否是有效范圍,此函數(shù)不允許跨扇區(qū)操作 */

          if(len > PerSector)

          return Error;

          in_addr = begin_addr & 0x01ff;/*扇區(qū)內(nèi)偏移量 */

          if((in_addr+len)>PerSector)

          return Error;

          in_addr = begin_addr;

          /*逐個寫入并校對 */

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

          for(i=0;i

          {

          /*寫一個字節(jié) */

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

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

          ISP_DATA=array[i]; /*取數(shù)據(jù) */

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

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

          ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節(jié)1 */

          ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節(jié)2 */

          _nop_();

          /*讀回來 */

          ISP_DATA=0x00;

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

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

          ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節(jié)1 */

          ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節(jié)2 */

          _nop_();

          /*比較對錯 */

          if(ISP_DATA!=array[i])

          {

          ISP_IAP_disable();

          return Error;

          }

          in_addr++;/*指向下一個字節(jié)*/

          }

          ISP_IAP_disable();

          return Ok;

          }

          /*

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

          扇區(qū)讀出

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

          */

          /*程序?qū)Φ刂窙]有作有效性判斷,請調(diào)用前事先保證他在規(guī)定范圍內(nèi) */

          voidarrayread(unsigned int begin_addr, unsigned char len)

          {

          unsigned int iSectorAddr;

          unsigned int i;

          iSectorAddr = begin_addr; // & 0xfe00; /*取扇區(qū)地址*/

          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;/*觸發(fā)ISP_IAP命令字節(jié)1 */

          ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節(jié)2 */

          _nop_();

          Ttotal[i]=ISP_DATA;

          iSectorAddr++;

          }

          ISP_IAP_disable();/*關(guān)閉IAP功能*/

          }

          主函數(shù)對EEPROM操作函數(shù)進(jìn)行調(diào)用:

          #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);

          /*

          第一次運(yùn)行時向EEPROM中寫入數(shù)據(jù)

          然后再將寫入函數(shù)注釋掉,將先前寫

          入的數(shù)據(jù)讀出,輸出在P2口上。

          */

          arrayread(0x8000,100);

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

          {

          P2=~Ttotal[i];

          delay(10000);

          }

          while(1);

          }



          評論


          技術(shù)專區(qū)

          關(guān)閉