目录

  • 硬知识
    • IAP及EEPROM新增特殊功能寄存器介绍
    • EEPROM空间大小及地址
    • 小常识
    • 大建议
    • 常见问题
  • 示例程序
    • EEPROM.c
    • EEPROM.h
    • 测试程序
      • main.c

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


硬知识

摘自《STC89C52系列单片机器件手册》

STC89C5x系列单片机内部集成了的EEPROM是与程序空间是分开的,利用ISP/IAP技术可将内部Data Flash当EEPROM,擦写次数在10万次以上。EEPROM可分为若干个扇区,每个扇区包含512字节。使用时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同的扇区,不一定要用满。数据存储器的擦除操作是按扇区进行的。
       EEPROM可用于保存一些需要在应用过程中修改并且掉电不丢失的参数数据。在用户程序中,可以对EEPROM进行字节读/字节编程/扇区擦除操作。在工作电压Vcc偏低时,建议不要进行EEPROM/IAP操作。

IAP及EEPROM新增特殊功能寄存器介绍


ISP/IAP数据寄存器ISP_DATA
       ISP_DATA : ISP/IAP操作时的数据寄存器。
       ISP/IAP 从Flash读出的数据放在此处,向Flash写的数据也需放在此处
ISP/IAP地址寄存器ISP_ADDRH和ISP_ADDRL
       ISP_ADDRH : ISP/IAP 操作时的地址寄存器高八位。 该寄存器地址为E3H,复位后值为00H.
       ISP_ADDRL : ISP/IAP 操作时的地址寄存器低八位。 该寄存器地址为E4H,复位后值为00H.
ISP/IAP命令寄存器ISP_CMD
       ISP/IAP命令寄存器IAP_CMD格式如下:


       程序在系统ISP程序区时可以对用户应用程序区/数据Flash区(EEPROM)进行字节读/字节编程/扇区擦除;程序在用户应用程序区时,仅可以对数据Flash 区(EEPROM)进行字节读/字节编程/扇区擦除。已经固化有ISP引导码,并设置为上电复位进入ISP
ISP/IA命令触发寄存器ISP_TRIG
       ISP_TRIG: ISP/IAP 操作时的命令触发寄存器。 在ISPEN(ISP_CONTR.7) = 1 时,对ISP_TRIG先写入46h,再写入B9h,ISP/IAP 命令才会生效。
       ISP/IAP操作完成后,ISP地址高八位寄存器ISP_ADDRH、ISP地址低八位寄存器ISP_ADDRL和ISP命令寄存器ISP_CMD的内容不变。如果接下来要对下一个地址的数据进行ISP/IAP操作,需手动将该地址的高8位和低8位分别写入ISP_ADDRH和ISP_ADDRL寄存器。
       每次ISP操作时,都要对ISP_TRIG先写入46H,再写入B9H,ISP/IAP命令才会生效。
ISP/IAP命令寄存器ISP_CONTR
       ISP/IAP控制寄存器IAP_CONTR格式如下:

       ISPEN: ISP/IAP功能允许位。
              0:禁止IAP/ISP读/写/擦除Data Flash/EEPROM
              1: 允许IAP/ISP读/写/擦除Data Flash/EEPROM
       SWBS: 软件选择从用户应用程序区启动(送0),还是从系统 ISP监控程序区启动(送1)。要与SWRST直接配合才可以实现
       SWRST:
              0: 不操作;
              1: 产生软件系统复位,硬件自动复位。
       ;在用户应用程序区(AP区)软件复位并从系统ISP监控程序区开始执行程序
              MOV ISP_CONTR, #01100000B ;SWBS = 1(选择ISP区), SWRST = 1(软复位)
       ;在系统ISP监控程序区软件复位并从用户应用程序区(AP 区)开始执行程序
              MOV ISP_CONTR, #00100000B ;SWBS = 0(选择AP 区), SWRST = 1(软复位)

EEPROM空间大小及地址

内部可用EEPROM的地址与程序空间是分开的:程序在用户应用程序区时,可以对EEPROM 进行IAP/ISP操作。



小常识

3个基本命令——字节读,字节编程,扇区擦除
       字节编程:将"1"写成"1"或"0",将"0"写成"0"。如果某字节是FFH,才可对其进行字节编程。如果该字节不是FFH,则须先将整个扇区擦除,因为只有“扇区擦除”才可以将"0"变为"1"。
       扇区擦除:只有“扇区擦除”才可能将"0"擦除为"1"。

大建议

  1. 同一次修改的数据放在同一扇区中,不是同一次修改的数据放在另外的扇区,就不需读出保护。
  2. 如果一个扇区只用一个字节,那就是真正的EEPROM,STC单片机的Data Flash比外部EPROM要快很多,读一个字节/编程一个字节大概是10us/60us/10ms
  3. 如果在一个扇区中存放了大量的数据,某次只需要修改其中的一个字节或一部分字节时,则另外的不需要修改的数据须先读出放在STC单片机的RAM中,然后擦除整个扇区,再将需要保留的数据和需修改的数据按字节逐字节写回该扇区中(只有字节写命令,无连续字节写命令)。这时每个扇区使用的字节数是使用的越少越方便(不需读出一大堆需保留数据)。

常见问题

  1. IAP指令完成后,地址是否会自动“加1”或“减1”? 答:不会。
  2. 送46和B9触发后,下一次IAP命令是否还需要送46和B9触发?答:是,一定要。

示例程序

改自官方例程。

EEPROM.c

/*------------------------------------------------------------------*/
/* --- STC MCU Limited ---------------------------------------------*/
/* --- STC89-90xx Series MCU ISP/IAP/EEPROM Demo -------------------*/
/* --- Mobile: (86)13922805190 -------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966----------------------*/
/* --- Web: www.STCMCU.com -----------------------------------------*/
/* --- Web: www.GXWMCU.com -----------------------------------------*/
/* If you want to use the program or the program referenced in the  */
/* article, please specify in which data and procedures from STC    */
/*------------------------------------------------------------------*/#include <STC89C5xRC.H>
#include "EEPROM.h"
#include "intrins.h"/*Declare SFR associated with the IAP */
sfr IAP_DATA    =   0xE2;           //Flash data register
sfr IAP_ADDRH   =   0xE3;           //Flash address HIGH
sfr IAP_ADDRL   =   0xE4;           //Flash address LOW
sfr IAP_CMD     =   0xE5;           //Flash command register
sfr IAP_TRIG    =   0xE6;           //Flash command trigger
sfr IAP_CONTR   =   0xE7;           //Flash control register/*Define ISP/IAP/EEPROM command*/
#define CMD_IDLE    0               //Stand-By
#define CMD_READ    1               //Byte-Read
#define CMD_PROGRAM 2               //Byte-Program
#define CMD_ERASE   3               //Sector-Erasevoid Delay(unsigned char n);
void IapIdle();/*----------------------------
Disable ISP/IAP/EEPROM function
Make MCU in a safe state
----------------------------*/
void IapIdle()
{IAP_CONTR = 0;                  //Close IAP functionIAP_CMD = 0;                    //Clear command to standbyIAP_TRIG = 0;                   //Clear trigger registerIAP_ADDRH = 0x80;               //Data ptr point to non-EEPROM areaIAP_ADDRL = 0;                  //Clear IAP address to prevent misuse
}/*----------------------------
Read one byte from ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)
Output:Flash data
----------------------------*/
unsigned char IapReadByte(unsigned short addr)
{unsigned char dat;                       //Data bufferIAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait timeIAP_CMD = CMD_READ;             //Set ISP/IAP/EEPROM READ commandIAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address lowIAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address highIAP_TRIG = 0x46;                //Send trigger command1 (0x46)IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)_nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation completedat = IAP_DATA;                 //Read ISP/IAP/EEPROM dataIapIdle();                      //Close ISP/IAP/EEPROM functionreturn dat;                     //Return Flash data
}/*----------------------------
Program one byte to ISP/IAP/EEPROM area
Input: addr (ISP/IAP/EEPROM address)dat (ISP/IAP/EEPROM data)
Output:-
----------------------------*/
void IapProgramByte(unsigned short addr, unsigned char dat)
{IAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait timeIAP_CMD = CMD_PROGRAM;          //Set ISP/IAP/EEPROM PROGRAM commandIAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address lowIAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address highIAP_DATA = dat;                 //Write ISP/IAP/EEPROM dataIAP_TRIG = 0x46;                //Send trigger command1 (0x46)IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)_nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation completeIapIdle();
}/*----------------------------
Erase one sector area
Input: addr (ISP/IAP/EEPROM address)
Output:-
----------------------------*/
void IapEraseSector(unsigned short addr)
{IAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait timeIAP_CMD = CMD_ERASE;            //Set ISP/IAP/EEPROM ERASE commandIAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address lowIAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address highIAP_TRIG = 0x46;                //Send trigger command1 (0x46)IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)_nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation completeIapIdle();
}unsigned char IapWriteBytes(unsigned short addr, unsigned char * pData, unsigned short len)
{unsigned char temp[512], Addr = addr;unsigned short i;Addr >>= 9;Addr <<= 9;addr %= 512;for(i = 0; i < 512; ++i){temp[i] = IapReadByte(Addr + i);}for(i = 0; i < len; ++i){temp[addr + i] = *(pData + i);}IapEraseSector(Addr);    //Erase current sectorfor (i = 0; i < 512; ++i)           //Program 512 bytes data into data flash{IapProgramByte(Addr + i, temp[i]);}for (i = 0; i < len; ++i){if (IapReadByte(Addr + addr + i) != *(pData + i))return 0;}return 1;
}

EEPROM.h

#ifndef EEPROM_H_
#define EEPROM_H_/*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
//#define ENABLE_IAP 0x80           //if SYSCLK<40MHz
#define ENABLE_IAP   0x81           //if SYSCLK<20MHz
//#define ENABLE_IAP 0x82            //if SYSCLK<10MHz
//#define ENABLE_IAP 0x83           //if SYSCLK<5MHz//#define IAP_ADDRESS 0x1000         //Start address for STC89C51 EEPROM
#define IAP_ADDRESS 0x2000          //Start address for STC89C52 EEPROM
//#define IAP_ADDRESS 0x3000            //Start address for STC89C53 EEPROM
//#define IAP_ADDRESS 0x4000            //Start address for STC89C54 EEPROM
//#define IAP_ADDRESS 0x8000            //Start address for STC89C58 EEPROM
//#define IAP_ADDRESS 0xA000            //Start address for STC89C510 EEPROM
//#define IAP_ADDRESS 0xC000            //Start address for STC89C512 EEPROM
//#define IAP_ADDRESS 0xE000            //Start address for STC89C514 EEPROMunsigned char IapReadByte(unsigned short addr);
void IapProgramByte(unsigned short addr, unsigned char dat);
void IapEraseSector(unsigned short addr);#endif

测试程序

检测EEPROM首地址第一个数是否与DATA一致,如果不一致,点亮LED0,如果一致点亮LED1。按下KEY1后擦除第一个扇区,按下KEY2后写入DATA。

main.c

#include <STC89C5xRC.H>
#include "EEPROM.h"#define DATA 233sbit LED0 = P2^0;
sbit LED1 = P2^1;
sbit KEY1 = P3^1;
sbit KEY2 = P3^0;void Delay20ms()      //@11.0592MHz
{unsigned char i, j;i = 36;j = 217;do{while (--j);} while (--i);
}void main(void)
{while(1){      if (IapReadByte(IAP_ADDRESS) == DATA) {LED0 = 1;LED1 = 0;}else{LED0 = 0;LED1 = 1;}if (!KEY1){Delay20ms();if (!KEY1){IapEraseSector(IAP_ADDRESS);}while(!KEY1);}if (!KEY2){Delay20ms();if (!KEY2){IapProgramByte(IAP_ADDRESS, DATA);}while(!KEY2);}}
}

【51单片机快速入门指南】7:片上EEPROM相关推荐

  1. 【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器

    目录 硬知识 DHT11 DHT22 通信协议 读取步骤 数据解读 DHT11 DHT22 示例程序 DHT11_22.c DHT11_22.h 测试程序 main.c 实验现象 DHT11 DHT2 ...

  2. 【51单片机快速入门指南】4.6:I2C 与 PCF8563实时时钟日历芯片

    目录 硬知识 概述 特性 功能描述 报警功能模式 定时器模式 CLKOUT输出 复位低电压检测器和时钟监视器 低电压检测器和时钟监视器 寄存器结构 寄存器概述 BCD编码格式寄存器概述 Control ...

  3. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  4. 【51单片机快速入门指南】6.1:LCD1602的八线、四线控制及自定义符号,完美兼容Proteus仿真

    目录 硬知识 显示特性 接口定义 操作时序 写操作时序 读操作时序 寄存器 忙标志位BF 地址计数器(AC) 显示数据寄存器(DDRAM) CGROM CGRAM 指令 清屏指令 光标归位指令 进入模 ...

  5. 【51单片机快速入门指南】5.3:SPI控制晶联讯JLX12864G_08602 LCD屏幕

    目录 示例程序 JLX12864G_08602.c JLX12864G_08602.h JLX12864G_08602_Font.c JLX12864G_08602_Font.h 测试程序 main. ...

  6. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

  7. 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

    目录 硬知识 IO 扩展芯片 TCA6416A TAC6416A 的寄存器 IO 输入寄存器 IO 输出寄存器 IO 反相寄存器 IO 方向寄存器 TCA6416A 的操作 TCA6416A 写数据 ...

  8. 【51单片机快速入门指南】4.4.1:python串口接收磁力计数据并进行最小二乘法椭球拟合

    目录 硬知识 Python代码 使用方法 串口收集数据 椭球拟合 验证 STC15F2K60S2 16.384MHz Keil uVision V5.29.0.0 PK51 Prof.Develope ...

  9. 【51单片机快速入门指南】4.4:I2C 读取HMC5883L / QMC5883L 磁力计

    目录 硬知识 简介 操作模式 HMC5883L 连续测量模式 单次测量模式 闲置模式 QMC5883L 连续测量模式 待命模式 主要差异 寄存器 寄存器列表 HMC5883L QMC5883L 配置寄 ...

  10. 【51单片机快速入门指南】4.3.3: MPU6050使用Mahony AHRS算法实现六轴姿态融合获取四元数、欧拉角

    目录 源码 Mahony_6.c Mahony_6.h 使用方法 测试程序 main.c 效果 STC89C516 32MHz Keil uVision V5.29.0.0 PK51 Prof.Dev ...

最新文章

  1. 计算机网络Rip例题,计算机网络技术习题
  2. 使用internal(com.android.internal)和hidden(@hide)APIs – Part 5
  3. ODS(Operational Data Store)定义
  4. Linux和Windows互传文件可视化工具lrzsz的安装和使用
  5. windows设置mysql使用率_Windows下配置Mysql
  6. 万字长文带你解析23 个问题 TCP 疑难杂症!
  7. MVC Razor基础
  8. Vue开发实例(03)之Vue项目引入element_ui
  9. PyTorch 音频处理教程
  10. c语言课程设计作业,c语言课程设计心得体会
  11. 计算机主机的系统安装方法,电脑安装系统的最全教程,系统安装教程详解
  12. ccxprocess启动项可以禁用么_启动项禁用
  13. JAVA 将图片转换成pdf文件
  14. React基础(伍)———【案例】todoList
  15. 基于32位版CentOS6配置符合HA模式的CDH5.7.0的Hadoop+Yarn+HBase集群
  16. 关于使用Navicat,Mysql Workbench,PowerDesigner根据mysql数据库生成ER(实体联系图)的解决方案的总结
  17. 分组密码体制【密码学笔记】
  18. [c#] DirectoryInfo.GetDirectories() 能扫描读取到文件夹,目录里却不存在。
  19. 蓝紫色食物对心血管最好
  20. Oracle分区表概述、分类、使用方法及注意事项

热门文章

  1. RIP、 OSPF、 EIGRP的区别
  2. Docker初学者指南-如何创建您的第一个Docker应用程序
  3. webassembly_WebAssembly的设计
  4. slack 使用说明_我如何使用Node和Botkit构建HR Slack Bot
  5. 两个链接合并_如何找到两个链接列表的合并点
  6. 计算机系统的数制及转换
  7. Django 模型与 Mysql 数据类型对应
  8. 设定Word段落的背景色
  9. java 的 == 和equals()区别
  10. 微信公众号开发笔记1-获取Access Token