接着上一课的数据传递类指令 这一课继续讲解其他的数据类指令 提示 下面的内容我们下册
中才会用到 这里只是为了把数据传递类指令讲完 才提前把它们讲一下 您不知道也没关系
一 数据传递类指令
6 累加器 A 与片外 RAM 之间的数据传递类指令
什么是片外 RAM
即片外数据存储器
呢 单片机不是有内部 RAM 吗 为什么还要片外 RAM 呢
难道单片机的内部 RAM 还不够用吗 的确如此 当单片机的内部 RAM 不够时 我们就要扩充 RAM 空间
那么单片机能扩充多少的外部 RAM 空间呢 89C51 单片机的片外 RAM 可以扩展到 64K 即从 0000H-FFFFH
那么它是怎样和累加器 A 进行数据传递的 随便说一下 与外部 RAM 进行数据传递必须通过累加器 A
它们之间的传递指令共有以下四条
1
MOVX A @Ri
2
MOVX @Ri A
3
MOVX A @DPTR
4
MOVX @DPTR A
指令说明
A 在 51 系列单片机中 所有要送入或读出外部 RAM 的数据必须先送到 A 中去 由此我们可以看 出内外部 RAM 的区别 内部 RAM 间可以直接进行数据的传递 而外部 RAM 则不行 比如 要将外部 RAM
中某一单元
假设为 100H 单元的数据
送入另一个单元
假设为 200H 单元
就必须先将 100H 单元中 的内容读入 A 中 然后再送到 200H 单元中去 在这里有一个问题 CPU 是如何区分内 外部 RAM 的
大家看这里的四条指令 其操作码都是 MOVX 而内部 RAM 的操作码则是 MOV CPU 就是根据不同的指令 来自动区分读写内 外部 RAM 的
B 要读出或写入外部的 RAM 当然还必须知道外部 RAM 的地址 在后两条指令中 地址是被直接
放在 DPTR 中的 而前两条指令由于 Ri
即 R0 或 R1
只是一个 8 位的工作寄存器 所以只能提供低 8
位的地址 所以不同的应用场合就要使用不同的读写指令
C 使用时应当首先将要读出或写入的地址送入 DPTR 或 Ri 中 然后再用读写指令
举例说明 将外部 RAM 中 100H 单元中的内容送入外部 RAM 中 200H 单元中
MOV DPTR #100H MOVX A @DPTR MOV DPTR,#200H MOVX @DPTR,A
7 累加器 A 与片外 ROM 之间的数据传递类指令
MOVC A A+@DPTR
前一小节讲了累加器 A 与外部 RAM 之间的数据传递类指令 接下来再来讲讲片外 ROM 与累加器 A
之间的数据传递类指令 在讲解之前 先来了解一下内部 ROM 和外部 ROM 的组成 89C51 的内部有 4K
的 FLASH ROM 空间 其地址为 000H-FFFH 片外可以扩展到 64K
OOOOH-FFFFH
在这 64K 的 ROM 空间
中 有 4K 字节的地址是片内和片外公用的
即 000H-FFFH
而 1000H-FFFFH 的空间是片外 ROM 专用的
讲到这里大家就会问 既然有 4K 的地址是公用的 那么 CPU 是如何区分的呢 不知大家是否还记得
在第二讲单片机的硬件电路中 有一个引脚 EA
即 31 脚
当 EA=1 CPU 从片内 ROM 的 4K 字节中取指
令 如果地址超过了 4K
FFFH
单片机就自动转向片外 ROM 取指令 大家注意 这个过程是自动完 成的 不需要人工干预 而当 EA=0 时 CPU 只从片外 ROM 取指令 所以在实际的应用中 如果只使用
内部 ROM 一般总是把 EA 脚接电源 我们的实验板就是这么做的
讲到这里 细心的朋友还会有一个问题当使用外部 ROM 和外部 RAM 时 它们的寻址范围都是
0000H-FFFFH 也就是说它们在地址上是重叠的 那么 CPU 在读取指令时又是如何来区分当前是从 ROM
取指令还是从 RAM 取指令呢 请大家来看第二课的 89C51 单片机硬件电路图 29 脚是 PSEN 当我们置
位 PSEN 时
即 PSEN=1
CPU 就读取外部 ROM 指令 而要从外部 RAM 读取指令时就要置位 WR
即 16 脚
或 RD
即 17 脚
这样即使 ROM 地址和 RAM 地址是重叠的 也不会出现混乱 这里又有一个问题了
16 脚和 17 脚不是并行口 P3.6 和 P3.7 吗 如果我们把它当作第二功能 WR 和 RD 来使用 CPU 又是如何 来区分的呢 这个问题我们前面已经讲过了 这里再重复一遍 单片机引脚的第二功能是不需要人工干 预的 也就是说只要 CPU 执行到相应的指令 就自动转成了第二功能
了解了片外 ROM 的读取指令原理 再来看片外 ROM 与累加器 A 之间的数据传递指令
注意 ROM
只能读取指令 而不能写入数据 这一点和 RAM 是不同的 不需要解释了吧
MOVC A A+@DPTR
指令说明
A 本条指令是将 ROM 中的数送入 A 中 通常称其为查表指令 我们常用此指令来查一个已做好在
ROM 中的表格
B 此条指令引出一个新的寻址方法 变址寻址 本指令是要在 ROM 的一个地址单元中找出数据
显然必须知道这个单元的地址 这个单元的地址是这样确定的 在执行本指令前 DPTR 中有一 个数 A 中也有一个数 执行指令时 将 A 和 DPTR 中的数加起来 就成为要查找的数的单元地
址 把查找到的结果放在 A 中 因此 本条指令执行前后 A 中的值不一定相同
举个例子 有一个数在 R0 中 要求用查表的方法确定它的平方值
此数取值范围是 0-5
MOV DPTR #TAB MOV A R0
MOVC A @A+DPTR
.
.
TAB: DB 0,1,4,9,16,25
假设 R0 中的值为 2
送入 A 中 而 DPTR 中的值则为 TAB
则最终确定的 ROM 单元的地址就
是 TAB+2
也就是到 TAB+2 这个单元中去取数 取到的是 4 (DB 后面的第三个数) 其它数据 也可以次类推 从这里可以看出 我们使用了标号
象 TAB 等
来代替具体的 ROM 单元地址 事实
上 标号的真实含义就是地址的数值 在这里它就代表了 TAB+0 TAB+1 TAB+25 这几个数据在
ROM 中的存放位置 而我们以前学过的如 LCALL DELAY 指令 DELAY 代表的是以 DELAY 为标号 的那段程序在 ROM 中存放的起始地址 CPU 就是根据这个起始地址才找到指令的 无法理解是吗 没 关系 让我们先来看几个符号的含义就会明白了
二 单片机的伪指令
我们前面简单提到过 END 是伪指令 那么到底什么是伪指令 它在单片机中有什么作用呢 接 下来我们就来讨论这个问题 伪指令是单片机中用来给寄存器定义或者赋值的特殊指令 为什么要用伪 指令呢 让我们先来看下面的实验
1 DB—定义字节伪指令
它的功能是从程序存储器 ROM 单元的某个地址开始 存入一组规定好的 8 位二进制常数
例如 ORG 2000H
TAB DB 45 48H 10 34H
解释一下 ORG—程序开始地址伪指令 什么意思呢 就是说本条指令的下一条从该地址开始存 放数据 比如上面的指令经汇编后 将从地址 2000H 开始给若干个 ROM 单元赋值 即
2000H
=45
2001H
=48H 2002H
=0AH 2003H
=34H 讲到这里 有的人会问 在这些指令中 我直接
用 MOV 2000H 45H MOV 2001H 48H 不就得了 干吗要用 DB 指令呢 是的 从理论上讲
两者的效果是一样的 只是因为我们现在的程序都很短 单片机不可能只做这些简单的工作 当程序比 较长时 这些指令的意义就不一样了
除了刚刚提到的 ORG 和 DB 伪指令外 单片机中还有那些伪指令呢 下面简单讲解一下
2 DW—定义字伪指令
在单片机中 一个字由两个字节组成 也就是说 如果一个字节可以表示一个 8 位数的话 那么 一个字就可以表示一个十六位的数
关于这方面的问题我们留到下册中再来讨论 这里就不讲了 以免
增加大家的学习难度
如此一来 这条伪指令的功能也就清楚了 就是从指定的 ROM 单元开始 定 义若干个 16 位常数 上一课我们已经讲过 51 系列单片机要存放一个 16 位的常数就必须把这个数分
成两个 8 位数据来存放 通常我们把一个 16 位数的高 8 位放入低地址 而把低 8 位放入高地址
注意
这两个地址必须是紧挨着的
例如 ORG 3000H
ABC DW 2345H 0A859H
程序经汇编后 3000H
=23H 3001H
=45H 3002H
=A8 3003H
=59H
3 DS—保留空间伪指令
它的功能是从指定的地址开始 保留若干个字节的 ROM 空间留作它用
例如 ORG 2000H
ABC DS0 8H
LOOP MOV A 30H
汇编以后 从 2000H 开始 将保留 8 个 ROM 单元留作它用 那么以 LOOP 为标号的指令就存放
在 2008H 单元中 这里有一点请大家注意 这几条伪指令都只能对程序存储器
ROM
起作用 而 不能用它们来对数据存储器
RAM
进行赋值或做其他的工作 至于它们到底有什么作用 我们什么
时候才需要用到它们 我们将在下册的实验中再作讲解 现在让我们通过一段程序来重点解释一下查表
程序的使用方法 这可是一定要学会的哦
例如 MOV DPTR #100H
MOV A R0
MOVC A @A+DPTR
.
.
ORG 0100H
DB 0,1,4,9,16,25
如果 R0 中的值为 2
则最终地址为 100H+2 即 102H
到 102H 单元中找到的是 4
这个 可以看懂了吧 那么 103H 中的数是多少呢 104H 呢 大家思考一下
8 堆栈的操作指令
什么是堆栈 我们前面已经介绍过了 那么堆栈是如何进行数据传递的呢 对堆栈的操作指 令有 2 条
1
PUSH direct
2
POP direct
第 1 条指令称之为推入 就是将 direct 中的内容送入到堆栈中 第 2 条指令称之为弹出 就是将 堆栈中的内容送回到 direct 中 这不难理解 我重点解释一下推入和弹出的执行过程 首先将 SP 中的 值加 1 然后把 SP 中的值当作地址 将 direct 中的值送进以 SP 中的值为地址的 RAM 单元中
例如 MOV SP #5FH
|
MOV |
A |
#100 |
|
MOV |
B |
#20 |
PUSH ACC
PUSH B
这段指令的执行过程是这样的 将 SP 中的值加 1 即变为 60H 然后将 A 中的值
#100
送到 60H
单元中 因此执行完 PUSH ACC 这条指令后 内存 60H 单元的值就是 100 同样 执行 PUSH B 时 是
将 SP+1 即变为 61H 然后将 B 中的值送入到 61H 单元中 即执行完本条指令后 61H 单元中的值变为
20 这是推入 那么弹出又是怎么样的呢 继续看下面的例子
MOV SP #5FH
|
MOV |
A |
#100 |
|
MOV |
B |
#20 |
PUSH ACC
PUSH B
POP B
POP ACC
POP 指令的执行是这样的 首先将 SP 中的值作为地址 并将此地址中的数送到 POP 指令后面的那
个 direct 中 然后 SP 减 1 上面程序的执行过程是 将 SP 中的值
现在是 61H
作为地址 取 61H 单 元中的数值
现在是 20
送到 B 中 所以执行完 POP B 指令后 B 中的值是 20 然后将 SP 减 1 那么
此时 SP 的值就变为 60H 然后执行 POP ACC 将 SP 中的值
60H
作为地址 从该地址中取数
现在
是 100
并送到 ACC 中 所以执行完本条指令后 ACC 中的值是 100
这有什么意义呢 ACC 中的值本来就是 100 B 中的值本来就是 20 啊 是的 在本例中 的确没 有意义 但在实际工作中 推入堆栈结束后
即执行指令 PUSH B 后
往往要执行其他的指令 而且这
些指令会把 A 中的值和 B 中的值改掉 所以在程序执行结束后 如果我们要把 A 和 B 中的值恢复到原来
的值 那么这些指令就有意义了 具体应用我们将在以后的课程中讲到 这里还有一个问题 如果不用 堆栈 比如说在 PUSH ACC 指令处用 MOV 60H A 在 PUSH B 处用指令 MOV 61H B 然后用 MOV A
60H MOV B 61H 来替代两条 POP 指令 不也一样吗 是的 从结果上看是一样的 但是从过程看是 不一样的 PUSH 和 POP 指令都是单字节 单周期指令 而 MOV 指令则是双字节 双周期指令 更何况
堆栈的作用不止于此 所以一般的单片机上都设有堆栈 而我们在编写子程序 需要保存数据时 通常 也采用堆栈的方法来实现
9 其他的数据传递类指令
|
1 |
XCH |
A |
Rn |
|
2 |
XCH |
A |
direct |
|
3 |
XCH |
A |
@Ri |
4
XCHD A,@Ri
5
MOVC A A+PC
前面的 4 条指令是进行数据交换用的 第 1 条 寄存器与累加器交换 第 2 条直接地址与累加器 交换 第 3 条间接 RAM 与累加器交换 第 4 条间接 RAM 与累加器的低 4 位交换 第 5 条是累加器与代码 字节之间的数据传递类指令 这些指令作为初学者可能暂时还用不上 所以就不介绍了 大家只要了解 一下就可以了 等下册中我们再来详细的讨论
三 本课总结
到本课为止 数据传递类指令全部讲解完了 在单片机的指令中 数据传递类指令是使用最多的 指令 因此这部分的内容是必须掌握的 如何来使用这些指令 我们将在以后的课程中结合具体的实验 加以介绍 为了加深印象 大家可以用 DBG8051 软件对上述指令进行反复练习 用实验结果来加深课堂 知识
四 第 12 课习题
|
1 |
单片机是如何区分片外 RAM 和片外 ROM 的 |
又是如何区分片外 ROM 和片内 ROM 的 |
|
2 |
简述推入堆栈和弹出堆栈的操作过程 |
|
41
:http://www.51hei.com 单片机学习中心,为您免费发布大量的学习资源以及商业代码
第十三课 单片机的指令 三
算术 逻辑运算类指令也是单片机中极为重要的指令系统 在很多教科书中都把它们归为一类
实际上它们还是有区别的 为了让大家便于记忆 这里把它们分了开来 在 51 单片机中 算术运算类 指令有 24 条 逻辑运算类指令有 25 条 这一课我们先来讲解算术运算类指令 下面我们分别加以讲解
一 算术运算类指令
1 不带进位的加法指令
指令说明 这些指令的意思就是把后面的值与 A 中的值相加 结果送到 A 中去
执行结果 A=40H
2 带进位的加法指令
指令说明 这些指令的作用都是将 A 中的值和其后面的值相加 并且加上进位位 CY 中的值 为 什么要这样做呢 我们知道 51 单片机是一种 8 位单片机 所以只能做 8 位的数学运算 也就是说最大 运算的范围只能是 0-255 这在实际工作中肯定是不够的 因此就要进行扩展 怎么扩展 就是将 2 个
8 位的数学运算合起来 成为一个 16 位的运算 这样可以表达的数的范围就能达到 0-65535 如何合并
呢 其实很简单 让我们看一个十进制数的加法例子 66+78 这两个数相加 我们根本不会在意它的 过程 但事实上我们是这样做的 先做 6+8低位然后再做 6+7 这是高位 做了两次加法 只是我
们做的时候并没有刻意分成两次加法来做罢了 或者说我们并没有意识到我们做了两次加法 之所以要
分成两次来做 是因为这两个数超过了一位数所能表达的范围0-9在做低位时产生了进位 我们通 常的办法是在适当的位置点一下 然后在做高位加法时将这一点加进去 其实计算机中做 16 位加法时
同样如此 先做低 8 位的 如果两数相加产生了进位 也要 点一下 做个标记 这个标记就是进位位
CY 在 PSW 中 我们前面已经讲过 在进行高位加法时将这个 CY 加进去 例如做 2 个 16 进制数相加
1067H+10A0H 先做 67H+A0H=107H 而 107H 显然超过了 0FFH 因此最终保存在 A 中的是 7 而 1 则进到
了 PSW 中的 CY 位去了 换言之 CY 位就相当于是 100H 然后再做 10H+10H+CY 结果是 21H 所以最终 的结果是 2107H
3 带借位的减法指令
指令说明 没有不带借位的减法指令 如果需要做不带借位的减法指令在做第一次相减时
只要将 CY 清零即可
4 乘法指令
1MUL AB
42
:http://www.51hei.com 单片机学习中心,为您免费发布大量的学习资源以及商业代码
指令说明 此指令的功能是将 A 和 B 中的两个 8 位无符号数相乘 两数相乘结果一般比较大 因 此最终结果用 1 个 16 位数来表达 其中高 8 位放在 B 中 低 8 位放在 A 中 在乘积大于 FFFFFH 65535
时 PSW 的 0V 位置 1 溢出否则 OV 为 0而 CY 位总是为 0
例 A=4EH B=5DH
MUL AB
乘积是 1C56H 所以在 B 中放的是 1CH 而 A 中放的则是 56H
5 除法指令
1DIV ABA/B
指令说明 此指令的功能是将 A 中的 8 位无符号数除以 B 中的 8 位无符号数什么是无符号数
简单的说就是没有负数的数 也就是整数 比如 1 2 3 1.2,4.5 等等这样的数除法一般会出现小
数 但计算机中可没法直接表达小数 它用的是我们小学生用的商和余数的概念 如 13/5 其商是 2
余数是 3 除了以后 商放在 A 中 余数放在 B 中 CY 位和 OV 位都是 0如果在做除法前 B 中的值
是 00H 也就是除数为 0 那么 0V=1
6 加 1 指令
指令说明 从结果上看 INC A 和 ADD A #1 差不多 但 INC A 是单字节单周期指令 而 ADD A
#1 则是双字节双周期指令 而且 INC A 不会影响 PSW 位 如A=0FFH INC A 后A=00H 而 CY
依然保持不变 如果是 ADD A #1 则A=00H 而 CY 一定是 1因此加 1 指令并不适合做加法
事实上它主要是用来做计数 地址增加等用途 另外 加法类指令都是以 A 为核心的 其中一个数必须 放在 A 中 而运算结果也必须放在 A 中 而加 1 类指令的对象则广泛得多 可以是寄存器 内存地址
间址寻址的地址等等
7 减 1 指令
指令说明 既然加 1 指令可以用于计数 定时 地址等加 1 那么有加也必然有减 所以减 1 指 令的功能与加 1 指令类似 这里就不多说了
8 十进制加法调整指令
DA A 这是一条对十进制加法进行调整的指令 等下册用到时再介绍
另外需要了解的是 在算术运算类指令中 除了加 1 和减 1 指令外 其他的算术运算类指令都要 把结果放到累加器 A 中 这与数据传递类指令有所不同
二 逻辑运算类指令
什么是逻辑运算 相信大家不会陌生 在数字电路中我们学过 与门或门非门 等 在 单片机中也有类似的运算 那么它们是如何分类的呢 接下来我们就来一一讲解 先来看对累加器 A
的逻辑运算指令
1 对累加器 A 的逻辑运算指令
1CLR A
指令说明 累加器 A 清零 效果同 MOV A #00H 是一样的 只不过它是单周期指令 而 MOV A
#00H 是双周期指令
2CPL A
43
:http://www.51hei.com 单片机学习中心,为您免费发布大量的学习资源以及商业代码
指令说明 将累加器 A 逐位取反 相当于数字电路的 非 逻辑 例如 A=12H CPL A 12H
化为二进制是 00010010 逻辑取反后为 11101101 即 A=EDH
(3) RL A
指令说明 将累加器 A 的值逻辑左移 例如 A=12H RL A 化为二进制为 00010010 逐位左移 后为 0010100 即 24H 这里把第 7 位移到了第 0 第 0 位移到了第 1 位 第 1 位移到了第 2 位 其余 的依次类推
4RLC A
指令说明 加上进位位 CY 并逻辑左移 例如 CY=1 A=12H RLC A 加上进位位 CY 后 1 00010010
逻辑左移变为 0 00100101即 CY=0 A=25H
5RR A
指令说明 将累加器 A 中的值逻辑右移 同 RL A 类似
6RRC A
指令说明 加上进位位 CY 并逻辑右移 同 RLC A 类似
7SWAP A
指令说明 将 A 中的值的高 低 4 位进行交换 例如 A=39H SWAP A 之后 A 中的值就是
93H 怎么正好是这么前后交换呢 因为这是一个十六进制数 每 1 个十六进位数代表 4 个二进制数
注意 如果是这样的 A=39D 后面没加 H 执行 SWAP A 之后 可不是A=93 要将它化成二 进制数再算 39D 化为二进制是 10111 也就是 0001 0111 高 4 位是 0001 低 4 位是 0111 交换后是
01110001 也就是 71H 即 113D
2 两个寄存器之间的逻辑运算指令
上面的指令都是针对累加器 A 的逻辑运算指令 也就是说对一个寄存器的逻辑运算 那么如果两 个寄存器之间的逻辑运算又是怎么样的呢 接着往下看
A 与 Rn 中的值按位 与' 结果送入 A 中
A 与 direct 中的值按位 与' 结果送入 A 中
A 与间址寻址单元@Ri 中的值按位 与' 结果送入 A 中
A 与立即数 data 按位 与' 结果送入 A 中
direct 中值与 A 中的值按位 与' 结果送入 direct 中
direct 中的值与立即数 data 按位 与' 结果送入 direct 中
指令说明 什么是逻辑 与 数字电路中我们已经学过 就是 F=A*B 简记为 全 1 出 1 有 0
出 0 如果忘了 没关系 找本书再看一下 这里就不详细的阐述了
例如 71H 和 56H 相 与将两数写成二进制形式 71H 01110001 和56H 00100110 逐 位相 与 结果 就是 00100000 即 20H 从上面的例子可以看出 两个参与运算的值只要其中有一个位
上是 0则这位的结果就是 0两个同是 1结果才是 1是不是符合逻辑 与 的结果
知道了逻辑 与 指令的功能后 逻辑 或 和逻辑 异或 的功能就很简单了 逻辑 或 是
逐位相 或即有 1 出 1 全 0 出 0 例 71H 和 56H 相 或 结果就是 77H 而 异或 则是逐位 异
或即相同出 0 相异出 1 仍旧 71H 和 56H 相 异或结果是 57H 两个寄存器之间的逻辑 或
以及逻辑 异或 的指令如下
A 与 Rn 中的值按位 或' 结果送入 A 中
A 与 direct 中的值按位 或' 结果送入 A 中
A 与间址寻址单元@Ri 中的值按位 或' 结果送入 A 中
A 与立即数 data 按位 或' 结果送入 A 中
direct 中值与 A 中的值按位 或' 结果送入 direct 中
ORL direct,#data direct 中的值与立即数 data 按位 或' 结果送入 direct 中
A 与 Rn 中的值按位 异或' 结果送入 A 中
A 与 direct 中的值按位 异或' 结果送入 A 中
44
:http://www.51hei.com 单片机学习中心,为您免费发布大量的学习资源以及商业代码
XRL A,@Ri A 与间址寻址单元@Ri 中的值按位 异或' 结果送入 A 中
XRL A,#data A 与立即数 data 按位 异或' 结果送入 A 中
XRL direct,A direct 中值与 A 中的值按位 异或' 结果送入 direct 中
XRL direct,#data direct 中的值与立即数 data 按位 异或' 结果送 direct 中
连续好几节课将讲了许多的基本知识 大家是不是又觉得有些枯燥和无聊了 别急,接下来让 我们轻松一下 做一个实验来证明一下几节课所学的内容
三 LED 灯流动的实验 这是很经典的哦
1 实验程序
ORG
0000H
;
LJMP
START
;
ORG 30H ;
START:MOV SP,#5FH ; MOV A,#80H ; LOOP:MOV P1,A ; RL A ; LCALL DELAY ; LJMP LOOP ; DELAY:MOV R7,#255 ; D1:MOV R6,#255 ;
D2:NOP NOP NOP
NOP
DJNZ
R6,D2
;
DJNZ
R7,D1
;
RET
;
END
好久没做实验了 大家还记得实验的步骤吗 调试 编译 下载 看到了什么 有一个暗点在
流动 想象一下 如果我们把 P1.0-1.7 的 LED 换成 8 只可控硅来控制霓虹灯 是不是就有点实用价值
了
2 程序分析
前面的 ORG 0000H LJMP START ORG 30H 我们都讲过了 从 START 开始 MOV SP #5FH 这 叫初始化堆栈 在本程序中有无此句无关紧要 不过我们慢慢开始接触正规的编程 我也就慢慢地给大 家培养习惯吧 MOV A #80H 将 80H 这个数送到 A 中去 干什么呢 不知道 往下看 MOV P1 A
将 A 中的值送到 P1 端口去 此时 A 中的值是 80H 所以送出去的也就是 80H 因此 P1 口的值是 80H
也就是二进制 10000000 对应 P1.7-P1.0 这 8 位 我们应当知道 此时 P1.7 接的 LED8 是不亮的 而其 它的 LED 都是亮的 所以就形成了一个 暗点继续往下看 RL A 将 A 中的值进行左移 算一下
移之后的结果是什么 对了 是 01H 也就是二进制 00000001 这样 应当是接在 P1.0 上的 LED1 不亮
了 而其它的都亮了 从现象上看就是 暗点 移到了后面 然后是调用延时程序 这里有一条指令
NOP 它是空操作指令 也就是什么都不做 用于短暂的延时 其他的指令我们很熟悉了 就是让这个
暗点 暗一会儿 然后又跳转到 LOOP 处LJMP LOOP请大家计算一下 下面该哪个灯不亮了
对了 应当是接在 P1.1 上灯不亮了 这样依次不断的循环 就形成了 暗点流动 的现象
3 提几个要求继续实验
1如何实现亮点流动
2如何改变流动的方向
不错~谢谢分享~受益颇多啊~