第十课 单片机的寻址

这一课让我们来了解一下单片机的寻址方式 这对大家掌握指令会有很大的帮助 什么是单片机

的寻址 单片机有几种寻址方式 请往下看

我们已经知道 单片机的工作过程就是一条一条地从 ROM 存储器中取出指令然后执行相关的操作

那么一条指令究竟有哪几部分组成 它又包括哪些内容 一般来说一条指令总是有操作码字段和操作

数字段两部分组成 看下面两条指令 MOV R7 #250 MOV P1 #0FFH 这是我们以前学过的指令 在 这两条指令中 MOV 就是操作码字段 R7 P1 就是操作数地址字段 #0FFH 我们称为常数(也就是立即

) 单片机执行指令时就根据指令中给出的地址寻找实际的操作数 不能理解 没关系 继续往下看

单片机的寻址 先来看下面的实验

程序一 程序二

MAIN SETB P1.0 MAIN SETB P1.0 1

MOV 30H #255

LCALL DELAY LCALL DELAY 2

CLR P1.0 CLR P1.0

MOV 30H,#200

LCALL DELAY LCALL DELAY

AJMP MAIN AJMP MAIN

DELAY

MOV R7

#250

DELAY

MOV

R7

30H

D1

MOV R6

#250

D1

MOV

R6

#250

D2 DJNZ R6 D2 D2 DJNZ R6 D2

DJNZ R7 D1 DJNZ R7 D1

RET RET

END END

 

程序一就是我们以前做过的 LED 灯闪烁的实验 我们已经知道每次调用延时程序的时间都是相同 的125mS) 如果现在提出这样的要求 灯亮后延时时间为 125mS 灯灭 灯灭后又延时 100mS 秒灯亮

如此循环 这样的程序还能满足要求吗 显然不能 怎么办 我们可以把它改成程序二 也就是先把一

个数送入 30H 在子程序中 R7 中的值并不固定 而是根据 30H 单元中传过来的数来确定 这样就可以 满足要求 大家自行分析一下这个程序

从这里我们可以得出结论 在数据传递中要找到被传递的数 很多时候 这个数并不能直接给出

而是需要变化 这就引出了一个概念 如何寻找操作数 我们把寻找操作数所在单元地址的过程称之为

寻址 在实验一中 我们直接使用数所在单元的地址找到了操作数 所以称之为直接寻址 而在实验二

中 我们是把数先放在工作寄存器 30H 中 再把 30H 中的数送到 R7看实验二的第 6 条指令这种方

式则称之为寄存器寻址 讲到这里 大家有没有看出来 这里的 30H 前面是没有#的 而象 MOV R7

#250 这样的指令在 250 前是有#的 为什么 我前面提到过 大家好好回顾一下

接下来提一个问题 我们知道 工作寄存器就是内存单元的一部份 如果我们选择工作寄存器组

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 的差别 这就很可观了 单片机要做的就是实 时控制 所以必须如此 斤斤计较

 

32

----------------

 

接下来再看另一个问题 现在我们已经知道 寻找操作数可以通过直接给的方式 立即寻址 和

直接给出数所在单元地址的方式 叫间接寻址 有这两中方式这就够了吗 看下面的问题 要求从 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 来存放等待寻找的数据 当然还可以用 DPTR 或 PC 访问外部存储器的数

据 只不过在这里我们讨论的是寄存器间接寻址 所以这两个就不在讨论范围之内

除了以上几种寻址方法外 单片机还有变址寻址 相对寻址和位寻址共七种寻址方式 这些您暂 时可以不去深究它 我们以后会结合具体的实验再来详细介绍 这里只是为了归类 所以才把它们例举 在一起 下面举几个例子说明一下

二 寻址方式举例

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 立即寻址

立即寻址时 指令中地址码部分给出的就是操作数本身

 

33

----------------

 

例如 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 bit1

可用于位寻址的空间有内部 RAM 的可位寻址区和 SFR特殊功能寄存器中的字节地址可以被 8

整除即地址以 0 8 F 结尾的寄存器空间

三 本课总结

这一课主要讲述了单片机的寻址方式 寻址是单片机中一个非常重要的概念 单片机执行指令实 际上就是到不同的地址空间寻找操作数的过程 请大家务必搞清寻址的概念和寻址的方法

到本课为止 我们已经连续讲了很多单片机的基本概念 可能有些朋友会觉得很难 我这里可以 告诉大家 如果您有这种感觉 那绝对是好事 因为学习使用单片机本来就不是一朝一夕的事 需要长 期的结累和实践 只有持之以恒 才能取得最后的胜利 其实世上很多事都是如此

不过话又说回来 当碰到一时无法理解的概念和知识时 如何来搞懂它呢 对于单片机学习来说

我可以给大家介绍一个简单的好方法 那就是先放着再说 继续往下学 等学会了后面的概念时你会突 然发现有很多原来的不懂的东西会变得非常的简单 试试看 不要停留 继续往下看

四 第 10 课习题

1 什么是单片机的寻址 单片机有几种寻址方式

2 单片机的指令有几部分组成

3 直接寻址和间接寻址的区别在哪里

4 写一段从 0AH 单元开始 把 20 个数送入 A 中的程序

 

34

----------------

 

第十一课 单片机的指令 一

指令就是编程者给单片机下的命令 也就是我们平常所说的单片机软件 前面我们已经陆续地讲

到了一些指令 但还远远不够 从这一课开始就要全面的讲解指令了 希望大家多动手实验 巩固所学 的知识 说实在的 其实单片机并不难学

为了让大家比较容易记忆 按照常规分类 我把单片机的 111 条指令分成了五类—即数据传递类 指令 算术运算类指令 逻辑运算类指令 控制转移类指令和位操作指令 这一课先来看数据传递类指

一 数据传递类指令

数据传递类指令是单片机中用的最多的指令 在 51 系列单片机的 111 条指令中共有 28 条是数据 传递类指令 前面我们已经学到了几条 比如 MOV R7 #250 MOV A R6 等 那么它们是怎么分类的

呢 请往下看

1 以累加器为目的操作数的指令

1
MOV
A Rn

2
MOV
Rn A

 


 

 

指令 1 把 Rn 中的数送入累加器 A Rn 代表工作寄存器 R0-R7 以后我们只要写到 Rn 都代表 R0-R7

这一点请大家记住了指令2则相反 把累加器 A 中的数送入工作寄存器中 指令3是把直接

地址中的数送入累加器 A 中 driect 就代表直接地址以后也相同而指令4就是上一课我们讲 的寄存器间接寻址 什么意思 这里再重复一遍 就是看一下工作寄存器中是什么值 把这个值作为地

址 把这个地址中的数送入累加器 A 中 Ri 代表什么意思呢 就是工作寄存器 R0 或者 R1以后如果写

Ri 都代表 R0 或 R1第5条指令就是把立即数也叫常数直接送入累加器 A 中 很显然 data 就 代表立即数以后也相同其实这个我们以前提到过 加#的数就代表送入的是这个数的本身

接下来举几个实例加以说明 大家可以用 DUG8051 这个软件验证一下

A MOV R7 #20H

MOV A R7 将工作寄存器 R7 中的值 20H 送入 A R7 中的值保持不变

B MOV A #250

MOV R7 A 将 A 中的值 250 送入工作寄存器 R7 A 中的值保持不变

C MOV 30H #20H

MOV A,30H 将内存 30H 单元中的值 20H 送入 A 30H 单元中的值保持不变

D MOV 20H #250

MOV R0 #20H

MOV A,@R0 先看 R0 中是什么值 把这个值作为地址 并将这个地址单元中的值送入 A

中 执行命令前 R0 中的值为 20H 则是将 20H 单元中的值 250 送入 A 中 最终送到 A 中的值是 250

E MOV A,#20H 将立即数 20H 送入 A 中 执行完本条指令后 A 中的值是 20H

这里有一点要解释一下 在实例 D 中 MOV 20H #250 中的 20H 是一个地址 而 MOV @R0,#20H 中的 20H 却是一个地址 为什么 大家结合前面的知识好好想想 如果不明白 说明你对地址和数据的 概念还没有搞清楚 呵呵 那就有点麻烦了*^*

2 以寄存器 Rn 为目的操作数的指令

1
MOV
Rn
A

2
MOV
Rn
direct

 

35

----------------

 

3MOV Rn #data

举几个实例大家自行分析一下 这个应该不难吧

 


 

 

这组指令功能是把源地址单元中的内容送入工作寄存器 源操作数不变

3 以直接地址为目的操作数的指令

1 MOV direct A

例如 MOV 30H A将累加器 A 中的数送入内存单元 30H

2 MOV direct Rn

例如 MOV 30H R7将寄存器 R7 中的数送入内存单元 30H

3 MOV direct direct

例如 MOV 30H 20H将内存单元 20H 中的数送入内存单元 30H

4 MOV direct @Ri

例如 MOV 30H @R0看一下 R0 中是什么值 把这个值作为地址 并将这个地址单元中的值送

入 30H 中 如执行指令前 R0 中的值为 20H 则是将 20H 单元中的值送入 30H 中

5 MOV direct #data

例如 MOV 30H #20H将立即数 20H 送入内存单元 30H 注意 和第三条指令的区别MOV 30H

20H这里的 20H 是一个 16 进制数 为什么 结合前面的知识自己想一下

4 以间接地址为目的操作数的指令

 


 

 

这三条指令就不介绍了,大家自行分析一下,不过有一点希望大家记住,在这里 Ri 只能用工作寄存

器 R0 或者 R1

5 十六位数的传递指令

MOV DPTR #data16

指令说明 这是 51 单片机中唯一的一条 16 位立即数传递指令 大家知道 51 系列单片机是一种 8 位单片机 8 位单片机所能表示的最大数只能是 28=0-255 讲到这里大家应该明白了 为什么我们前面 的实验中立即数不能大于 255 如果现在有个数是 1234H 我们要把它送入 DPTR 该怎么办呢 当然有

办法 INTEL 公司已经把 DPTR 分成了两个寄存器 DPH 和 DPL看一下前面的特殊功能寄存器介绍

我们只要把 12H(高 8 位)送入 DPH 把 34H(低 8 位)送入 DPL 中去就可以了 所以执行指令 MOV DPTR

#1234H 和执行指令 MOV DPH #12H1 MOV DPL #34H2是一样的

二 指令练习

请写出下列每条指令的执行结果 并用 DBG8051 软件进行验证 看结果是否正确

1.MOV 12H,#34H

2.MOV R0,#23H

3.MOV R7,#22H

4.MOV R1,12H

5.MOV A,@R0

6.MOV 34H,@R1

7.MOV 45H,34H

8.MOV 12H,DPH

9.MOV R0,DPL

三 本课总结

 

36

----------------

 

本课主要讲述了以累加器为目的操作数的指令 以寄存器为目的操作数的指令 以直接地址为目 的操作数的指令 以间接地址为目的操作数的指令和一个十六位数的数据传递类指令 这些指令有的我 们前面已经学到过 希望大家用 DBG8051 软件多练习 以加强对数据及指令的认识

四 第 11 课习题

1 Rn Ri direct data 分别代表什么 举例说明

2 地址 30H 和数据 30H 有什么区别

3 DPTR 是什么 #data16 代表什么

37

----------------

 

版权所有:单片机教程网 2007
Email:erd51@163.com qq:58565254