www.8951.com

进入论坛

淘宝网店

软件下载

返回主页

单片机教程

单片机软件

电路设计

电子基础

网站产品

购买方式

 进入论坛

软件下载

单片机指令(四)

 一.控制转移类指令
控制转移类指令共有17 条,分为无条件转移指令、条件转移指令和返回及调用指令三大类,下面我们分别加以学习:
1.无条件转移类指令
(1)无条件绝对转移指令:AJMP addr11
(2)无条件长转移指令:LJMP addr16
(3)无条件相对转移指令:SJMP rel
在讲解上面这三条指令之前先来认识一下三个符号:add11 、add16 、rel。其中add11 和add16 表示外部ROM 的16 位和11 位地址,前面我们已经讲过,单片机的外部ROM 可以扩展到64K,add16 就表示64K 程序存储器的任何地址,换句话说LJMP 指令可以跳转到程序的任何地方,而add11 则表示下一条指令的2K 页面,也就是说,SJMP 指令只能跳转到程序的2K 范围之内;rel 表示8 位的偏移量,其范围是下一条指令第一字节的前128 到后127 个字节(即-128-+127B) 。介绍完了三个符号,再看上面的三条转移类指令,如果要仔细分析的话,它们之间其实区别较大,但在初学时,我们可以不理会这么多,统统把它们理解成:(*JMP 标号),比如SJMP LOOP ,就是跳转到有LOOP 标号处。

 

    原则上,所有用SJMP 或AJMP 的地方都可以用LJMP 来替代。因此在初学时,需要跳转时可以全用LJMP 代替,除了一个场合,什么场合呢?先看一下AJMP,AJMP 是一条双字节指令,也就说这条指令本身占用存储器(ROM )的两个单元,而LJMP 则是一条三字节指令,即这条指令占用存储器(ROM )的三个单元,这就是区别。

下面再来看第4 条跳转指令:


(4)无条件间接转移指令:JMP @A+DPTR
这条指令的用途也是跳转,跳转到什么地方去呢?这可不能由标号简单地决定了,让我们从一个实际的例子入手吧:
MOV DPTR,#TAB ;将TAB 所代表的地址送入DPTR
MOV A,R0 ;从R0 中取数(详见下面说明)
MOV B,#2 ;
MUL A,B ;A 中的值乘2 ;(详见下面的说明)
JMP A,@A+DPTR ;跳转
TAB: AJMP S1 ;跳转表格
AJMP S2 ;
AJMP S3 ;

应用背景介绍:在单片机开发中,经常要用到键盘,我们的要求是:当按下功能键A⋯⋯G 时去完成不同的功能,这用程序设计语言来表达的话,就是:按下不同的键去执行不同的程序段,以完成不同的功能,怎么样来实现这个功能呢?

看图,前面的程序读入的是按键的值,如按下‘A'键后获得的键值是“0”,按下‘B'键后获得的值是“1”等等,然后根据不同的值进行跳转,如键值为“0”就转到S1 处执行,如键值为“1”就转到S2 处执行,⋯⋯到底如何来实现这一功能呢?


先从程序的下面看起,是若干条AJMP 语句,这若干条AJMP 语句最后在存储器中是这样存放的(见图),也就是每个AJMP 语句都占用了两个存储器的空间,并且是连续存放的。而AJMP S1 存放的地址是TAB,到底TAB 等于多少,我们不需要知道,把它留给汇编程序来算好了。
下面我们来看这段程序的执行过程:第1 条MOV DPTR,#TAB 执行完了之后,DPTR 中的值就是TAB ,第2 条是MOV A,R0,我们假设R0 是由按键处理程序获得的键值,比如按下‘A’键,R0 中的值是“0”,按下‘B’键,R0 中的值是“1”⋯⋯以此类推;现在我们假设按下的是‘B’键,则执行完第2 条指令后,A 中的值就是“1”。并且按照我们的分析,按下‘B’后应当执行S2 这段程序,让我们来看一看是否是这样呢?第3 条、第4 条指令是将A 中的值乘“2”,即执行完第4 条指令后A 中的值是“2”,下面就执行JMP @A+DPTR 了,现在DPTR 中的值是“TAB”

     而A+DPTR 后就是“TAB+2”,因此,执行完这条程序后,将会跳到TAB+2 这个地址处继续执行;看一看在TAB+2 这个地址里面放的是什么?就是AJMP S2 这条指令,因此,马上又执行AJMP S2 这条指令,程序将跳到S2 处往下执行,这与我们的要求相符合。

请大家自行分析按下键‘A’、‘C’、‘D’⋯⋯之后的情况。

这样我们用JMP @A+DPTR 这条指令就实现了按下一个键跳转到相应程序段去执行的这样一个要求。再提一个问题,为什么取得键值后要乘“2”呢?如果例程下面的所有指令换成LJMP ,即:LJMP S1,LJMP S2⋯⋯这段程序还能正确地执行吗?如果不能,应该怎么改?

 

2.条件转移类指令
条件转移类指令就是在满足一定的条件后进行相对转移。
1 转移指令:JZ rel
2 转移指令:JNZ rel

第1条指令的功能是:如果(A)=0 ,则转移,否则顺序执行(执行本指令的下一条指令),转移到什么地方去呢?如果按照传统的方法,就要算偏移量,很麻烦,好在现在我们可以借助于机器汇编了。因此这条指令我们可以这样理解:JZ 标号,即转移到标号处。下面举一个例子来加以说明:

L1: MOV R1,#0FFH;

L2: SJMP L2 ;END
在执行上面这段程序前如果R0 中的值是“0”的话,就转移到L1 标号处执行,因此最终的执行结果是R1 中的值为0FFH ;而如果R0 中的值不等于“0”,则顺序执行,也就是执行 MOV R1,#00H 指令,最终的执行结果是R1 中的值等于“0”。把这个例子中的JZ 改成JNZ 试试吧,看看程序执行的结果是什么?


(3)比较转移指令

A.CJNE A,#data,rel

B.CJNE A,direct,rel

C.CJNE Rn,#data,rel

D.CJNE @Ri,#data,rel
指令说明:第1 条指令的功能是将A 中的值和立即数data 比较,如果两者相等,就顺序执行;如果不相等,就转移。同样地,我们可以将rel 理解成标号,即:CJNE A,#data, 标号。这样利用这条指令,我们就可以判断两数是否相等,这在很多场合是非常有用的,但有时还想知道两数比较之后哪个大,哪个小,本条指令也具有这样的功能,如果两数不相等,则CPU 还会反映出哪个数大,哪个数小,这是用CY(进位位)来实现的,如果前面的数(A 中的)大,则CY=0 ;否则CY=1 ,因此在程序转移后再次利用CY 就可判断出A 中的数比data 大还是小了。
例如:

MOV A,R0 ;

CJNE A,#10H,L1 ;

MOV R1,#0FFH ;

AJMP L3 ;
L1: JC L2 ;

MOV R1,#0AAH ;

AJMP L3 ;
L2: MOV R1,#0FFH ;

L3: SJMP L3 ;
上面的程序中有一条指令我们还没学过,即JC,这条指令的原型是JC rel, 作用和上面的JZ 类似,但是它是判CY 是“0”还是“1”进行转移,如果CY=1 ,则转移到JC 后面的标号处执行;如果CY=0 则顺序执行。
分析一下上面的程序,如果(A)=10H ,则顺序执行,即R1=0 ;如果(A)不等于10H ,则转到L1 处继续执行,在L1 处,再次进行判断,如果(A)>10H ,则CY=1 ,将顺序执行,(即执行MOV R1,#0AAH 指令);而如果(A)<10H ,则将转移到L2 处指行,(即执行MOV R1,#0FFH 指令)。

因此最终结果是:本程序执行前,如果(R0)=10H ,则(R1)=00H ;如果(R0)>10H ,则(R1)=0AAH ;如果(R0)<10H,则(R1)=0FFH。


弄懂了这条指令,其它的几条就类似了,第2 条是把A 当中的值和直接地址中的值比较,第3 条则是将直接地址中的值和立即数比较,第4 条是将间址寻址得到的数和立即数比较,这里就不解释了,请大家自行分析一下。下面给出几个相应的例子:
CJNE A,10H;把A 中的值和10H 中的值比较(注意和上题的区别)

CJNE 10H,#35H;把10H 中的值和35H 中的值比较

CJNE @R0,#35H;把R0 中的值作为地址,从此地址中取数并和35H 比较


循环转移指令

A.DJNZ Rn,rel

B.DJNZ direct,rel
第1条指令在前面的实验中已经有详细的分析,这里就不解释了;第2条指令,只是将Rn 改成直接地址,其它的也一样。
3.调用及返回指令
在前面的实验中,我们已用过了子程序,只是我们并没有明确地介绍。子程序是干什么用的,为什么要用子程序呢?举个例子,我们数学老师布置了10 道算术题,经过观察,每一道题中都包含一个(5+2)*3 的运算。我们可以有两种选择,第一种选择,每做一道题,都把这个算式算一遍;

第二种选择,我们可以先把这个结果算出来(也就是21),放在一边,然后要用到这个算式时就将21 代进去,这两种方法哪种更好呢?那就不必多言了吧。设计程序时也是这样,有时候一个功能会在程序的不同地方反复使用,我们就可以把这个功能设计成一段程序,每次需要用到这个功能时就“调用”一下,这就是子程序的用途所在,后面我们还会更详细地讲解子程序的用法。
主程序调用了子程序,子程序执行完之后必须再返回到主程序继续执行,不能“一去不回头”, 那么回到什么地方呢?就是回到调用子程序的下面一条指令处继续执行(当然啦,要是还回到这条指令,不又要再调用子程序了吗?那可就没完没了了⋯⋯)。大家可以回去看一下前面的实验,是不是这样做的?


1 调用指令
2 长调用指令:LCALL addr16
3 短调用指令:ACALL addr11
上面两条指令都是在主程序中调用子程序,两者的区别大家结合前面的知识可以自己分析一下。同样作为初学者,我们可以不必加以区分,也就是说可以用LCALL 指令代替ACALL。


1 返回指令
2 子程序返回:RET
3 中断返回:RETI
RET 用于子程序返回,RETI 用于中断程序返回,这是有区别的,可不能用错了,至于什么是中断返回,我们讲到中断时再来解释。如何从子程序返回呢?很简单,就是执行RET 指令,看一下前面的实验。


空操作指令:NOP
所谓空操作,就是什么事也不干,停一个机器周期,一般用作短时间的延时,这个我们已经讲过了。

 

单片机经典教程

 第一课 单片机的概述和分类

 第二课 单片机引脚功能介绍

 第三课 单片机内部结构(一)

 第四课 单片机内部结构(二)

 第五课 单片机内部结构(三)

 第六课 单片机内部结构(四)

 第七课 单片机内部结构(五)

 第八课 单片机内部结构(六)

 第九课  单片机是如何工作的?

 第十课 寻址是如何实现的

 第十一课 单片机的指令(一)

 第十二课 单片机的指令(二)

 第十三课 单片机的指令(三)

 第十四课 单片机的指令(四)

 第十五课 单片机的指令(五)

 第十六课 单片机程序的设计

 第十七课 单片机定时/计数器

 第十八课 单片机的中断系统

 第十九课 定时与中断实验一

 第二十课 定时与中断实验二

 第二十一课 键盘接口与编程一

 第二十二课 键盘接口与编程二

 第二十三课 数码管接口与编程1

 第二十四课 数码管接口与编程2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

XL2000单片机开发板&实验仪

XL600+51mini仿真器

xl400+51mini开发板

XL400单片机学习开发板

XL600编程实验单片机开发板

 

EP3.0支持stc双串口编程器

Ep51 单片机编程器

Top853 usb通用编程器

Top2007多功能编程器

GENIUS UPL800通用编程  

编辑:学林单片机@ 修订1.3 2010-01-25  学林电子,中国单片机学习板和开发板第一品牌   本文8951.com版权所有,未经书面批准转载必究。

当前共1030篇单片机基础入门文章,更多精彩内容请进入学林单片机论坛   联系我们 法律声明  粤ICP备05015330号