0 卖盘信息
BOM询价
您现在的位置: 首页 > 电子资讯 >设计应用 > STC单片机利用IAP技术实现EEPROM的设计

STC单片机利用IAP技术实现EEPROM的设计

来源: 电子发烧友
2019-03-05
类别:设计应用
eye 189
文章创建人 拍明

原标题:STC单片机利用IAP技术实现EEPROM的设计

  

  STC89C51、52内部都自带有2K字节的EEPROM,54、55和58都自带有16K字节的EEPROM,STC单片机是利用IAP技术实现的EEPROM,内部Flash擦写次数可达100,000 次以上,先来介绍下ISP与IAP的区别和特点。

  ISP:In System Programable 是指在系统编程,通俗的讲,就是片子已经焊板子上,不用取下,就可以简单而方便地对其进行编程。比如我们通过电脑给STC单片机下载程序,或给AT89S51单片机下载程序,这就是利用了ISP技术。

STC单片机利用IAP技术实现EEPROM的设计.jpg

  IAP:In Application Programable 是指在应用编程,就是片子提供一系列的机制(硬件/软件上的)当片子在运行程序的时候可以提供一种改变flash数据的方法。通俗点讲,也就是说程序自己可以往程序存储器里写数据或修改程序。这种方式的典型应用就是用一小段代码来实现程序的下载,实际上单片机的ISP功能就是通过IAP技术来实现的,即片子在出厂前就已经有一段小的boot程序在里面,片子上电后,开始运行这段程序,当检测到上位机有下载要求时,便和上位机通信,然后下载数据到存储区。大家要注意千万不要尝试去擦除这段ISP引导程序,否则恐怕以后再也下载不了程序了。STC单片机内部有几个专门的特殊功能寄存器负责管理ISP/IAP功能的,见表1。

  表1 ISP/IAP相关寄存器列表

  名称

  地址

  功能描述

  D7

  D6

  D5

  D4

  D3

  D2

  D1

  D0

  复位值

  ISP_DATA

  E2h

  Flash数据寄存器

  1111 1111

  ISP_ADDRH

  E3h

  Flash高字节地址寄存器

  0000 0000

  ISP_ADDRL

  E4h

  Flash低字节地址寄存器

  0000 0000

  ISP_CMD

  E5h

  Flash命令模式寄存器

  MS2

  MS1

  MS0

  xxxx x000

  ISP_TRIG

  E6h

  Flash命令触发寄存器

  xxxx xxxx

  ISP_CONTR

  E7h

  ISP/IAP 控制寄存器

  ISPEN

  SWBS

  SWRST

  WT2

  WT1

  WT0

  000x x000

  ISP_DATA:ISP/IAP操作时的数据寄存器。

  ISP/IAP从Flash读出的数据放在此处,向Flash写入的数据也需放在此处。

  ISP_ADDRH:ISP/IAP操作时的地址寄存器高八位。

  ISP_ADDRL:ISP/IAP操作时的地址寄存器低八位。

  ISP_CMD:ISP/IAP操作时的命令模式寄存器,须命令触发寄存器触发方可生效。命令模式如表2所示。表2 ISP_CMD寄存器模式设置

  D7

  D6

  D5

  D4

  D3

  D2

  D1

  D0

  模式选择

  保留

  命令选择

  0

  0

  0

  待机模式,无ISP操作

  --

  --

  --

  --

  --

  0

  0

  1

  对用户的应用程序flash区及数据flash区字节读

  --

  --

  --

  --

  --

  0

  1

  0

  对用户的应用程序flash区及数据flash区字节编程

  --

  --

  --

  --

  --

  0

  1

  1

  对用户的应用程序flash区及数据flash区扇区擦除

  程序在系统ISP程序区时可以对用户应用程序区/数据Flash区(EEPROM)进行字节读/字节编程/扇区擦除;程序在用户应用程序区时,仅可以对数据Flash区(EEPROM)进行字节读/字节编程/扇区擦除。STC89C51RC/RD+系列单片机出厂时已经固化有ISP引导码,并设置为上电复位进入ISP程序区,并且出厂时就已完全加密。

  ISP_TRIG:ISP/IAP操作时的命令触发寄存器。

  在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG 先写入46h,再写入B9h,ISP/IAP命令才会生效。

  STC89C52RC,STC89LE52RC单片机内部可用DataFlash(EEPROM)的地址如表3所示,其它型号单片机请查阅相关资料。

  表3STC89C52RC、STC89LE52RC单片机内部EEPROM地址表

  第一扇区

  第二扇区

  第三扇区

  第四扇区

  起始地址

  结束地址

  起始地址

  结束地址

  起始地址

  结束地址

  起始地址

  结束地址

  2000H

  21FFH

  2200H

  23FFH

  2400H

  25FFH

  2600H

  27FFH

  第五扇区

  第六扇区

  第七扇区

  第八扇区

  起始地址

  结束地址

  起始地址

  结束地址

  起始地址

  结束地址

  起始地址

  结束地址

  2800H

  29FFH

  2A00H

  2BFFH

  2C00H

  2DFFH

  2E00H

  2FFFH

  每个扇区为512字节,建议大家在写程序时,将同一次修改的数据放在同一个扇区,方便修改,因为在执行擦除命令时,一次最少要擦除一个扇区的数据,每次在更新数据前都必须要擦除原数据方可重新写入新数据,不能直接在原来数据基础上更新内容。

  下面通过一个例子来讲解STC系列单片机EEPROM的具体用法。

  【例】:在实验板上实现如下描述,操作STC单片机自带的EEPROM,存储一组按秒递增的二位数据,并且将数据实时显示在数码管上,数据每变化一次就往EEPROM中写入一次,当关闭实验板电源,再次开启电源时,从EEPROM中读取先前存储的数据,接着递增显示。

  #include

  #include //52系列单片机头文件

  #define uchar unsigned char

  #define uint unsigned int

  #define RdCommand 0x01 //定义ISP的操作命令

  #define PrgCommand 0x02

  #define EraseCommand 0x03

  #define Error 1

  #define Ok 0

  #define WaitTIme 0x01 //定义CPU的等待时间

  sfr ISP_DATA=0xe2;//寄存器申明

  sfr ISP_ADDRH=0xe3;

  sfr ISP_ADDRL=0xe4;

  sfr ISP_CMD=0xe5;

  sfr ISP_TRIG=0xe6;

  sfr ISP_CONTR=0xe7;

  sbit dula=P2^6;//申明U1锁存器的锁存端

  sbit wela=P2^7;//申明U2锁存器的锁存端

  uchar code table[]={

  0x3f,0x06,0x5b,0x4f,

  0x66,0x6d,0x7d,0x07,

  0x7f,0x6f,0x77,0x7c,

  0x39,0x5e,0x79,0x71};

  uchar num;

  void delayms(uint xms)

  {

  uint i,j;

  for(i=xms;i》0;i--) //i=xms即延时约xms毫秒

  for(j=110;j》0;j--);

  }

  void display(uchar shi,uchar ge) //显示子函数

  {

  dula=1;

  P0=table[shi]; //送十位段选数据

  dula=0;

  P0=0xff; //送位选数据前关闭所有显示,防止打开位选锁存时

  wela=1; //原来段选数据通过位选锁存器造成混乱

  P0=0xfe; //送位选数据

  wela=0;

  delayms(5); //延时

  dula=1;

  P0=table[ge];//送个位段选数据

  dula=0;

  P0=0xff;

  wela=1;

  P0=0xfd;

  wela=0;

  delayms(5);

  }

  /* ================ 打开 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_();

  }

  /* ==================== 字节读======================== */

  unsigned char byte_read(unsigned int byte_addr)

  {

  ISP_ADDRH =(unsigned char)(byte_addr 》》 8);/* 地址赋值 */

  ISP_ADDRL =(unsigned char)(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(unsigned int sector_addr)

  {

  unsigned inTISectorAddr;

  iSectorAddr =(sector_addr & 0xfe00); /* 取扇区地址 */

  ISP_ADDRH =(unsigned char)(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(unsigned int byte_addr, unsigned charoriginal_data)

  {

  ISP_ADDRH =(unsigned char)(byte_addr 》》 8);/* 取地址 */

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

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

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

  ISP_DATA =original_data; /* 写入数据准备 */

  ISPgoon(); /* 触发执行 */

  ISP_IAP_disable(); /* 关闭IAP功能 */

  }

  void main()

  {

  uchar a,b,num1;

  TMOD=0x01; //设置定时器0为工作方式1(0000 0001)

  TH0=(65536-50000)/256;

  TL0=(65536-50000)%256;

  EA=1;

  ET0=1;

  TR0=1;

  num1=byte_read(0x2000);//程序开始时读取EEPROM中数据

  if(num1》=60)//防止首次上电时读取出错

  num1=0;

  while(1)

  {

  if(num》=20)

  {

  num=0;

  num1++;

  SectorErase(0x2000);//擦除扇区

  byte_write(0x2000,num1);//重新写入数据

  if(num1==60)

  {

  num1=0;

  }

  a=num1/10;

  b=num1%10;

  }

  display(a,b);

  }

  }

  void TImer0() interrupt 1

  {

  TH0=(65536-50000)/256;

  TL0=(65536-50000)%256;

  num++;

  }


责任编辑:David

【免责声明】

1、本文内容、数据、图表等来源于网络引用或其他公开资料,版权归属原作者、原发表出处。若版权所有方对本文的引用持有异议,请联系拍明芯城(marketing@iczoom.com),本方将及时处理。

2、本文的引用仅供读者交流学习使用,不涉及商业目的。

3、本文内容仅代表作者观点,拍明芯城不对内容的准确性、可靠性或完整性提供明示或暗示的保证。读者阅读本文后做出的决定或行为,是基于自主意愿和独立判断做出的,请读者明确相关结果。

4、如需转载本方拥有版权的文章,请联系拍明芯城(marketing@iczoom.com)注明“转载原因”。未经允许私自转载拍明芯城将保留追究其法律责任的权利。

拍明芯城拥有对此声明的最终解释权。

相关资讯