查看: 2388|回复: 0

STC单片机EEPROM读写程序

[复制链接]
  • TA的每日心情
    擦汗
    2024-5-31 10:44
  • 签到天数: 1492 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2013-12-27 15:28:03 | 显示全部楼层 |阅读模式
    分享到:
    /* STC89C54RD+flash空间从0x4000~0xf3ff 90个扇区,每扇区512字节       */
    //     #define BaseAddr          0x1000           /*    51rc */
    //     #define EndSectoraddr   0x3d00           /*    51rc */
    //     #define EndAddr    0x3fff            /*    51rc 12K eeprom   */
           #define BaseAddr          0x4000
           #define EndSectoraddr   0xf200
           #define EndAddr                0xf3ff
           #define UseAddr                0x1000
    /* ------------- 定义扇区大小 ------------- */
    #define PerSector          512
    /* 用户程序需要记忆的数组, 用户实际使用了n-1个数据,数组长度规整到
           2 4 8 16 32 64 */
    uchar Ttotal[16]     =
    {
           0x55,                           /* 作为判别引导头使用,用户程序请不要修改它 */
           /* 用户保存记忆的数据 */
           0x01,                           /* 用途说明....*/
           0x02,
           0x03,
           0x04,
           0x05,
           0x06,
           0x07,
           0x08,
           0x09,
           0x0a,
           0x0b,
           0x0c,
           0x0d,
           0x0e,
           0x0f,
    };
    uint        timerForDelay,              /* 专供延时用的变量 */
                  i,                                 /* 循环变量                 */
                  EepromPtr;                   /* eeprom读写指针      */
    /* --------------- 命令定义 --------------- */
    #define RdCommand            0x01       /* 字节读     */
    #define PrgCommand           0x02       /* 字节写     */
    #define EraseCommand 0x03       /* 扇区擦除 */
    /* 定义常量 */
    #define Error   1
    #define Ok      0
    /* 定义Flash对应于20MHz晶振系统的操作等待时间 */
    /* 时钟倍频时WaitTime 0x00*/
    #define WaitTime   0x01
    /* ================ 打开 ISP,IAP 功能 ================= */
    void ISP_IAP_enable(void){
           EA  =     0;                                              /* 关中断            */
           ISP_CONTR =       ISP_CONTR & 0x18;       /* 0001,1000 */
           ISP_CONTR =       ISP_CONTR | WaitTime;      /* 写入硬件延时   */
           ISP_CONTR =       ISP_CONTR | 0x80;       /* ISPEN=1           */
    }
    /* =============== 关闭 ISP,IAP 功能 ================== */
    void ISP_IAP_disable(void){
           ISP_CONTR   =     ISP_CONTR & 0x7f;    /* ISPEN = 0 */
           ISP_TRIG      =     0x00;
           EA                =   1;                  /* 开中断 */
    }
    /* ================ 公用的触发代码 ==================== */
    void ISPgoon(void){
           ISP_IAP_enable();               /* 打开 ISP,IAP 功能  */
           ISP_TRIG      =     0x46;             /* 触发ISP_IAP命令字节1       */
           ISP_TRIG      =     0xb9;             /* 触发ISP_IAP命令字节2       */
           _nop_();
    }
    /* ==================== 字节读 ======================== */
    uchar byte_read(uint byte_addr){
           ISP_ADDRH = (uchar)(byte_addr >> 8);    /* 地址赋值   */
           ISP_ADDRL = (uchar)(byte_addr & 0x00ff);
           ISP_CMD   = ISP_CMD    & 0xf8;                 /* 清除低3      */
           ISP_CMD   = ISP_CMD    | RdCommand;       /* 写入读命令      */
           ISPgoon();                                               /* 触发执行          */
           ISP_IAP_disable();                            /* 关闭ISP,IAP功能    */
           return (ISP_DATA);                           /* 返回读到的数据      */
    }
    /* ================== 扇区擦除 ======================== */
    void SectorErase(uint sector_addr){
           uint iSectorAddr;
           iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
           ISP_ADDRH = (uchar)(iSectorAddr >> 8);
           ISP_ADDRL = 0x00;
           ISP_CMD      = ISP_CMD & 0xf8;                   /* 清空低3      */
           ISP_CMD      = ISP_CMD | EraseCommand;     /* 擦除命令3      */
           ISPgoon();                                               /* 触发执行          */
           ISP_IAP_disable();                            /* 关闭ISP,IAP功能    */
    }
    /* ==================== 字节写 ======================== */
    void byte_write(uint byte_addr, uchar original_data){
           ISP_ADDRH =      (uchar)(byte_addr >> 8);      /* 取地址     */
           ISP_ADDRL =       (uchar)(byte_addr & 0x00ff);
           ISP_CMD      = ISP_CMD & 0xf8;                        /* 清低3   */
           ISP_CMD  = ISP_CMD | PrgCommand;           /* 写命令2    */
           ISP_DATA = original_data;                 /* 写入数据准备   */
           ISPgoon();                                               /* 触发执行          */
           ISP_IAP_disable();                                   /* 关闭IAP功能  */
    }
    /* =================== 字节写并校验 =================== */
    uchar byte_write_verify(uint byte_addr, uchar original_data){
           ISP_ADDRH = (uchar)(byte_addr >> 8);    /* 取地址     */
           ISP_ADDRL = (uchar)(byte_addr & 0xff);
           ISP_CMD  = ISP_CMD & 0xf8;                      /* 清低3   */
           ISP_CMD  = ISP_CMD | PrgCommand;           /* 写命令2    */
           ISP_DATA = original_data;
           ISPgoon();                                               /* 触发执行          */
           /* 开始读,没有在此重复给地址,地址不会被自动改变     */
           ISP_DATA = 0x00;                      /* 清数据传递寄存器   */
           ISP_CMD = ISP_CMD & 0xf8;                        /* 清低3   */
           ISP_CMD = 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;
           }
    }
    /* ===================== 数组写入 ===================== */
    uchar ArrayWrite(uint begin_addr, uint len, uchar *array){
           uint  i;
           uint  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< len; i++){
                  /* 写一个字节 */
                  ISP_ADDRH = (uchar)(in_addr >> 8);
                  ISP_ADDRL = (uchar)(in_addr & 0x00ff);
                  ISP_DATA  = array;                      /* 取数据      */
                  ISP_CMD   = ISP_CMD & 0xf8;                    /* 清低3 */
                  ISP_CMD   = ISP_CMD | PrgCommand;  /* 写命令2   */
                  ISP_TRIG  = 0x46;             /* 触发ISP_IAP命令字节1 */
                  ISP_TRIG  = 0xb9;             /* 触发ISP_IAP命令字节2 */
                  _nop_();
                  /* 读回来 */
                  ISP_DATA     =     0x00;
                  ISP_CMD  = ISP_CMD & 0xf8;               /* 清低3 */
                  ISP_CMD  = ISP_CMD | RdCommand;            /* 读命令1   */
                  ISP_TRIG = 0x46;        /* 触发ISP_IAP命令字节1 */
                  ISP_TRIG = 0xb9;        /* 触发ISP_IAP命令字节2 */
                  _nop_();
                  /*  比较对错 */
                  if(ISP_DATA != array){
                         ISP_IAP_disable();
                         return Error;
                  }
                  in_addr++;                                 /* 指向下一个字节      */
           }
           ISP_IAP_disable();
           return      Ok;
    }
    /* ========================= 扇区读出 ========================= */
    /* 程序对地址没有作有效性判断,请调用方事先保证他在规定范围内      */
    void ArrayRead(uint begin_addr, uchar len){
    //     uchar xdata     data_buffer[];               /* 整个扇区读取缓存区      */
           uint iSectorAddr;
           uint i;
           iSectorAddr = begin_addr;    // & 0xfe00;          /* 取扇区地址     */
           ISP_IAP_enable();
           for(i = 0; i < len; i++){
                  ISP_ADDRH =      (uchar)(iSectorAddr >> 8);
                  ISP_ADDRL =       (uchar)(iSectorAddr & 0x00ff);
                  ISP_CMD   =      ISP_CMD      & 0xf8;                        /* 清低3 */
                  ISP_CMD   =      ISP_CMD      | RdCommand;              /* 读命令1   */
                  ISP_DATA = 0;
                  ISP_TRIG = 0x46;               /* 触发ISP_IAP命令字节1 */
                  ISP_TRIG = 0xb9;               /* 触发ISP_IAP命令字节2 */
                  _nop_();
                  Ttotal  =     ISP_DATA;
                  iSectorAddr++;
           }
           ISP_IAP_disable();                                          /* 关闭IAP功能  */
    }
    /* ==============================================================
    eeprom中读取数据
    ============================================================== */
    void DataRestore()
    {
           EepromPtr = BaseAddr;                      /* 指向eeprom的起始点     */
           while(EepromPtr < EndAddr)                    /* eeprom的可用区域内 */
           {
                  if(byte_read(EepromPtr) == 0x55)/* 找到了上一次有效纪录  */
                  {
                         break;                                        /*    寻找完成                     */
                  }
                  EepromPtr += 0x10;                           /* 指向下一个小区             */
           }
           if(EepromPtr >= EndAddr)                 /* 如果照遍都没有,是新片*/
           {
                  EepromPtr = BaseAddr;               /* 指向eeprom的起始点     */
                  for(i=0;i<90;i++)
                  {
                         SectorErase(EepromPtr+0x200*i);       /* 全部扇区擦除          */
                  }
                  while(ArrayWrite(EepromPtr, 0x10, Ttotal))       /* 写默认值   */
                  {                                                      /* 写入失败才运行的部分   */
                         byte_write(EepromPtr, 0);     /* 该单元已经失效             */
                         if(EepromPtr < EndAddr)
                         {
                                EepromPtr += 0x10;             /* 换一块新的小区             */
                         }
                         else
                         {
                                P1=0;                                  /* 指示芯片内eeprom全坏 */
                                EA= 0;                                /* 不再做任何事                 */
                                while(1);                      /* 死机                               */
                         }
                  }
           }
           ArrayRead(EepromPtr, 16);
    }
    /* ==============================================================
    将需要记忆的数据保存到eeprom
    ============================================================== */
    void DataSave()
    {
    uint  wrPtr;                                                             /* 临时指针          */
    NextArea:
           byte_write_verify(EepromPtr, 0);        /* 将原来的标记清除   */
           wrPtr = EepromPtr & 0xfe00;      /* 上一个扇区的起始地址   */
           EepromPtr += 0x10;                                         /* 目标存入地址          */
           /* ------------------ 判断是否启用新的扇区 ---------------- */
           if((EepromPtr & 0x1ff)==0)
           {
                  SectorErase(wrPtr);                     /* 将上一个扇区擦除,备用      */
                  if(EepromPtr>=EndAddr)            /* 已经用完了最后一个区域      */
                  {
                         EepromPtr = BaseAddr;                             /* 从头开始   */
                  }
           }
           /* -------------------- 数据存入前的准备 ------------------ */
           /* 。。。。。。。。。。。。。。转移、处理                             */
           Ttotal[0] = 0x55;                                       /* 重申启用标记          */
           if(ArrayWrite(EepromPtr, 0x10, Ttotal))
           {                                                      /* 数据写入,如果有错换一块   */
                  goto NextArea;
           }
    }
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-15 12:08 , Processed in 0.108816 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.