片内数据存储器为随机存取存储器(RAM),容量很少(51子系列只有128B,52子系列只有256B),通常用来存储程序运行时所需要的常数或变量。
1.内部数据存储器编址
STC15W4K32S4系列单片机片内包含4KB的RAM地址,其片内数据存储器由基本RAM区、扩充RAM区、扩展RAM区和特殊功能寄存器(SFR)区组成,其编址方法如下:
1)基本地址128B,编址为00H~7FH。
2)片内扩充地址128B,编址为80H~FFH。
3)SFR特殊功能寄存器128B,编址为80H~FFH。
4)片内扩展地址3840B,编址为00H~0EFFH。
由于片内数据存储器中的扩充RAM地址和SFR的编址重叠,为不引起读/写访问混乱,规定RAM中的扩充地址采用间接寻址方式读/写,基本地址和SFR采用直接寻址方式进行访问。而片内扩展地址采用外部存储器间接寻址方式进行访问。
2.内部数据存储器的划分
STC单片机片内RAM块的基本地址编址为00H~7FH,分为工作寄存器区、位寻址区、数据缓冲区和堆栈区4部分。内部数据存储器结构如图2-7所示。
图2-7 8051单片机内部数据 存储器结构
(1)工作寄存器区
从图2-7中可以看到,单片机内部RAM块的00H~1FH区是工作寄存器区,分为4个组,每组包含8个工作寄存器R0~R7,共32个内部RAM单元地址。用户可以通过指令改变PSW状态寄存器中的RS1和RS0值来选择当前要使用的工作寄存器组(注意,4个工作寄存器组不能同时使用)。如果程序中并不需要4个工作寄存器组,那么剩下的工作寄存器组所对应的地址单元也可以作为一般数据缓冲区或堆栈区使用。
单片机的这种功能为软件设计带来了便利,特别是在中断嵌套的应用中,为实现工作寄存器的现场保护提供了方便。工作寄存器和片内RAM地址对应关系见表2-3。
表2-3 工作寄存器和片内RAM地址对应关系
(2)位寻址区
内部RAM的20H~2FH为位寻址区域(见表2-4),这16个单元(共128位)的每一位都有一个位地址,位地址编址范围为00H~7FH。
表2-4 内部RAM中位单元与位地址对应表
(续)
位寻址区域的这16个单元构成了1位处理机的存储器空间,每一位都有自己的位地址,每一位都可以用作软件触发器或标志位,由程序直接进行位处理。通常可以把各种程序状态标志、位控制变量存于位寻址区内。当位寻址区空闲不用时,这16个单元也可以进行字节寻址,作为一般数据缓冲器使用。
(3)数据缓冲区
内部RAM的30H~7FH是数据缓冲区,也称为用户RAM区,共80个单元,还有内部扩充RAM区范围的80H~FFH地址,共208个单元作为用户RAM地址。
内部扩展RAM区范围的100H~FFFH地址,共3840个单元也是用户RAM地址。对这段地址空间操作时,应对AUXR特殊功能寄存器的EXTRAM位置0,并采用DPTR作间接寻址指针,才能进行访问(单片机复位时EXTRAM=0)。(www.xing528.com)
外部扩展RAM区范围的000H~FFFFH地址,共64K个单元是外部RAM地址。对这段地址空间操作时,应对AUXR特殊功能寄存器的EXTRAM位置1,并采用DPTR作间接寻址指针,才能进行访问。
3.堆栈和堆栈指针
计算机在实际的程序运行中,往往需要一个后进先出的RAM区,以保存CPU的现场,这种后进先出的缓冲器区称为堆栈。堆栈是一种数据项按序排列的数据结构,占一段内部数据单元,按后进先出的方式工作,使用一个专用寄存器作堆栈指针,指明当前堆栈的操作位置,堆栈指针总是指向栈顶。
堆栈就好比水桶或手枪中的弹匣,更似一个装乒乓球的小圆筒(圆筒一端开口,一端封闭,直径比乒乓球稍大),将编写了不同编号的乒乓球放入圆筒里时,就相当于把数据压入了堆栈。这时,通过对乒乓球的放入和取出可以发现一个规律:先放进去的乒乓球只能在后面取出来,后放进去的乒乓球却能够先行取出。堆栈的“后进先出”就是这样的结构特点。
堆栈只能在栈顶的一端对数据项进行插入和删除。当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack);而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。根据堆栈的生成方式,又分为递增堆栈(Ascending Stack)和递减堆栈(Decending Stack)。如果把堆栈比作一个水桶,那么桶底就相当于栈底,桶中的水面就相当于栈顶,栈顶随水面的高低而变化。
因此,堆栈就是这样一种数据结构,它在内存中开辟了一个存储区域,数据按顺序一个一个地存入(即用PUSH指令压入)这个区域。堆栈指针总是指向最后一个压入堆栈的数据单元,存储这个地址指针的寄存器就叫堆栈指示器。开始放入数据的单元叫“栈底”。数据顺序存入的过程叫“压栈”。在压栈的过程中,每当有一个数据压入堆栈,就顺序存储在随后的一个单元中,堆栈指示器中的地址数自动加1。读取这些数据时,按照堆栈指示器中的地址读取数据,每取出一字节的数据,堆栈指示器中的地址数自动减1,这个过程叫弹出(即用POP指令)。如此就实现了后进先出的操作。
单片机在实际程序运行中需要在内部开辟一段缓冲区作为堆栈,以便在子程序调用、中断服务处理等场合保存CPU的运行现场。单片机的堆栈区不是固定的,原则上可设在内部RAM的任意区域内,栈顶的位置由栈顶指针(SP)指出。但为了防止与工作寄存器区和位寻址区的数据冲突,一般在30H~7FH范围内选择一块作堆栈区,栈顶的位置由专用的堆栈指针寄存器SP给出。复位时,SP为07H单元,堆栈的实际位置从08H开始,即位于工作寄存器区内。因此,在程序开始初始化时,用户可以给SP赋以新值(也可以不变),用来确定堆栈的起始位置,即栈底位置。
单片机的堆栈属于向上生长型,如图2-8所示。当一个数据压入堆栈时,SP的内容先自动加1,然后再压入数据。随着数据的压栈,SP的值也越来越大。当一个数据从堆栈弹出之后,SP自动减1。随着数据的弹出,SP的值也随之减小。
除用软件方式直接改变SP值外,执行PUSH和POP、子程序调用、中断响应、子程序返回(RET)和中断返回(RETI)等指令时,SP值将自加或自减。
图2-8 单片机堆栈操作示意图
堆栈有3个具体功能:
(1)保护断点
单片机在调用子程序操作或执行中断操作后,最后都要返回主程序。因此,在调用子程序前应预先把主程序的断点(即当前执行子程序调用指令的下一条指令的PC值)保存在堆栈中,为程序的正确返回做好准备。在调用子程序或产生中断时,单片机将自动把当前的PC值压入堆栈。假设堆栈指针(SP)=6FH,则
PUSH PCL;先将(SP)=(SP)+1=70H,然后压入低字节(PCL)→((SP))
PUSH PCH;再将(SP)=(SP)+1=71H,然后压入高字节(PCH)→((SP))
当子程序或中断返回时均应执行一条返回指令RET或RETI,则单片机在执行返回指令时将自动把堆栈栈顶的2字节数据传送到PC中。如
POP PCH;先弹出高字节→PCH,然后(SP)=(SP)-1=70H
POP PCL;再弹出低字节→PCL,最后(SP)=(SP)-1=6FH
操作时,满足堆栈数据“后进先出”的原则。
(2)现场保护
单片机在执行子程序或中断服务子程序之后,需要用到一些RAM单元和寄存器单元。如果这些单元已经被主程序使用,这时就会破坏单元中原有的内容,造成资源冲突。因此,为了不破坏原有的数据,必须在实际执行子程序之前将这些数据保存起来,待子程序执行完毕后再按原样恢复,这就是现场保护。
现场保护最方便、最快捷的办法就是采用堆栈。保护数据时,使用PUSH指令把数据压入堆栈;恢复数据时,使用POP指令按照“后进先出”的原则,将堆栈数据送回指定的寄存器。
(3)临时暂存数据
在程序设计时,有些中间变量或数据需要暂时保存,以备下一步数据处理,待数据处理完成后,就可丢弃这些数据。这时,可把数据临时存储在堆栈中,以减少不必要的内存开销,并快速实现数据缓存。
单片机系统上电复位时,堆栈(SP)=07,即占用了08H开始的基本RAM地址,而这段地址分配给了R工作寄存器。因此,在实际应用中,特别是设计的程序比较复杂,需要使用多组工作寄存器时,为避免资源使用冲突,应在主程序开头初始化段,将堆栈指针编程设置到基本RAM地址的高端,例如,(SP)=6FH即可(汇编指令为MOV SP,#6FH),以便使堆栈占用70H~7FH这段地址。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。