對STC15系列單片機EEPROM使用感受


#include "reg51.h"
#include "intrins.h"

typedef unsigned char BYTE;
typedef unsigned int WORD;

//-----------------------------------------------

sfr IAP_DATA    =   0xC2;           //IAP數據寄存器
sfr IAP_ADDRH   =   0xC3;           //IAP地址寄存器高字節
sfr IAP_ADDRL   =   0xC4;           //IAP地址寄存器低字節
sfr IAP_CMD     =   0xC5;           //IAP命令寄存器
sfr IAP_TRIG    =   0xC6;           //IAP命令觸發寄存器
sfr IAP_CONTR   =   0xC7;           //IAP控制寄存器

#define CMD_IDLE    0               //空閒模式
#define CMD_READ    1               //IAP字節讀命令
#define CMD_PROGRAM 2               //IAP字節編程命令
#define CMD_ERASE   3               //IAP扇區擦除命令

//#define ENABLE_IAP 0x80           //if SYSCLK<30MHz
//#define ENABLE_IAP 0x81           //if SYSCLK<24MHz
#define ENABLE_IAP  0x82            //if SYSCLK<20MHz
//#define ENABLE_IAP 0x83           //if SYSCLK<12MHz
//#define ENABLE_IAP 0x84           //if SYSCLK<6MHz
//#define ENABLE_IAP 0x85           //if SYSCLK<3MHz
//#define ENABLE_IAP 0x86           //if SYSCLK<2MHz
//#define ENABLE_IAP 0x87           //if SYSCLK<1MHz

//測試地址
#define IAP_ADDRESS 0x0400

void Delay(BYTE n);
void IapIdle();
BYTE IapReadByte(WORD addr);
void IapProgramByte(WORD addr, BYTE dat);
void IapEraseSector(WORD addr);

void main()
{
    WORD i;

    P1 = 0xfe;                      //1111,1110 系統OK
    Delay(10);                      //延時
    IapEraseSector(IAP_ADDRESS);    //扇區擦除
    for (i=0; i<512; i++)           //檢測是否擦除成功(全FF檢測)
    {
        if (IapReadByte(IAP_ADDRESS+i) != 0xff)
            goto Error;             //如果出錯,則退出
    }
    P1 = 0xfc;                      //1111,1100 擦除成功
    Delay(10);                      //延時
    for (i=0; i<512; i++)           //編程512字節
    {
        IapProgramByte(IAP_ADDRESS+i, (BYTE)i);
    }
    P1 = 0xf8;                      //1111,1000 編程完成
    Delay(10);                      //延時
    for (i=0; i<512; i++)           //校驗512字節
    {
        if (IapReadByte(IAP_ADDRESS+i) != (BYTE)i)
            goto Error;             //如果校驗錯誤,則退出
    }
    P1 = 0xf0;                      //1111,0000 測試完成
    while (1);
Error:
    P1 &= 0x7f;                     //0xxx,xxxx IAP操作失敗
    while (1);
}

/*----------------------------
軟件延時
----------------------------*/
void Delay(BYTE n)
{
    WORD x;

    while (n--)
    {
        x = 0;
        while (++x);
    }
}

/*----------------------------
關閉IAP
----------------------------*/
void IapIdle()
{
    IAP_CONTR = 0;                  //關閉IAP功能
    IAP_CMD = 0;                    //清除命令寄存器
    IAP_TRIG = 0;                   //清除觸發寄存器
    IAP_ADDRH = 0x80;               //將地址設置到非IAP區域
    IAP_ADDRL = 0;
}

/*----------------------------
從ISP/IAP/EEPROM區域讀取一字節
----------------------------*/
BYTE IapReadByte(WORD addr)
{
    BYTE dat;                       //數據緩衝區

    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //設置IAP命令
    IAP_ADDRL = addr;               //設置IAP低地址
    IAP_ADDRH = addr >> 8;          //設置IAP高地址
    IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;                 //讀ISP/IAP/EEPROM數據
    IapIdle();                      //關閉IAP功能

    return dat;                     //返回
}

/*----------------------------
寫一字節數據到ISP/IAP/EEPROM區域
----------------------------*/
void IapProgramByte(WORD addr, BYTE dat)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //設置IAP命令
    IAP_ADDRL = addr;               //設置IAP低地址
    IAP_ADDRH = addr >> 8;          //設置IAP高地址
    IAP_DATA = dat;                 //寫ISP/IAP/EEPROM數據
    IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}

/*----------------------------
扇區擦除
----------------------------*/
void IapEraseSector(WORD addr)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_ERASE;            //設置IAP命令
    IAP_ADDRL = addr;               //設置IAP低地址
    IAP_ADDRH = addr >> 8;          //設置IAP高地址
    IAP_TRIG = 0x5a;                //寫觸發命令(0x5a)
    IAP_TRIG = 0xa5;                //寫觸發命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}


這是官方的實例,在測試中總是讀不到數據。搞了好長時間也沒有找到問題問題,沒辦法,在官方手冊上查找了參數,發現//測試地址#define IAP_ADDRESS 0x0400錯了,應該是從//測試地址#define IAP_ADDRESS 0x0000開始,改成就可以了,可以寫入數據,關機也可以讀取到數據。

但我操作是隻寫入一個字節,在原程序上改了下,發現還是不能用,從串口反饋過來的數據發現數據不能寫入,每次寫指令都給定了,但數據就是寫不進去,參考別的資料,感覺寫入前都發必須先讀取出來數據,保存。在擦除一次EEPROM,在把改好的數據寫入,把程序寫好,測試從串口反饋出來數據都正常了。

這功能很不錯,不用外加EEPROM芯片,可以實現功能帶記憶,可以存取設定的狀態,在下次在開機,執行上次關機的狀態。   這次也學會怎樣讀寫EEPROM,平時對EEPROM芯片打交道也很多的,一般都是用編程器來讀寫的。總感覺很神密的。下回有空自己寫個來讀取的轉機。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章