单片机寻址

单片机寻址是如何实现的

什么是单片机的寻址?单片机有几种寻址方式?
我们已经知道,单片机的工作过程就是一条一条地从ROM 存储器中取出指令然后执行相关的操作,那么一条指令究竟有哪几部分组成?它又包括哪些内容?一般来说一条指令总是有操作码字段和操作数字段两部分组成,看下面两条指令,MOV R7,#250;MOV P1,#0FFH ,这是我们以前学过的指令,在这两条指令中MOV 就是操作码字段,R7 和P1 就是操作数地址字段,而#0FFH 我们称为常数(也就是立即数),单片机执行指令时就根据指令中给出的地址寻找实际的操作数,不能理解,没关系,继续往下看。
一.单片机的寻址
先来看下面的实验:

程序一就是我们以前做过的LED 灯闪烁的实验,我们已经知道每次调用延时程序的时间都是相同的(125mS) ,如果现在提出这样的要求:灯亮后延时时间为125mS 灯灭,灯灭后又延时100mS 秒灯亮,如此循环,这样的程序还能满足要求吗?显然不能,怎么办?我们可以把它改成程序二,也就是先把一个数送入30H ,在子程序中R7 中的值并不固定,而是根据30H 单元中传过来的数来确定,这样就可以满足要求,大家自行分析一下这个程序。

从这里我们可以得出结论,在数据传递中要找到被传递的数,很多时候,这个数并不能直接给出,而是需要变化,这就引出了一个概念:如何寻找操作数,我们把寻找操作数所在单元地址的过程称之为寻址。在实验一中,我们直接使用数所在单元的地址找到了操作数,所以称之为直接寻址。而在实验二中,我们是把数先放在工作寄存器中,从工作寄存器中寻找数据,这种方式则称之为寄存器寻址。例如:MOV R7,30H,就是把工作寄存器30H 单元中的数送到R7 中,这就是寄存器寻址。

接下来提一个问题:我们知道,工作寄存器就是内存单元的一部份,如果我们选择工作寄存器组0,则R0 就是RAM 的00H 单元,那么这样一来,MOV A,00H ,和MOV A,R0 不就没什么区别了吗?为什么要加以区分呢?的确,这两条指令执行的结果是完全相同的,都是将00H 单元中的内容送到A 中去,但是执行的过程不同,执行第1 条指令需要2 个周期;而执行第2 条则只需要1 个周期,第1 条指令变成最终的目标码要两个字节(E5H 00H),而第2 条则只要一个字节(E8h)就可以了。也许有朋友会问,不就差了一个周期吗,为什么怎么斤斤计较!如果是12M 晶振的话,也就1个微秒,一个字节又能有多少呢?当然如果这条指令只执行一次,也许无所谓,但一条指令如果执行上1000 次,就是1 毫秒,如果要执行1000000 次,就是1S 的差别,这就很可观了,单片机要做的就是实时控制,所以必须如此“斤斤计较”。再来看另一个问题,现在我们已经知道,寻找操作数可以通过直接给的方式(立即寻址)和直接给出数所在单元地址的方式(直接寻址),这就够了吗?

看下面的问题,要求从30H 单元开始,取20 个数,分别送入累加器A 中。就我们目前掌握的办法,要从30H 单元取数,就用MOV A,30H ,那么下一个数呢?是31H 单元的,怎么取呢?还是只能用MOV A,31H ,那么20 个数,不是得20 条指令才能写完吗?这里只有20 个数,如果要送200 个或2000 个数,那岂不要写上200 条或2000 条命令?这未免太笨了吧。为什么会出现这样的状况?因为我们只会把地址写在指令中,所以就没办法了,如果我们不是把地址直接写在指令中,而是把地址放在另外一个寄存器单元中,根据这个寄存器单元中的数值决定该到哪个单元中取数。比如,当前这个寄存器中的值是30H ,那么就到30H 单元中去取,如果是31H 就到31H 单元中去取,就可以解决这个问题了。怎么个解决法呢?既然看的是寄存器中的值,那么我们就可以通过一定的方法让这里面的值发生变化,比如取完一个数后,将这个寄存器单元中的值加1,还是执行同一条指令,可是取数的对象却不一样了。

看下面的例子:

MOV R7,#20 ;(1)

MOV R0,#30H ;(2)

LOOP:MOV A,@R0 ;(3)

INC R0 ;(4)

DJNZ R7,LOOP ;(5)
这个例子中的大部份指令我们是能看懂的,第1 条,是将立即数20 送到R7 中,执行完后R7 中的值应当是20;第2 条是将立即数30H 送入R0 工作寄存器中,所以执行完后,R0 单元中的值是30H;第3 条,是看一下R0 单元中是什么值,把这个值作为地址,取这个地址单元的内容送入A 中,此时,执行这条指令的结果就相当于执行MOV A,30H ;第4 条,没学过,就是把R0 中的值加1,因此执行完后,R0 中的值就是31H 了;第5 条,学过,将R7 中的值减1,看是否等于“0”,不等于“0”,则转到标号LOOP 处继续执行,因此,执行完这句后,将转去执行MOV A,@R0 这一条,此时相当于执行了MOV A,31H (因为此时的R0 中的值已是31H 了);如此,直到R7 中的值逐次相减等于“0”,也就是循环20 次为止,就实现了我们的要求:从30H 单元开始将20 个数据送入A 中。这是另一种寻找数据的方法,由于数据是间接被找到的,所以把这种寻址方式称之为寄存器间址寻址。(注意☺,在间址寻址中,只能用R0 或R1 来存放等待寻找的数据)。
除了以上几种寻址方法外,单片机还有变址寻址,相对寻址和位寻址共七种寻址方式。这些您暂时可以不去深究它,我们以后会结合具体的实验再来详细介绍,这里只是为了归类,所以才把它们例举在一起。

二.寻址方式举例
1.直接寻址
直接寻址时,指令中的地址码部分直接给出了操作数的有效地址。例如:MOV A,4FH ;A←(4FH)可用于直接寻址的空间有内部RAM 的低128 字节(包括其中的位寻址区与特殊功能寄存器)。
2.寄存器直接寻址
寄存器寻址时,指令中地址码给出的是某一通用寄存器的编号,寄存器的内容为操作数。
例如:MOV A,R7 ;A←(R7)
可用于寄存器寻址的空间有R0-R7,ACC,CY(位),DPTR,B。
3.寄存器间接寻址
寄存器间接寻址时,指令中给出的寄存器的内容为操作数的地址,而不是操作数本身。例如:MOV A,@R0 ;A←[(R1)]可用于寄存器间接寻址的空间只能是R0 和R1, 用DPTR 或PC 可间接寻址64K 字节外部的RAM 或ROM.
4.立即寻址
立寻址时,指令中地址码部分给出的就是操作数本身。
例如:MOV A,#0FFH ;A←0FFH 可用于立即寻址的空间有
5.变址寻址
变址寻址时,指定变址寄存器的内容与指令中给出的偏移量相加DPTR 所得的结果作为操作数的地址。
例如:MOVC A,@A+DPTR ; A←[(A)+(DPTR)]。
无论用DPTR 或PC 作为基准指针,变址寻址只适用于程序存储器(即ROM),通常用于读取数据表。
6.相对寻址
相对寻址时,由程序计数器PC 提供的基准地址与指令中提供的偏移量rel 相加,得到操作数的地址。例如:SJMP rel ;PC←(PC)+2+rel
7.位寻址
位寻址时,操作数是二进制数的某一位,其位地址出现在指令中。
例如:SETB bit ;(bit)←1
可用于位寻址的空间有内部RAM 的可位寻址区和SFR(特殊功能寄存器)中的字节地址可以被8
整除(即地址以0、8、F 结尾)的寄存器空间。