本节书摘来自异步社区《例说51单片机(c语言版)(第3版)》一书中的第1章,第1.3节,作者 张义和 , 王敏男 , 许宏昌 , 余春长,更多章节内容可以访问云栖社区“异步社区”公众号查看
例说51单片机(c语言版)(第3版)
除了无rom型的8031及8032外,mcs-51的存储器包括程序存储器(rom)与数据存储器(ram)两部分,一般地这两部分是独立的个体。标准的8x51系列具有4kb程序存储器、128b数据存储器,而标准的8x52系列具有8kb、256b数据存储器,刚好是8x51系列的两倍。不管是8x51、8031、8032或8x52,其外部扩展的程序存储器或数据存储器最多为64kb。
虽然mcs-51的兼容单片机都扩展了其内部程序存储器与数据存储器,例如atmel半导体公司的ts83c51rb2,其内部有16kb程序存储器、256b数据存储器;ts83c51rc2,其内部有32kb程序存储器、256b数据存储器;ts83c51rd2,其内部有64kb程序存储器、768kb数据存储器。尽管如此,在此仍探讨mcs-51单片机微控制器的标准存储器结构。
顾名思义,程序存储器(rom)是存放程序的位置,而cpu将自动从程序存储器中读取所要执行的指令码。mcs-51可选择使用内部程序存储器或外部程序存储器(如图1-18所示),说明如下。

若使用8031或8032,由于内部没有程序存储器,一定要使用外部程序存储器,所以其overline {{text{ea}}} 引脚必须接地。

当overline {{text{ea}}} 引脚接高电平时,cpu将使用内部程序存储器,若程序超过4kb(8x51)或8kb(8x52)时,cpu会自动从外部程序存储器里,读取超过部分的程序代码。

当overline {{text{ea}}} 引脚接地时,cpu将自外部程序存储器读取所要执行的指令码,而cpu内部的程序存储器形同虚设。
说明:
4kb的程序存储器对于初学者而言,已是绰绰有余。坏掉的8x51/8x52,很可能是其中的程序存储器坏掉,可将其overline {{text{ea}}}引脚接地,改为外接程序存储器,即可当作8031/8032使用。
当cpu复位后,程序将从程序存储器0000h地址位置开始执行,如没有遇到跳转指令,则按程序存储器地址顺序执行。当然,程序存储器前面几个位置还有一些玄机,留待中断的单元再详细说明。
图1-18 mcs-51的程序存储器结构
mcs-51的程序存储器与数据存储器是分开的独立区块,所以存取数据存储器时,所使用的地址并不会与程序存储器冲突。相对于程序存储器而言,数据存储器就不那么简单,如图1-19所示。
图1-19 mcs-51的数据存储器结构
除了内部数据存储器外,8x51的数据存储器还可扩展外部数据存储器,这两部分的数据存储器可以并存。不过,存取数据存储器时,所采用的指令并不一样,例如,存取内部数据存储器时,可用mov指令,但存取外部数据存储器时,则使用movx指令。
另外,内部数据存储器中,从0000h到007fh之间的128b为可直接寻址或间接寻址的存储器。在编写c语言程序时,以数据类型来区别直接寻址与间接寻址。在这一区间的数据存储器又可分成三部分(如图1-20所示),说明如下。
1.寄存器组区
0000h到001fh的32个地址为寄存器组(register bank)区,说明如下。
(1)0000h到0007h为寄存器组0(即rb0),0008h到000fh为寄存器组1(即rb1),0010h到0017h为寄存器组2(即rb2),0018h到001fh为寄存器组3(即rb3)。
图1-20 内部数据存储器
(2)每组寄存器组都包含r0~r7共8个寄存器,而任一时刻只能使用其中一组寄存 器组。
(3)寄存器组的切换可以用程序状态字寄存器(program status word,psw)中的rs1与rs0来决定,如表1-4所示。
(4)当cpu复位时,系统的堆栈指针(sp)指向07h地址,所以数据存入堆栈时,将从08h开始,也就是rb1里的r0地址。为避免冲突或不必要的错误,通常会把堆栈指针移到30h以后的地址。
2.可位寻址区
0020h到002fh的16个字节存储器区为可位寻址区。通常存取存储器是以字节为单位,“可位寻址”则是指定存取1个位(bit)。在8051的汇编语言里,可使用布尔运算指令进行位操作,例如,要把20h存储器地址的bit 5设置为1,则可使用下列指令:
另外,从0020h到002fh的16个字节总共128个位(16×8),也可以直接指定为0到127,以刚才的20h存储器地址的bit 5而言,也可将“20h.5”指定为“05”,指令如下:
同理,若要将25h存储器地址的bit 2清除为0,则可使用下列指令:
或
其中,42=58+2。
3.一般数据与堆栈区
0030h到007fh的80个字节地址为一般数据存取及堆栈区。由于cpu复位后,堆栈指针指向07h位置,为了确保数据的安全与程序执行的正确,如果在程序之中使用了push、pop命令,最好能把堆栈指针改至本区,例如,要将堆栈指针移至0030h地址,则在程序开始处即使用如下命令:
从0080h到00ffh之间的128b为特殊功能寄存器(special function register,sfr)或可直接寻址的存储器,至于“特殊功能寄存器”,稍后再详细说明。
如果是8052/8032,则0080h到00ffh之间的128b除了是特殊功能寄存器或可直接寻址的存储器外,另外也可以使用间接寻址的方式存取与这特殊功能寄存器位置重叠但为独立的存储器。
在mcs-51里,寄存器只是cpu里特定地址的数据存储器而已。而在0080h到00ffh之间的128b,正是特殊功能寄存器(special function register,sfr)所在位置。特殊功能寄存器就是8x51/52内部的结构,若以汇编语言编写程序时,必须熟练掌握这些寄存器,若以c语言编写程序,就不是那么重要。其位置的声明放置在keil c所提供的“reg51.h”头文件(详见后面章节)里,只要把它包含到程序里即可,而不必记忆这些位置。以下简单介绍这些寄存器(如表1-5所示),仅供参考。
注:(1)本表c8-cf行部分为8052/8032才有的寄存器,本表第1列的部分为可位寻址的寄存器,较深灰底的部分为89s51/52才有的。
(2)8051/52、89c51/52只有一组数据指针寄存器,所以其中的dp0l应改为dpl,dp0h应改为dph。
p0、p1、p2、p3
p0~p3为mcs-51的4个输入/输出端口,其地址分别为80h、90h、0a0h及0b0h,待第3章再详细介绍。
sp
sp为堆栈指针寄存器(stack pointer register),其地址为81h。堆栈是一种特殊的数据存储方式,其数据的操作顺序是先进后出(first in last out,filo),当数据以push命令送入堆栈时,sp自动减1;若以pop命令从堆栈取出数据时,sp自动加1。
dpl、dph
89c51只有一组16位的数据指针寄存器(data pointer register,dptr),这组数据指针寄存器是由dpl与dph两个8位的数据指针寄存器组成,其地址分别为82h、83h。若以dpl为低8位、dph为高8位,所组成的16位数据指针寄存器将可寻址到64kb的数据地址。89s51有两组16位数据指针寄存器,分别是dp0l、dp0h、dp1l及dp1h,其地址分别为82h、83h、84h、85h。若以汇编语言编写程序时,dptr是查表法的必备寄存器。不过,使用c语言编写程序时,就不太需要由我们直接控制这个寄存器。
pcon
pcon为电源控制寄存器(power control register),其地址为87h,其功能是设置cpu的电源方式,待后续7-3-3节再行说明。
tcon
tcon为定时器/计数器控制寄存器(timer/counter control register),其地址为88h,其功能是设置定时器/计数器的启动,记录定时/计数溢出及外部中断的类型等(见第6章),待后续关于定时器/计数器部分(第7章),再行说明。
tmod
tmod为定时器/计数器方式控制寄存器(timer/counter mode control register),其地址为089h,其功能是设置定时/计数的方式,待后续关于定时器/计数器部分(第7章)再行说明。
tl0、tl1、th0、th1
tl0、th0为第一组定时器/计数器(timer0)的计数器,其地址为8ah、8ch,将th0与tl0组合即可进行16位的定时/计数。tl1、th1为第二组定时器/计数器(timer1)的计数器,其地址为8bh、8dh,将th1与tl1组合即可进行16位的定时/计数,待后续关于定时器/计数器部分(第7章)再行说明。
scon
scon为串行口控制寄存器(serial port control register),其地址为98h,其功能是设置串行口工作方式与标志,待后续关于串行口部分(第8章)再行说明。
sbuf
sbuf为串行口缓冲器(serial buffer),其地址为99h,它由使用同一个地址的两个寄存器所构成,其中一个寄存器作为发送数据用的缓冲器,另一个寄存器作为接收数据用的缓冲器。至于如何分辨同一个地址的两个寄存器,视指令而定,若是数据发送的指令,则自动定位到发送数据用的缓冲器;若是接收数据的指令,则自动定位到接收数据用的缓冲器,待后续关于串行口部分(第8章)再行说明。
ie
ie为中断使能寄存器(interrupt enable register),其地址为0a8h,其功能是启用中断功能,待后续关于中断部分(第6章)再行说明。
ip
ip为中断优先等级寄存器(interrupt priority register),其地址为0b8h,其功能是设置中断的优先等级,待后续关于中断部分(第6章)再行说明。
t2con
t2con为timer2的定时器/计数器控制寄存器,其地址为0c8h,其功能是设置timer2的启动、记录定时/计数溢出,以及外部中断的类型等,而timer2只在8052/8032中才有。
rcap2l、rcap2h
rcap2l、rcap2h为捕捉寄存器(capture register),其地址为0cah、0cbh。当timer2在捕捉方式时,若t2ex(p1.1)引脚上的输入信号由高电平跳变为低电平,tl2与th2的内容将被载入rcap2l与rcap2h里,就像是把timer2的内容“捉进”rcap寄存器一样。
tl2、th2
tl2、th2为第三组定时器/计数器(timer2)的计数器,其地址为0cch、0cdh,将th2与tl2组合即可进行16位的定时/计数。
psw
psw为cpu的程序状态字组寄存器(program status word register),其地址为0d0h,其内容说明如下。
psw.7:本位为进位标志(cy),进行加法(减法)运算时,若最左边位(msb,即bit 7)产生进位(借位)时,则本位将自动设置为1,即cy=1;否则cy=0。
psw.6:本位为辅助进位标志(ac),进行加法(减法)运算时,若bit 3产生进位(借位)时,则本位将自动设置为1,即ac=1;否则ac=0。
psw.5:本位为用户标志(f0),可由用户自行设置的位。
psw.4与psw.3:这两个位为寄存器组选择位(rs1、rs0),其功能如表1-4所示。
psw.2:本位为溢出标志(ov),当进行算术运算时,若发生溢出,则ov=1;否则 ov=0。
psw.1:本位为保留位,没有提供服务。
psw.0:本位为校验标志(p),8051采用偶校验,若acc里有奇数个1,则p=1;若acc里有偶数个1,则p=0。
acc
acc累加器(accumulator)又称为a寄存器,其地址为0e0h,这个寄存器提供cpu主要运行的位置,可说是最常用的寄存器。
b
b寄存器的地址为0f0h,主要功能是配合a寄存器进行乘法或除法运算,进行乘法运算时,乘数放在b寄存器,而运算结果的高8位放在b寄存器;进行除法运算时,除数放在b寄存器,而运算结果的余数放在b寄存器。若不进行乘/除法运算,b寄存器也可当成一般寄存器使用。
auxr
auxr寄存器为89s51新增的辅助寄存器(auxiliary register),其地址为8eh,其内容说明如下。
wdidle:本位设置在待机方式(idle mode)下,是否启用看门狗。若本位设置为1,则在idle方式下将启用看门狗;若本位设置为0,则在idle方式下将停用看门狗。
disrto:本位设置是否输出复位信号,若本位设置为1,则reset引脚(第9脚)只有输入功能;若本位设置为0,则在wdt计数完毕后,reset引脚输出复位信号(即高电平脉冲)。
disale:本位设置是否启用ale信号,若本位设置为1,则只有在执行movx指令或movc指令时,ale引脚(第30脚)才会正常工作;若本位设置为0,则固定每6个脉冲就输出1个高电平脉冲,稍后说明。
其他位为保留位。当然,这个寄存器只有在89s51里才有作用。
auxr1
auxr1寄存器为89s51新增的第2个辅助寄存器,其地址为0a2h,其内容说明如下:
dps:本位的功能是选择数据指针寄存器。若本位设置为1,则使用dp1l及dp1h;若本位设置为0,则使用dp0l及dp0h。
其他位为保留位。同样,这个寄存器只有在89s51里才有作用。
wdtrst
wdtrst寄存器为89s51新增的看门狗定时器复位寄存器(watchdogtimer reset register),其地址为0a6h。当要启用看门狗定时器wdt时,依序将01eh、0e1h放入wdtrst寄存器,当14位计数器溢出(达到16383,即3fffh),即由reset引脚送出一个高电平脉冲以复位系统。此脉冲的宽度为98 times t_text{osc},其中t_text{osc} = 1/f_text{osc} ,以12mhz的时钟脉冲为例,脉冲的宽度为98 times frac{1}{{12 times 10^6 }} cong 8.167mtext{u} s,关于看门狗与节电方式,待后续相关单元,再行说明。